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