1 //===----------------------------------------------------------------------===//
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
7 //===----------------------------------------------------------------------===//
9 #ifndef _LIBCPP___MUTEX_ONCE_FLAG_H
10 #define _LIBCPP___MUTEX_ONCE_FLAG_H
13 #include <__functional/invoke.h>
14 #include <__memory/shared_count.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>
20 #ifndef _LIBCPP_CXX03_LANG
24 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
25 # pragma GCC system_header
29 #include <__undef_macros>
31 _LIBCPP_BEGIN_NAMESPACE_STD
33 struct _LIBCPP_TEMPLATE_VIS once_flag
;
35 #ifndef _LIBCPP_CXX03_LANG
37 template <class _Callable
, class... _Args
>
38 _LIBCPP_HIDE_FROM_ABI
void call_once(once_flag
&, _Callable
&&, _Args
&&...);
40 #else // _LIBCPP_CXX03_LANG
42 template <class _Callable
>
43 _LIBCPP_HIDE_FROM_ABI
void call_once(once_flag
&, _Callable
&);
45 template <class _Callable
>
46 _LIBCPP_HIDE_FROM_ABI
void call_once(once_flag
&, const _Callable
&);
48 #endif // _LIBCPP_CXX03_LANG
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;
55 #if defined(_LIBCPP_ABI_MICROSOFT)
56 typedef uintptr_t _State_type
;
58 typedef unsigned long _State_type
;
61 static const _State_type _Unset
= 0;
62 static const _State_type _Pending
= 1;
63 static const _State_type _Complete
= ~_State_type(0);
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
&);
75 template <class _Callable
>
76 friend void call_once(once_flag
&, const _Callable
&);
77 #endif // _LIBCPP_CXX03_LANG
80 #ifndef _LIBCPP_CXX03_LANG
83 class __call_once_param
{
87 _LIBCPP_HIDE_FROM_ABI
explicit __call_once_param(_Fp
& __f
) : __f_(__f
) {}
89 _LIBCPP_HIDE_FROM_ABI
void operator()() {
90 typedef typename __make_tuple_indices
<tuple_size
<_Fp
>::value
, 1>::type _Index
;
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_
))...);
104 class __call_once_param
{
108 _LIBCPP_HIDE_FROM_ABI
explicit __call_once_param(_Fp
& __f
) : __f_(__f
) {}
110 _LIBCPP_HIDE_FROM_ABI
void operator()() { __f_(); }
116 void _LIBCPP_HIDE_FROM_ABI
__call_once_proxy(void* __vp
) {
117 __call_once_param
<_Fp
>* __p
= static_cast<__call_once_param
<_Fp
>*>(__vp
);
121 _LIBCPP_EXPORTED_FROM_ABI
void __call_once(volatile once_flag::_State_type
&, void*, void (*)(void*));
123 #ifndef _LIBCPP_CXX03_LANG
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
>);
135 #else // _LIBCPP_CXX03_LANG
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
>);
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
>);
153 #endif // _LIBCPP_CXX03_LANG
155 _LIBCPP_END_NAMESPACE_STD
159 #endif // _LIBCPP___MUTEX_ONCE_FLAG_H