master
  1//===----------------------------------------------------------------------===//
  2//
  3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
  4// See https://llvm.org/LICENSE.txt for license information.
  5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  6//
  7//===----------------------------------------------------------------------===//
  8
  9#ifndef _LIBCPP___MUTEX_ONCE_FLAG_H
 10#define _LIBCPP___MUTEX_ONCE_FLAG_H
 11
 12#include <__config>
 13#include <__functional/invoke.h>
 14#include <__memory/addressof.h>
 15#include <__memory/shared_count.h> // __libcpp_acquire_load
 16#include <__tuple/tuple_indices.h>
 17#include <__tuple/tuple_size.h>
 18#include <__utility/forward.h>
 19#include <__utility/move.h>
 20#include <cstdint>
 21#ifndef _LIBCPP_CXX03_LANG
 22#  include <tuple>
 23#endif
 24
 25#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
 26#  pragma GCC system_header
 27#endif
 28
 29_LIBCPP_PUSH_MACROS
 30#include <__undef_macros>
 31
 32_LIBCPP_BEGIN_NAMESPACE_STD
 33
 34struct once_flag;
 35
 36#ifndef _LIBCPP_CXX03_LANG
 37
 38template <class _Callable, class... _Args>
 39_LIBCPP_HIDE_FROM_ABI void call_once(once_flag&, _Callable&&, _Args&&...);
 40
 41#else // _LIBCPP_CXX03_LANG
 42
 43template <class _Callable>
 44_LIBCPP_HIDE_FROM_ABI void call_once(once_flag&, _Callable&);
 45
 46template <class _Callable>
 47_LIBCPP_HIDE_FROM_ABI void call_once(once_flag&, const _Callable&);
 48
 49#endif // _LIBCPP_CXX03_LANG
 50
 51struct once_flag {
 52  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR once_flag() _NOEXCEPT : __state_(_Unset) {}
 53  once_flag(const once_flag&)            = delete;
 54  once_flag& operator=(const once_flag&) = delete;
 55
 56#if defined(_LIBCPP_ABI_MICROSOFT)
 57  typedef uintptr_t _State_type;
 58#else
 59  typedef unsigned long _State_type;
 60#endif
 61
 62  static const _State_type _Unset    = 0;
 63  static const _State_type _Pending  = 1;
 64  static const _State_type _Complete = ~_State_type(0);
 65
 66private:
 67  _State_type __state_;
 68
 69#ifndef _LIBCPP_CXX03_LANG
 70  template <class _Callable, class... _Args>
 71  friend void call_once(once_flag&, _Callable&&, _Args&&...);
 72#else  // _LIBCPP_CXX03_LANG
 73  template <class _Callable>
 74  friend void call_once(once_flag&, _Callable&);
 75
 76  template <class _Callable>
 77  friend void call_once(once_flag&, const _Callable&);
 78#endif // _LIBCPP_CXX03_LANG
 79};
 80
 81#ifndef _LIBCPP_CXX03_LANG
 82
 83template <class _Fp>
 84class __call_once_param {
 85  _Fp& __f_;
 86
 87public:
 88  _LIBCPP_HIDE_FROM_ABI explicit __call_once_param(_Fp& __f) : __f_(__f) {}
 89
 90  _LIBCPP_HIDE_FROM_ABI void operator()() {
 91    typedef typename __make_tuple_indices<tuple_size<_Fp>::value, 1>::type _Index;
 92    __execute(_Index());
 93  }
 94
 95private:
 96  template <size_t... _Indices>
 97  _LIBCPP_HIDE_FROM_ABI void __execute(__tuple_indices<_Indices...>) {
 98    std::__invoke(std::get<0>(std::move(__f_)), std::get<_Indices>(std::move(__f_))...);
 99  }
100};
101
102#else
103
104template <class _Fp>
105class __call_once_param {
106  _Fp& __f_;
107
108public:
109  _LIBCPP_HIDE_FROM_ABI explicit __call_once_param(_Fp& __f) : __f_(__f) {}
110
111  _LIBCPP_HIDE_FROM_ABI void operator()() { __f_(); }
112};
113
114#endif
115
116template <class _Fp>
117void _LIBCPP_HIDE_FROM_ABI __call_once_proxy(void* __vp) {
118  __call_once_param<_Fp>* __p = static_cast<__call_once_param<_Fp>*>(__vp);
119  (*__p)();
120}
121
122_LIBCPP_EXPORTED_FROM_ABI void __call_once(volatile once_flag::_State_type&, void*, void (*)(void*));
123
124#ifndef _LIBCPP_CXX03_LANG
125
126template <class _Callable, class... _Args>
127inline _LIBCPP_HIDE_FROM_ABI void call_once(once_flag& __flag, _Callable&& __func, _Args&&... __args) {
128  if (__libcpp_acquire_load(&__flag.__state_) != once_flag::_Complete) {
129    typedef tuple<_Callable&&, _Args&&...> _Gp;
130    _Gp __f(std::forward<_Callable>(__func), std::forward<_Args>(__args)...);
131    __call_once_param<_Gp> __p(__f);
132    std::__call_once(__flag.__state_, std::addressof(__p), std::addressof(__call_once_proxy<_Gp>));
133  }
134}
135
136#else // _LIBCPP_CXX03_LANG
137
138template <class _Callable>
139inline _LIBCPP_HIDE_FROM_ABI void call_once(once_flag& __flag, _Callable& __func) {
140  if (__libcpp_acquire_load(&__flag.__state_) != once_flag::_Complete) {
141    __call_once_param<_Callable> __p(__func);
142    std::__call_once(__flag.__state_, std::addressof(__p), std::addressof(__call_once_proxy<_Callable>));
143  }
144}
145
146template <class _Callable>
147inline _LIBCPP_HIDE_FROM_ABI void call_once(once_flag& __flag, const _Callable& __func) {
148  if (__libcpp_acquire_load(&__flag.__state_) != once_flag::_Complete) {
149    __call_once_param<const _Callable> __p(__func);
150    std::__call_once(__flag.__state_, std::addressof(__p), std::addressof(__call_once_proxy<const _Callable>));
151  }
152}
153
154#endif // _LIBCPP_CXX03_LANG
155
156_LIBCPP_END_NAMESPACE_STD
157
158_LIBCPP_POP_MACROS
159
160#endif // _LIBCPP___MUTEX_ONCE_FLAG_H