aboutsummaryrefslogtreecommitdiff
path: root/contrib/llvm-project/libcxx/include/__mutex/once_flag.h
blob: 5a6f8e09055f752978957be7554fa766537fdea3 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

#ifndef _LIBCPP___MUTEX_ONCE_FLAG_H
#define _LIBCPP___MUTEX_ONCE_FLAG_H

#include <__config>
#include <__functional/invoke.h>
#include <__memory/shared_ptr.h> // __libcpp_acquire_load
#include <__tuple/tuple_indices.h>
#include <__tuple/tuple_size.h>
#include <__utility/forward.h>
#include <__utility/move.h>
#include <cstdint>
#ifndef _LIBCPP_CXX03_LANG
#  include <tuple>
#endif

#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
#  pragma GCC system_header
#endif

_LIBCPP_BEGIN_NAMESPACE_STD

struct _LIBCPP_TEMPLATE_VIS once_flag;

#ifndef _LIBCPP_CXX03_LANG

template <class _Callable, class... _Args>
_LIBCPP_HIDE_FROM_ABI void call_once(once_flag&, _Callable&&, _Args&&...);

#else // _LIBCPP_CXX03_LANG

template <class _Callable>
_LIBCPP_HIDE_FROM_ABI void call_once(once_flag&, _Callable&);

template <class _Callable>
_LIBCPP_HIDE_FROM_ABI void call_once(once_flag&, const _Callable&);

#endif // _LIBCPP_CXX03_LANG

struct _LIBCPP_TEMPLATE_VIS once_flag {
  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR once_flag() _NOEXCEPT : __state_(_Unset) {}
  once_flag(const once_flag&)            = delete;
  once_flag& operator=(const once_flag&) = delete;

#if defined(_LIBCPP_ABI_MICROSOFT)
  typedef uintptr_t _State_type;
#else
  typedef unsigned long _State_type;
#endif

  static const _State_type _Unset    = 0;
  static const _State_type _Pending  = 1;
  static const _State_type _Complete = ~_State_type(0);

private:
  _State_type __state_;

#ifndef _LIBCPP_CXX03_LANG
  template <class _Callable, class... _Args>
  friend void call_once(once_flag&, _Callable&&, _Args&&...);
#else  // _LIBCPP_CXX03_LANG
  template <class _Callable>
  friend void call_once(once_flag&, _Callable&);

  template <class _Callable>
  friend void call_once(once_flag&, const _Callable&);
#endif // _LIBCPP_CXX03_LANG
};

#ifndef _LIBCPP_CXX03_LANG

template <class _Fp>
class __call_once_param {
  _Fp& __f_;

public:
  _LIBCPP_HIDE_FROM_ABI explicit __call_once_param(_Fp& __f) : __f_(__f) {}

  _LIBCPP_HIDE_FROM_ABI void operator()() {
    typedef typename __make_tuple_indices<tuple_size<_Fp>::value, 1>::type _Index;
    __execute(_Index());
  }

private:
  template <size_t... _Indices>
  _LIBCPP_HIDE_FROM_ABI void __execute(__tuple_indices<_Indices...>) {
    std::__invoke(std::get<0>(std::move(__f_)), std::get<_Indices>(std::move(__f_))...);
  }
};

#else

template <class _Fp>
class __call_once_param {
  _Fp& __f_;

public:
  _LIBCPP_HIDE_FROM_ABI explicit __call_once_param(_Fp& __f) : __f_(__f) {}

  _LIBCPP_HIDE_FROM_ABI void operator()() { __f_(); }
};

#endif

template <class _Fp>
void _LIBCPP_HIDE_FROM_ABI __call_once_proxy(void* __vp) {
  __call_once_param<_Fp>* __p = static_cast<__call_once_param<_Fp>*>(__vp);
  (*__p)();
}

_LIBCPP_EXPORTED_FROM_ABI void __call_once(volatile once_flag::_State_type&, void*, void (*)(void*));

#ifndef _LIBCPP_CXX03_LANG

template <class _Callable, class... _Args>
inline _LIBCPP_HIDE_FROM_ABI void call_once(once_flag& __flag, _Callable&& __func, _Args&&... __args) {
  if (__libcpp_acquire_load(&__flag.__state_) != once_flag::_Complete) {
    typedef tuple<_Callable&&, _Args&&...> _Gp;
    _Gp __f(std::forward<_Callable>(__func), std::forward<_Args>(__args)...);
    __call_once_param<_Gp> __p(__f);
    std::__call_once(__flag.__state_, &__p, &__call_once_proxy<_Gp>);
  }
}

#else // _LIBCPP_CXX03_LANG

template <class _Callable>
inline _LIBCPP_HIDE_FROM_ABI void call_once(once_flag& __flag, _Callable& __func) {
  if (__libcpp_acquire_load(&__flag.__state_) != once_flag::_Complete) {
    __call_once_param<_Callable> __p(__func);
    std::__call_once(__flag.__state_, &__p, &__call_once_proxy<_Callable>);
  }
}

template <class _Callable>
inline _LIBCPP_HIDE_FROM_ABI void call_once(once_flag& __flag, const _Callable& __func) {
  if (__libcpp_acquire_load(&__flag.__state_) != once_flag::_Complete) {
    __call_once_param<const _Callable> __p(__func);
    std::__call_once(__flag.__state_, &__p, &__call_once_proxy<const _Callable>);
  }
}

#endif // _LIBCPP_CXX03_LANG

_LIBCPP_END_NAMESPACE_STD

#endif // _LIBCPP___MUTEX_ONCE_FLAG_H