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