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___ATOMIC_ATOMIC_H
10#define _LIBCPP___ATOMIC_ATOMIC_H
11
12#include <__atomic/atomic_sync.h>
13#include <__atomic/atomic_waitable_traits.h>
14#include <__atomic/check_memory_order.h>
15#include <__atomic/floating_point_helper.h>
16#include <__atomic/is_always_lock_free.h>
17#include <__atomic/memory_order.h>
18#include <__atomic/support.h>
19#include <__concepts/arithmetic.h>
20#include <__concepts/same_as.h>
21#include <__config>
22#include <__cstddef/ptrdiff_t.h>
23#include <__memory/addressof.h>
24#include <__type_traits/enable_if.h>
25#include <__type_traits/is_constructible.h>
26#include <__type_traits/is_floating_point.h>
27#include <__type_traits/is_function.h>
28#include <__type_traits/is_integral.h>
29#include <__type_traits/is_nothrow_constructible.h>
30#include <__type_traits/is_pointer.h>
31#include <__type_traits/is_same.h>
32#include <__type_traits/is_trivially_copyable.h>
33#include <__type_traits/remove_pointer.h>
34#include <__utility/forward.h>
35#include <cstring>
36
37#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
38# pragma GCC system_header
39#endif
40
41_LIBCPP_BEGIN_NAMESPACE_STD
42
43template <class _Tp, bool = is_integral<_Tp>::value && !is_same<_Tp, bool>::value>
44struct __atomic_base // false
45{
46 mutable __cxx_atomic_impl<_Tp> __a_;
47
48 using value_type = _Tp;
49
50#if _LIBCPP_STD_VER >= 17
51 static constexpr bool is_always_lock_free = __libcpp_is_always_lock_free<__cxx_atomic_impl<_Tp> >::__value;
52#endif
53
54 [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI bool is_lock_free() const volatile _NOEXCEPT {
55 return __cxx_atomic_is_lock_free(sizeof(__cxx_atomic_impl<_Tp>));
56 }
57 [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI bool is_lock_free() const _NOEXCEPT {
58 return static_cast<__atomic_base const volatile*>(this)->is_lock_free();
59 }
60 _LIBCPP_HIDE_FROM_ABI void store(_Tp __d, memory_order __m = memory_order_seq_cst) volatile _NOEXCEPT
61 _LIBCPP_CHECK_STORE_MEMORY_ORDER(__m) {
62 std::__cxx_atomic_store(std::addressof(__a_), __d, __m);
63 }
64 _LIBCPP_HIDE_FROM_ABI void store(_Tp __d, memory_order __m = memory_order_seq_cst) _NOEXCEPT
65 _LIBCPP_CHECK_STORE_MEMORY_ORDER(__m) {
66 std::__cxx_atomic_store(std::addressof(__a_), __d, __m);
67 }
68 [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _Tp load(memory_order __m = memory_order_seq_cst) const volatile _NOEXCEPT
69 _LIBCPP_CHECK_LOAD_MEMORY_ORDER(__m) {
70 return std::__cxx_atomic_load(std::addressof(__a_), __m);
71 }
72 [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _Tp load(memory_order __m = memory_order_seq_cst) const _NOEXCEPT
73 _LIBCPP_CHECK_LOAD_MEMORY_ORDER(__m) {
74 return std::__cxx_atomic_load(std::addressof(__a_), __m);
75 }
76 _LIBCPP_HIDE_FROM_ABI operator _Tp() const volatile _NOEXCEPT { return load(); }
77 _LIBCPP_HIDE_FROM_ABI operator _Tp() const _NOEXCEPT { return load(); }
78 _LIBCPP_HIDE_FROM_ABI _Tp exchange(_Tp __d, memory_order __m = memory_order_seq_cst) volatile _NOEXCEPT {
79 return std::__cxx_atomic_exchange(std::addressof(__a_), __d, __m);
80 }
81 _LIBCPP_HIDE_FROM_ABI _Tp exchange(_Tp __d, memory_order __m = memory_order_seq_cst) _NOEXCEPT {
82 return std::__cxx_atomic_exchange(std::addressof(__a_), __d, __m);
83 }
84 _LIBCPP_HIDE_FROM_ABI bool
85 compare_exchange_weak(_Tp& __e, _Tp __d, memory_order __s, memory_order __f) volatile _NOEXCEPT
86 _LIBCPP_CHECK_EXCHANGE_MEMORY_ORDER(__s, __f) {
87 return std::__cxx_atomic_compare_exchange_weak(std::addressof(__a_), std::addressof(__e), __d, __s, __f);
88 }
89 _LIBCPP_HIDE_FROM_ABI bool compare_exchange_weak(_Tp& __e, _Tp __d, memory_order __s, memory_order __f) _NOEXCEPT
90 _LIBCPP_CHECK_EXCHANGE_MEMORY_ORDER(__s, __f) {
91 return std::__cxx_atomic_compare_exchange_weak(std::addressof(__a_), std::addressof(__e), __d, __s, __f);
92 }
93 _LIBCPP_HIDE_FROM_ABI bool
94 compare_exchange_strong(_Tp& __e, _Tp __d, memory_order __s, memory_order __f) volatile _NOEXCEPT
95 _LIBCPP_CHECK_EXCHANGE_MEMORY_ORDER(__s, __f) {
96 return std::__cxx_atomic_compare_exchange_strong(std::addressof(__a_), std::addressof(__e), __d, __s, __f);
97 }
98 _LIBCPP_HIDE_FROM_ABI bool compare_exchange_strong(_Tp& __e, _Tp __d, memory_order __s, memory_order __f) _NOEXCEPT
99 _LIBCPP_CHECK_EXCHANGE_MEMORY_ORDER(__s, __f) {
100 return std::__cxx_atomic_compare_exchange_strong(std::addressof(__a_), std::addressof(__e), __d, __s, __f);
101 }
102 _LIBCPP_HIDE_FROM_ABI bool
103 compare_exchange_weak(_Tp& __e, _Tp __d, memory_order __m = memory_order_seq_cst) volatile _NOEXCEPT {
104 return std::__cxx_atomic_compare_exchange_weak(std::addressof(__a_), std::addressof(__e), __d, __m, __m);
105 }
106 _LIBCPP_HIDE_FROM_ABI bool
107 compare_exchange_weak(_Tp& __e, _Tp __d, memory_order __m = memory_order_seq_cst) _NOEXCEPT {
108 return std::__cxx_atomic_compare_exchange_weak(std::addressof(__a_), std::addressof(__e), __d, __m, __m);
109 }
110 _LIBCPP_HIDE_FROM_ABI bool
111 compare_exchange_strong(_Tp& __e, _Tp __d, memory_order __m = memory_order_seq_cst) volatile _NOEXCEPT {
112 return std::__cxx_atomic_compare_exchange_strong(std::addressof(__a_), std::addressof(__e), __d, __m, __m);
113 }
114 _LIBCPP_HIDE_FROM_ABI bool
115 compare_exchange_strong(_Tp& __e, _Tp __d, memory_order __m = memory_order_seq_cst) _NOEXCEPT {
116 return std::__cxx_atomic_compare_exchange_strong(std::addressof(__a_), std::addressof(__e), __d, __m, __m);
117 }
118
119#if _LIBCPP_STD_VER >= 20
120 _LIBCPP_HIDE_FROM_ABI void wait(_Tp __v, memory_order __m = memory_order_seq_cst) const volatile noexcept {
121 std::__atomic_wait(*this, __v, __m);
122 }
123 _LIBCPP_HIDE_FROM_ABI void wait(_Tp __v, memory_order __m = memory_order_seq_cst) const noexcept {
124 std::__atomic_wait(*this, __v, __m);
125 }
126 _LIBCPP_HIDE_FROM_ABI void notify_one() volatile noexcept { std::__atomic_notify_one(*this); }
127 _LIBCPP_HIDE_FROM_ABI void notify_one() noexcept { std::__atomic_notify_one(*this); }
128 _LIBCPP_HIDE_FROM_ABI void notify_all() volatile noexcept { std::__atomic_notify_all(*this); }
129 _LIBCPP_HIDE_FROM_ABI void notify_all() noexcept { std::__atomic_notify_all(*this); }
130#endif // _LIBCPP_STD_VER >= 20
131
132#if _LIBCPP_STD_VER >= 20
133 _LIBCPP_HIDE_FROM_ABI constexpr __atomic_base() noexcept(is_nothrow_default_constructible_v<_Tp>) : __a_(_Tp()) {}
134#else
135 _LIBCPP_HIDE_FROM_ABI __atomic_base() _NOEXCEPT = default;
136#endif
137
138 _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR __atomic_base(_Tp __d) _NOEXCEPT : __a_(__d) {}
139
140 __atomic_base(const __atomic_base&) = delete;
141};
142
143// atomic<Integral>
144
145template <class _Tp>
146struct __atomic_base<_Tp, true> : public __atomic_base<_Tp, false> {
147 using __base _LIBCPP_NODEBUG = __atomic_base<_Tp, false>;
148
149 using difference_type = typename __base::value_type;
150
151 _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 __atomic_base() _NOEXCEPT = default;
152
153 _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR __atomic_base(_Tp __d) _NOEXCEPT : __base(__d) {}
154
155 _LIBCPP_HIDE_FROM_ABI _Tp fetch_add(_Tp __op, memory_order __m = memory_order_seq_cst) volatile _NOEXCEPT {
156 return std::__cxx_atomic_fetch_add(std::addressof(this->__a_), __op, __m);
157 }
158 _LIBCPP_HIDE_FROM_ABI _Tp fetch_add(_Tp __op, memory_order __m = memory_order_seq_cst) _NOEXCEPT {
159 return std::__cxx_atomic_fetch_add(std::addressof(this->__a_), __op, __m);
160 }
161 _LIBCPP_HIDE_FROM_ABI _Tp fetch_sub(_Tp __op, memory_order __m = memory_order_seq_cst) volatile _NOEXCEPT {
162 return std::__cxx_atomic_fetch_sub(std::addressof(this->__a_), __op, __m);
163 }
164 _LIBCPP_HIDE_FROM_ABI _Tp fetch_sub(_Tp __op, memory_order __m = memory_order_seq_cst) _NOEXCEPT {
165 return std::__cxx_atomic_fetch_sub(std::addressof(this->__a_), __op, __m);
166 }
167 _LIBCPP_HIDE_FROM_ABI _Tp fetch_and(_Tp __op, memory_order __m = memory_order_seq_cst) volatile _NOEXCEPT {
168 return std::__cxx_atomic_fetch_and(std::addressof(this->__a_), __op, __m);
169 }
170 _LIBCPP_HIDE_FROM_ABI _Tp fetch_and(_Tp __op, memory_order __m = memory_order_seq_cst) _NOEXCEPT {
171 return std::__cxx_atomic_fetch_and(std::addressof(this->__a_), __op, __m);
172 }
173 _LIBCPP_HIDE_FROM_ABI _Tp fetch_or(_Tp __op, memory_order __m = memory_order_seq_cst) volatile _NOEXCEPT {
174 return std::__cxx_atomic_fetch_or(std::addressof(this->__a_), __op, __m);
175 }
176 _LIBCPP_HIDE_FROM_ABI _Tp fetch_or(_Tp __op, memory_order __m = memory_order_seq_cst) _NOEXCEPT {
177 return std::__cxx_atomic_fetch_or(std::addressof(this->__a_), __op, __m);
178 }
179 _LIBCPP_HIDE_FROM_ABI _Tp fetch_xor(_Tp __op, memory_order __m = memory_order_seq_cst) volatile _NOEXCEPT {
180 return std::__cxx_atomic_fetch_xor(std::addressof(this->__a_), __op, __m);
181 }
182 _LIBCPP_HIDE_FROM_ABI _Tp fetch_xor(_Tp __op, memory_order __m = memory_order_seq_cst) _NOEXCEPT {
183 return std::__cxx_atomic_fetch_xor(std::addressof(this->__a_), __op, __m);
184 }
185#if _LIBCPP_STD_VER >= 26
186 _LIBCPP_HIDE_FROM_ABI _Tp fetch_max(_Tp __op, memory_order __m = memory_order_seq_cst) volatile _NOEXCEPT {
187 return std::__cxx_atomic_fetch_max(std::addressof(this->__a_), __op, __m);
188 }
189 _LIBCPP_HIDE_FROM_ABI _Tp fetch_max(_Tp __op, memory_order __m = memory_order_seq_cst) _NOEXCEPT {
190 return std::__cxx_atomic_fetch_max(std::addressof(this->__a_), __op, __m);
191 }
192 _LIBCPP_HIDE_FROM_ABI _Tp fetch_min(_Tp __op, memory_order __m = memory_order_seq_cst) volatile _NOEXCEPT {
193 return std::__cxx_atomic_fetch_min(std::addressof(this->__a_), __op, __m);
194 }
195 _LIBCPP_HIDE_FROM_ABI _Tp fetch_min(_Tp __op, memory_order __m = memory_order_seq_cst) _NOEXCEPT {
196 return std::__cxx_atomic_fetch_min(std::addressof(this->__a_), __op, __m);
197 }
198#endif
199
200 _LIBCPP_HIDE_FROM_ABI _Tp operator++(int) volatile _NOEXCEPT { return fetch_add(_Tp(1)); }
201 _LIBCPP_HIDE_FROM_ABI _Tp operator++(int) _NOEXCEPT { return fetch_add(_Tp(1)); }
202 _LIBCPP_HIDE_FROM_ABI _Tp operator--(int) volatile _NOEXCEPT { return fetch_sub(_Tp(1)); }
203 _LIBCPP_HIDE_FROM_ABI _Tp operator--(int) _NOEXCEPT { return fetch_sub(_Tp(1)); }
204 _LIBCPP_HIDE_FROM_ABI _Tp operator++() volatile _NOEXCEPT { return fetch_add(_Tp(1)) + _Tp(1); }
205 _LIBCPP_HIDE_FROM_ABI _Tp operator++() _NOEXCEPT { return fetch_add(_Tp(1)) + _Tp(1); }
206 _LIBCPP_HIDE_FROM_ABI _Tp operator--() volatile _NOEXCEPT { return fetch_sub(_Tp(1)) - _Tp(1); }
207 _LIBCPP_HIDE_FROM_ABI _Tp operator--() _NOEXCEPT { return fetch_sub(_Tp(1)) - _Tp(1); }
208 _LIBCPP_HIDE_FROM_ABI _Tp operator+=(_Tp __op) volatile _NOEXCEPT { return fetch_add(__op) + __op; }
209 _LIBCPP_HIDE_FROM_ABI _Tp operator+=(_Tp __op) _NOEXCEPT { return fetch_add(__op) + __op; }
210 _LIBCPP_HIDE_FROM_ABI _Tp operator-=(_Tp __op) volatile _NOEXCEPT { return fetch_sub(__op) - __op; }
211 _LIBCPP_HIDE_FROM_ABI _Tp operator-=(_Tp __op) _NOEXCEPT { return fetch_sub(__op) - __op; }
212 _LIBCPP_HIDE_FROM_ABI _Tp operator&=(_Tp __op) volatile _NOEXCEPT { return fetch_and(__op) & __op; }
213 _LIBCPP_HIDE_FROM_ABI _Tp operator&=(_Tp __op) _NOEXCEPT { return fetch_and(__op) & __op; }
214 _LIBCPP_HIDE_FROM_ABI _Tp operator|=(_Tp __op) volatile _NOEXCEPT { return fetch_or(__op) | __op; }
215 _LIBCPP_HIDE_FROM_ABI _Tp operator|=(_Tp __op) _NOEXCEPT { return fetch_or(__op) | __op; }
216 _LIBCPP_HIDE_FROM_ABI _Tp operator^=(_Tp __op) volatile _NOEXCEPT { return fetch_xor(__op) ^ __op; }
217 _LIBCPP_HIDE_FROM_ABI _Tp operator^=(_Tp __op) _NOEXCEPT { return fetch_xor(__op) ^ __op; }
218};
219
220#if _LIBCPP_STD_VER >= 17
221// Here we need _IsIntegral because the default template argument is not enough
222// e.g __atomic_base<int> is __atomic_base<int, true>, which inherits from
223// __atomic_base<int, false> and the caller of the wait function is
224// __atomic_base<int, false>. So specializing __atomic_base<_Tp> does not work
225template <class _Tp, bool _IsIntegral>
226struct __atomic_waitable_traits<__atomic_base<_Tp, _IsIntegral> > {
227 using __value_type _LIBCPP_NODEBUG = _Tp;
228
229 static _LIBCPP_HIDE_FROM_ABI _Tp __atomic_load(const __atomic_base<_Tp, _IsIntegral>& __a, memory_order __order) {
230 return __a.load(__order);
231 }
232
233 static _LIBCPP_HIDE_FROM_ABI _Tp
234 __atomic_load(const volatile __atomic_base<_Tp, _IsIntegral>& __this, memory_order __order) {
235 return __this.load(__order);
236 }
237
238 static _LIBCPP_HIDE_FROM_ABI const __cxx_atomic_impl<_Tp>*
239 __atomic_contention_address(const __atomic_base<_Tp, _IsIntegral>& __a) {
240 return std::addressof(__a.__a_);
241 }
242
243 static _LIBCPP_HIDE_FROM_ABI const volatile __cxx_atomic_impl<_Tp>*
244 __atomic_contention_address(const volatile __atomic_base<_Tp, _IsIntegral>& __this) {
245 return std::addressof(__this.__a_);
246 }
247};
248
249#endif // _LIBCPP_STD_VER >= 17
250
251template <typename _Tp>
252struct __check_atomic_mandates {
253 using type _LIBCPP_NODEBUG = _Tp;
254 static_assert(is_trivially_copyable<_Tp>::value, "std::atomic<T> requires that 'T' be a trivially copyable type");
255};
256
257template <class _Tp>
258struct atomic : public __atomic_base<typename __check_atomic_mandates<_Tp>::type> {
259 using __base _LIBCPP_NODEBUG = __atomic_base<_Tp>;
260
261#if _LIBCPP_STD_VER >= 20
262 _LIBCPP_HIDE_FROM_ABI atomic()
263 requires is_default_constructible_v<_Tp>
264 = default;
265#else
266 _LIBCPP_HIDE_FROM_ABI atomic() _NOEXCEPT = default;
267#endif
268
269 _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR atomic(_Tp __d) _NOEXCEPT : __base(__d) {}
270
271 _LIBCPP_HIDE_FROM_ABI _Tp operator=(_Tp __d) volatile _NOEXCEPT {
272 __base::store(__d);
273 return __d;
274 }
275 _LIBCPP_HIDE_FROM_ABI _Tp operator=(_Tp __d) _NOEXCEPT {
276 __base::store(__d);
277 return __d;
278 }
279
280 atomic& operator=(const atomic&) = delete;
281 atomic& operator=(const atomic&) volatile = delete;
282};
283
284// atomic<T*>
285
286template <class _Tp>
287struct atomic<_Tp*> : public __atomic_base<_Tp*> {
288 using __base _LIBCPP_NODEBUG = __atomic_base<_Tp*>;
289
290 using difference_type = ptrdiff_t;
291
292 _LIBCPP_HIDE_FROM_ABI atomic() _NOEXCEPT = default;
293
294 _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR atomic(_Tp* __d) _NOEXCEPT : __base(__d) {}
295
296 _LIBCPP_HIDE_FROM_ABI _Tp* operator=(_Tp* __d) volatile _NOEXCEPT {
297 __base::store(__d);
298 return __d;
299 }
300 _LIBCPP_HIDE_FROM_ABI _Tp* operator=(_Tp* __d) _NOEXCEPT {
301 __base::store(__d);
302 return __d;
303 }
304
305 _LIBCPP_HIDE_FROM_ABI _Tp* fetch_add(ptrdiff_t __op, memory_order __m = memory_order_seq_cst) volatile _NOEXCEPT {
306 // __atomic_fetch_add accepts function pointers, guard against them.
307 static_assert(!is_function<__remove_pointer_t<_Tp> >::value, "Pointer to function isn't allowed");
308 return std::__cxx_atomic_fetch_add(std::addressof(this->__a_), __op, __m);
309 }
310
311 _LIBCPP_HIDE_FROM_ABI _Tp* fetch_add(ptrdiff_t __op, memory_order __m = memory_order_seq_cst) _NOEXCEPT {
312 // __atomic_fetch_add accepts function pointers, guard against them.
313 static_assert(!is_function<__remove_pointer_t<_Tp> >::value, "Pointer to function isn't allowed");
314 return std::__cxx_atomic_fetch_add(std::addressof(this->__a_), __op, __m);
315 }
316
317 _LIBCPP_HIDE_FROM_ABI _Tp* fetch_sub(ptrdiff_t __op, memory_order __m = memory_order_seq_cst) volatile _NOEXCEPT {
318 // __atomic_fetch_sub accepts function pointers, guard against them.
319 static_assert(!is_function<__remove_pointer_t<_Tp> >::value, "Pointer to function isn't allowed");
320 return std::__cxx_atomic_fetch_sub(std::addressof(this->__a_), __op, __m);
321 }
322
323 _LIBCPP_HIDE_FROM_ABI _Tp* fetch_sub(ptrdiff_t __op, memory_order __m = memory_order_seq_cst) _NOEXCEPT {
324 // __atomic_fetch_sub accepts function pointers, guard against them.
325 static_assert(!is_function<__remove_pointer_t<_Tp> >::value, "Pointer to function isn't allowed");
326 return std::__cxx_atomic_fetch_sub(std::addressof(this->__a_), __op, __m);
327 }
328
329#if _LIBCPP_STD_VER >= 26
330 _LIBCPP_HIDE_FROM_ABI _Tp* fetch_max(_Tp* __op, memory_order __m = memory_order_seq_cst) volatile noexcept {
331 static_assert(!is_function<__remove_pointer_t<_Tp> >::value, "Pointer to function isn't allowed");
332 return std::__cxx_atomic_fetch_max(std::addressof(this->__a_), __op, __m);
333 }
334
335 _LIBCPP_HIDE_FROM_ABI _Tp* fetch_max(_Tp* __op, memory_order __m = memory_order_seq_cst) noexcept {
336 static_assert(!is_function<__remove_pointer_t<_Tp> >::value, "Pointer to function isn't allowed");
337 return std::__cxx_atomic_fetch_max(std::addressof(this->__a_), __op, __m);
338 }
339
340 _LIBCPP_HIDE_FROM_ABI _Tp* fetch_min(_Tp* __op, memory_order __m = memory_order_seq_cst) volatile noexcept {
341 static_assert(!is_function<__remove_pointer_t<_Tp> >::value, "Pointer to function isn't allowed");
342 return std::__cxx_atomic_fetch_min(std::addressof(this->__a_), __op, __m);
343 }
344
345 _LIBCPP_HIDE_FROM_ABI _Tp* fetch_min(_Tp* __op, memory_order __m = memory_order_seq_cst) noexcept {
346 static_assert(!is_function<__remove_pointer_t<_Tp> >::value, "Pointer to function isn't allowed");
347 return std::__cxx_atomic_fetch_min(std::addressof(this->__a_), __op, __m);
348 }
349#endif
350
351 _LIBCPP_HIDE_FROM_ABI _Tp* operator++(int) volatile _NOEXCEPT { return fetch_add(1); }
352 _LIBCPP_HIDE_FROM_ABI _Tp* operator++(int) _NOEXCEPT { return fetch_add(1); }
353 _LIBCPP_HIDE_FROM_ABI _Tp* operator--(int) volatile _NOEXCEPT { return fetch_sub(1); }
354 _LIBCPP_HIDE_FROM_ABI _Tp* operator--(int) _NOEXCEPT { return fetch_sub(1); }
355 _LIBCPP_HIDE_FROM_ABI _Tp* operator++() volatile _NOEXCEPT { return fetch_add(1) + 1; }
356 _LIBCPP_HIDE_FROM_ABI _Tp* operator++() _NOEXCEPT { return fetch_add(1) + 1; }
357 _LIBCPP_HIDE_FROM_ABI _Tp* operator--() volatile _NOEXCEPT { return fetch_sub(1) - 1; }
358 _LIBCPP_HIDE_FROM_ABI _Tp* operator--() _NOEXCEPT { return fetch_sub(1) - 1; }
359 _LIBCPP_HIDE_FROM_ABI _Tp* operator+=(ptrdiff_t __op) volatile _NOEXCEPT { return fetch_add(__op) + __op; }
360 _LIBCPP_HIDE_FROM_ABI _Tp* operator+=(ptrdiff_t __op) _NOEXCEPT { return fetch_add(__op) + __op; }
361 _LIBCPP_HIDE_FROM_ABI _Tp* operator-=(ptrdiff_t __op) volatile _NOEXCEPT { return fetch_sub(__op) - __op; }
362 _LIBCPP_HIDE_FROM_ABI _Tp* operator-=(ptrdiff_t __op) _NOEXCEPT { return fetch_sub(__op) - __op; }
363
364 atomic& operator=(const atomic&) = delete;
365 atomic& operator=(const atomic&) volatile = delete;
366};
367
368#if _LIBCPP_STD_VER >= 17
369template <class _Tp>
370struct __atomic_waitable_traits<atomic<_Tp> > : __atomic_waitable_traits<__atomic_base<_Tp> > {};
371#endif // _LIBCPP_STD_VER >= 17
372
373#if _LIBCPP_STD_VER >= 20
374template <class _Tp>
375 requires is_floating_point_v<_Tp>
376struct atomic<_Tp> : __atomic_base<_Tp> {
377private:
378 template <class _This, class _Operation, class _BuiltinOp>
379 _LIBCPP_HIDE_FROM_ABI static _Tp
380 __rmw_op(_This&& __self, _Tp __operand, memory_order __m, _Operation __operation, _BuiltinOp __builtin_op) {
381 if constexpr (std::__has_rmw_builtin<_Tp>()) {
382 return __builtin_op(std::addressof(std::forward<_This>(__self).__a_), __operand, __m);
383 } else {
384 _Tp __old = __self.load(memory_order_relaxed);
385 _Tp __new = __operation(__old, __operand);
386 while (!__self.compare_exchange_weak(__old, __new, __m, memory_order_relaxed)) {
387# ifdef _LIBCPP_COMPILER_CLANG_BASED
388 if constexpr (std::__is_fp80_long_double<_Tp>()) {
389 // https://llvm.org/PR47978
390 // clang bug: __old is not updated on failure for atomic<long double>::compare_exchange_weak
391 // Note __old = __self.load(memory_order_relaxed) will not work
392 std::__cxx_atomic_load_inplace(std::addressof(__self.__a_), std::addressof(__old), memory_order_relaxed);
393 }
394# endif
395 __new = __operation(__old, __operand);
396 }
397 return __old;
398 }
399 }
400
401 template <class _This>
402 _LIBCPP_HIDE_FROM_ABI static _Tp __fetch_add(_This&& __self, _Tp __operand, memory_order __m) {
403 auto __builtin_op = [](auto __a, auto __builtin_operand, auto __order) {
404 return std::__cxx_atomic_fetch_add(__a, __builtin_operand, __order);
405 };
406 auto __plus = [](auto __a, auto __b) { return __a + __b; };
407 return __rmw_op(std::forward<_This>(__self), __operand, __m, __plus, __builtin_op);
408 }
409
410 template <class _This>
411 _LIBCPP_HIDE_FROM_ABI static _Tp __fetch_sub(_This&& __self, _Tp __operand, memory_order __m) {
412 auto __builtin_op = [](auto __a, auto __builtin_operand, auto __order) {
413 return std::__cxx_atomic_fetch_sub(__a, __builtin_operand, __order);
414 };
415 auto __minus = [](auto __a, auto __b) { return __a - __b; };
416 return __rmw_op(std::forward<_This>(__self), __operand, __m, __minus, __builtin_op);
417 }
418
419public:
420 using __base _LIBCPP_NODEBUG = __atomic_base<_Tp>;
421 using value_type = _Tp;
422 using difference_type = value_type;
423
424 _LIBCPP_HIDE_FROM_ABI constexpr atomic() noexcept = default;
425 _LIBCPP_HIDE_FROM_ABI constexpr atomic(_Tp __d) noexcept : __base(__d) {}
426
427 atomic(const atomic&) = delete;
428 atomic& operator=(const atomic&) = delete;
429 atomic& operator=(const atomic&) volatile = delete;
430
431 _LIBCPP_HIDE_FROM_ABI _Tp operator=(_Tp __d) volatile noexcept
432 requires __base::is_always_lock_free
433 {
434 __base::store(__d);
435 return __d;
436 }
437 _LIBCPP_HIDE_FROM_ABI _Tp operator=(_Tp __d) noexcept {
438 __base::store(__d);
439 return __d;
440 }
441
442 _LIBCPP_HIDE_FROM_ABI _Tp fetch_add(_Tp __op, memory_order __m = memory_order_seq_cst) volatile noexcept
443 requires __base::is_always_lock_free
444 {
445 return __fetch_add(*this, __op, __m);
446 }
447
448 _LIBCPP_HIDE_FROM_ABI _Tp fetch_add(_Tp __op, memory_order __m = memory_order_seq_cst) noexcept {
449 return __fetch_add(*this, __op, __m);
450 }
451
452 _LIBCPP_HIDE_FROM_ABI _Tp fetch_sub(_Tp __op, memory_order __m = memory_order_seq_cst) volatile noexcept
453 requires __base::is_always_lock_free
454 {
455 return __fetch_sub(*this, __op, __m);
456 }
457
458 _LIBCPP_HIDE_FROM_ABI _Tp fetch_sub(_Tp __op, memory_order __m = memory_order_seq_cst) noexcept {
459 return __fetch_sub(*this, __op, __m);
460 }
461
462 _LIBCPP_HIDE_FROM_ABI _Tp operator+=(_Tp __op) volatile noexcept
463 requires __base::is_always_lock_free
464 {
465 return fetch_add(__op) + __op;
466 }
467
468 _LIBCPP_HIDE_FROM_ABI _Tp operator+=(_Tp __op) noexcept { return fetch_add(__op) + __op; }
469
470 _LIBCPP_HIDE_FROM_ABI _Tp operator-=(_Tp __op) volatile noexcept
471 requires __base::is_always_lock_free
472 {
473 return fetch_sub(__op) - __op;
474 }
475
476 _LIBCPP_HIDE_FROM_ABI _Tp operator-=(_Tp __op) noexcept { return fetch_sub(__op) - __op; }
477};
478
479#endif // _LIBCPP_STD_VER >= 20
480
481// atomic_is_lock_free
482
483template <class _Tp>
484[[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI bool atomic_is_lock_free(const volatile atomic<_Tp>* __o) _NOEXCEPT {
485 return __o->is_lock_free();
486}
487
488template <class _Tp>
489[[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI bool atomic_is_lock_free(const atomic<_Tp>* __o) _NOEXCEPT {
490 return __o->is_lock_free();
491}
492
493// atomic_init
494
495template <class _Tp>
496_LIBCPP_DEPRECATED_IN_CXX20 _LIBCPP_HIDE_FROM_ABI void
497atomic_init(volatile atomic<_Tp>* __o, typename atomic<_Tp>::value_type __d) _NOEXCEPT {
498 std::__cxx_atomic_init(std::addressof(__o->__a_), __d);
499}
500
501template <class _Tp>
502_LIBCPP_DEPRECATED_IN_CXX20 _LIBCPP_HIDE_FROM_ABI void
503atomic_init(atomic<_Tp>* __o, typename atomic<_Tp>::value_type __d) _NOEXCEPT {
504 std::__cxx_atomic_init(std::addressof(__o->__a_), __d);
505}
506
507// atomic_store
508
509template <class _Tp>
510_LIBCPP_HIDE_FROM_ABI void atomic_store(volatile atomic<_Tp>* __o, typename atomic<_Tp>::value_type __d) _NOEXCEPT {
511 __o->store(__d);
512}
513
514template <class _Tp>
515_LIBCPP_HIDE_FROM_ABI void atomic_store(atomic<_Tp>* __o, typename atomic<_Tp>::value_type __d) _NOEXCEPT {
516 __o->store(__d);
517}
518
519// atomic_store_explicit
520
521template <class _Tp>
522_LIBCPP_HIDE_FROM_ABI void
523atomic_store_explicit(volatile atomic<_Tp>* __o, typename atomic<_Tp>::value_type __d, memory_order __m) _NOEXCEPT
524 _LIBCPP_CHECK_STORE_MEMORY_ORDER(__m) {
525 __o->store(__d, __m);
526}
527
528template <class _Tp>
529_LIBCPP_HIDE_FROM_ABI void
530atomic_store_explicit(atomic<_Tp>* __o, typename atomic<_Tp>::value_type __d, memory_order __m) _NOEXCEPT
531 _LIBCPP_CHECK_STORE_MEMORY_ORDER(__m) {
532 __o->store(__d, __m);
533}
534
535// atomic_load
536
537template <class _Tp>
538[[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _Tp atomic_load(const volatile atomic<_Tp>* __o) _NOEXCEPT {
539 return __o->load();
540}
541
542template <class _Tp>
543[[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _Tp atomic_load(const atomic<_Tp>* __o) _NOEXCEPT {
544 return __o->load();
545}
546
547// atomic_load_explicit
548
549template <class _Tp>
550[[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _Tp
551atomic_load_explicit(const volatile atomic<_Tp>* __o, memory_order __m) _NOEXCEPT _LIBCPP_CHECK_LOAD_MEMORY_ORDER(__m) {
552 return __o->load(__m);
553}
554
555template <class _Tp>
556[[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _Tp atomic_load_explicit(const atomic<_Tp>* __o, memory_order __m) _NOEXCEPT
557 _LIBCPP_CHECK_LOAD_MEMORY_ORDER(__m) {
558 return __o->load(__m);
559}
560
561// atomic_exchange
562
563template <class _Tp>
564_LIBCPP_HIDE_FROM_ABI _Tp atomic_exchange(volatile atomic<_Tp>* __o, typename atomic<_Tp>::value_type __d) _NOEXCEPT {
565 return __o->exchange(__d);
566}
567
568template <class _Tp>
569_LIBCPP_HIDE_FROM_ABI _Tp atomic_exchange(atomic<_Tp>* __o, typename atomic<_Tp>::value_type __d) _NOEXCEPT {
570 return __o->exchange(__d);
571}
572
573// atomic_exchange_explicit
574
575template <class _Tp>
576_LIBCPP_HIDE_FROM_ABI _Tp
577atomic_exchange_explicit(volatile atomic<_Tp>* __o, typename atomic<_Tp>::value_type __d, memory_order __m) _NOEXCEPT {
578 return __o->exchange(__d, __m);
579}
580
581template <class _Tp>
582_LIBCPP_HIDE_FROM_ABI _Tp
583atomic_exchange_explicit(atomic<_Tp>* __o, typename atomic<_Tp>::value_type __d, memory_order __m) _NOEXCEPT {
584 return __o->exchange(__d, __m);
585}
586
587// atomic_compare_exchange_weak
588
589template <class _Tp>
590_LIBCPP_HIDE_FROM_ABI bool atomic_compare_exchange_weak(
591 volatile atomic<_Tp>* __o, typename atomic<_Tp>::value_type* __e, typename atomic<_Tp>::value_type __d) _NOEXCEPT {
592 return __o->compare_exchange_weak(*__e, __d);
593}
594
595template <class _Tp>
596_LIBCPP_HIDE_FROM_ABI bool atomic_compare_exchange_weak(
597 atomic<_Tp>* __o, typename atomic<_Tp>::value_type* __e, typename atomic<_Tp>::value_type __d) _NOEXCEPT {
598 return __o->compare_exchange_weak(*__e, __d);
599}
600
601// atomic_compare_exchange_strong
602
603template <class _Tp>
604_LIBCPP_HIDE_FROM_ABI bool atomic_compare_exchange_strong(
605 volatile atomic<_Tp>* __o, typename atomic<_Tp>::value_type* __e, typename atomic<_Tp>::value_type __d) _NOEXCEPT {
606 return __o->compare_exchange_strong(*__e, __d);
607}
608
609template <class _Tp>
610_LIBCPP_HIDE_FROM_ABI bool atomic_compare_exchange_strong(
611 atomic<_Tp>* __o, typename atomic<_Tp>::value_type* __e, typename atomic<_Tp>::value_type __d) _NOEXCEPT {
612 return __o->compare_exchange_strong(*__e, __d);
613}
614
615// atomic_compare_exchange_weak_explicit
616
617template <class _Tp>
618_LIBCPP_HIDE_FROM_ABI bool atomic_compare_exchange_weak_explicit(
619 volatile atomic<_Tp>* __o,
620 typename atomic<_Tp>::value_type* __e,
621 typename atomic<_Tp>::value_type __d,
622 memory_order __s,
623 memory_order __f) _NOEXCEPT _LIBCPP_CHECK_EXCHANGE_MEMORY_ORDER(__s, __f) {
624 return __o->compare_exchange_weak(*__e, __d, __s, __f);
625}
626
627template <class _Tp>
628_LIBCPP_HIDE_FROM_ABI bool atomic_compare_exchange_weak_explicit(
629 atomic<_Tp>* __o,
630 typename atomic<_Tp>::value_type* __e,
631 typename atomic<_Tp>::value_type __d,
632 memory_order __s,
633 memory_order __f) _NOEXCEPT _LIBCPP_CHECK_EXCHANGE_MEMORY_ORDER(__s, __f) {
634 return __o->compare_exchange_weak(*__e, __d, __s, __f);
635}
636
637// atomic_compare_exchange_strong_explicit
638
639template <class _Tp>
640_LIBCPP_HIDE_FROM_ABI bool atomic_compare_exchange_strong_explicit(
641 volatile atomic<_Tp>* __o,
642 typename atomic<_Tp>::value_type* __e,
643 typename atomic<_Tp>::value_type __d,
644 memory_order __s,
645 memory_order __f) _NOEXCEPT _LIBCPP_CHECK_EXCHANGE_MEMORY_ORDER(__s, __f) {
646 return __o->compare_exchange_strong(*__e, __d, __s, __f);
647}
648
649template <class _Tp>
650_LIBCPP_HIDE_FROM_ABI bool atomic_compare_exchange_strong_explicit(
651 atomic<_Tp>* __o,
652 typename atomic<_Tp>::value_type* __e,
653 typename atomic<_Tp>::value_type __d,
654 memory_order __s,
655 memory_order __f) _NOEXCEPT _LIBCPP_CHECK_EXCHANGE_MEMORY_ORDER(__s, __f) {
656 return __o->compare_exchange_strong(*__e, __d, __s, __f);
657}
658
659#if _LIBCPP_STD_VER >= 20
660
661// atomic_wait
662
663template <class _Tp>
664_LIBCPP_HIDE_FROM_ABI void atomic_wait(const volatile atomic<_Tp>* __o, typename atomic<_Tp>::value_type __v) noexcept {
665 return __o->wait(__v);
666}
667
668template <class _Tp>
669_LIBCPP_HIDE_FROM_ABI void atomic_wait(const atomic<_Tp>* __o, typename atomic<_Tp>::value_type __v) noexcept {
670 return __o->wait(__v);
671}
672
673// atomic_wait_explicit
674
675template <class _Tp>
676_LIBCPP_HIDE_FROM_ABI void
677atomic_wait_explicit(const volatile atomic<_Tp>* __o, typename atomic<_Tp>::value_type __v, memory_order __m) noexcept
678 _LIBCPP_CHECK_LOAD_MEMORY_ORDER(__m) {
679 return __o->wait(__v, __m);
680}
681
682template <class _Tp>
683_LIBCPP_HIDE_FROM_ABI void
684atomic_wait_explicit(const atomic<_Tp>* __o, typename atomic<_Tp>::value_type __v, memory_order __m) noexcept
685 _LIBCPP_CHECK_LOAD_MEMORY_ORDER(__m) {
686 return __o->wait(__v, __m);
687}
688
689// atomic_notify_one
690
691template <class _Tp>
692_LIBCPP_HIDE_FROM_ABI void atomic_notify_one(volatile atomic<_Tp>* __o) noexcept {
693 __o->notify_one();
694}
695template <class _Tp>
696_LIBCPP_HIDE_FROM_ABI void atomic_notify_one(atomic<_Tp>* __o) noexcept {
697 __o->notify_one();
698}
699
700// atomic_notify_all
701
702template <class _Tp>
703_LIBCPP_HIDE_FROM_ABI void atomic_notify_all(volatile atomic<_Tp>* __o) noexcept {
704 __o->notify_all();
705}
706template <class _Tp>
707_LIBCPP_HIDE_FROM_ABI void atomic_notify_all(atomic<_Tp>* __o) noexcept {
708 __o->notify_all();
709}
710
711#endif // _LIBCPP_STD_VER >= 20
712
713// atomic_fetch_add
714
715template <class _Tp>
716_LIBCPP_HIDE_FROM_ABI _Tp
717atomic_fetch_add(volatile atomic<_Tp>* __o, typename atomic<_Tp>::difference_type __op) _NOEXCEPT {
718 return __o->fetch_add(__op);
719}
720
721template <class _Tp>
722_LIBCPP_HIDE_FROM_ABI _Tp atomic_fetch_add(atomic<_Tp>* __o, typename atomic<_Tp>::difference_type __op) _NOEXCEPT {
723 return __o->fetch_add(__op);
724}
725
726// atomic_fetch_add_explicit
727
728template <class _Tp>
729_LIBCPP_HIDE_FROM_ABI _Tp atomic_fetch_add_explicit(
730 volatile atomic<_Tp>* __o, typename atomic<_Tp>::difference_type __op, memory_order __m) _NOEXCEPT {
731 return __o->fetch_add(__op, __m);
732}
733
734template <class _Tp>
735_LIBCPP_HIDE_FROM_ABI _Tp
736atomic_fetch_add_explicit(atomic<_Tp>* __o, typename atomic<_Tp>::difference_type __op, memory_order __m) _NOEXCEPT {
737 return __o->fetch_add(__op, __m);
738}
739
740// atomic_fetch_sub
741
742template <class _Tp>
743_LIBCPP_HIDE_FROM_ABI _Tp
744atomic_fetch_sub(volatile atomic<_Tp>* __o, typename atomic<_Tp>::difference_type __op) _NOEXCEPT {
745 return __o->fetch_sub(__op);
746}
747
748template <class _Tp>
749_LIBCPP_HIDE_FROM_ABI _Tp atomic_fetch_sub(atomic<_Tp>* __o, typename atomic<_Tp>::difference_type __op) _NOEXCEPT {
750 return __o->fetch_sub(__op);
751}
752
753// atomic_fetch_sub_explicit
754
755template <class _Tp>
756_LIBCPP_HIDE_FROM_ABI _Tp atomic_fetch_sub_explicit(
757 volatile atomic<_Tp>* __o, typename atomic<_Tp>::difference_type __op, memory_order __m) _NOEXCEPT {
758 return __o->fetch_sub(__op, __m);
759}
760
761template <class _Tp>
762_LIBCPP_HIDE_FROM_ABI _Tp
763atomic_fetch_sub_explicit(atomic<_Tp>* __o, typename atomic<_Tp>::difference_type __op, memory_order __m) _NOEXCEPT {
764 return __o->fetch_sub(__op, __m);
765}
766
767// atomic_fetch_and
768
769template <class _Tp, __enable_if_t<is_integral<_Tp>::value && !is_same<_Tp, bool>::value, int> = 0>
770_LIBCPP_HIDE_FROM_ABI _Tp atomic_fetch_and(volatile atomic<_Tp>* __o, typename atomic<_Tp>::value_type __op) _NOEXCEPT {
771 return __o->fetch_and(__op);
772}
773
774template <class _Tp, __enable_if_t<is_integral<_Tp>::value && !is_same<_Tp, bool>::value, int> = 0>
775_LIBCPP_HIDE_FROM_ABI _Tp atomic_fetch_and(atomic<_Tp>* __o, typename atomic<_Tp>::value_type __op) _NOEXCEPT {
776 return __o->fetch_and(__op);
777}
778
779// atomic_fetch_and_explicit
780
781template <class _Tp, __enable_if_t<is_integral<_Tp>::value && !is_same<_Tp, bool>::value, int> = 0>
782_LIBCPP_HIDE_FROM_ABI _Tp atomic_fetch_and_explicit(
783 volatile atomic<_Tp>* __o, typename atomic<_Tp>::value_type __op, memory_order __m) _NOEXCEPT {
784 return __o->fetch_and(__op, __m);
785}
786
787template <class _Tp, __enable_if_t<is_integral<_Tp>::value && !is_same<_Tp, bool>::value, int> = 0>
788_LIBCPP_HIDE_FROM_ABI _Tp
789atomic_fetch_and_explicit(atomic<_Tp>* __o, typename atomic<_Tp>::value_type __op, memory_order __m) _NOEXCEPT {
790 return __o->fetch_and(__op, __m);
791}
792
793// atomic_fetch_or
794
795template <class _Tp, __enable_if_t<is_integral<_Tp>::value && !is_same<_Tp, bool>::value, int> = 0>
796_LIBCPP_HIDE_FROM_ABI _Tp atomic_fetch_or(volatile atomic<_Tp>* __o, typename atomic<_Tp>::value_type __op) _NOEXCEPT {
797 return __o->fetch_or(__op);
798}
799
800template <class _Tp, __enable_if_t<is_integral<_Tp>::value && !is_same<_Tp, bool>::value, int> = 0>
801_LIBCPP_HIDE_FROM_ABI _Tp atomic_fetch_or(atomic<_Tp>* __o, typename atomic<_Tp>::value_type __op) _NOEXCEPT {
802 return __o->fetch_or(__op);
803}
804
805// atomic_fetch_or_explicit
806
807template <class _Tp, __enable_if_t<is_integral<_Tp>::value && !is_same<_Tp, bool>::value, int> = 0>
808_LIBCPP_HIDE_FROM_ABI _Tp
809atomic_fetch_or_explicit(volatile atomic<_Tp>* __o, typename atomic<_Tp>::value_type __op, memory_order __m) _NOEXCEPT {
810 return __o->fetch_or(__op, __m);
811}
812
813template <class _Tp, __enable_if_t<is_integral<_Tp>::value && !is_same<_Tp, bool>::value, int> = 0>
814_LIBCPP_HIDE_FROM_ABI _Tp
815atomic_fetch_or_explicit(atomic<_Tp>* __o, typename atomic<_Tp>::value_type __op, memory_order __m) _NOEXCEPT {
816 return __o->fetch_or(__op, __m);
817}
818
819// atomic_fetch_xor
820
821template <class _Tp, __enable_if_t<is_integral<_Tp>::value && !is_same<_Tp, bool>::value, int> = 0>
822_LIBCPP_HIDE_FROM_ABI _Tp atomic_fetch_xor(volatile atomic<_Tp>* __o, typename atomic<_Tp>::value_type __op) _NOEXCEPT {
823 return __o->fetch_xor(__op);
824}
825
826template <class _Tp, __enable_if_t<is_integral<_Tp>::value && !is_same<_Tp, bool>::value, int> = 0>
827_LIBCPP_HIDE_FROM_ABI _Tp atomic_fetch_xor(atomic<_Tp>* __o, typename atomic<_Tp>::value_type __op) _NOEXCEPT {
828 return __o->fetch_xor(__op);
829}
830
831// atomic_fetch_xor_explicit
832
833template <class _Tp, __enable_if_t<is_integral<_Tp>::value && !is_same<_Tp, bool>::value, int> = 0>
834_LIBCPP_HIDE_FROM_ABI _Tp atomic_fetch_xor_explicit(
835 volatile atomic<_Tp>* __o, typename atomic<_Tp>::value_type __op, memory_order __m) _NOEXCEPT {
836 return __o->fetch_xor(__op, __m);
837}
838
839template <class _Tp, __enable_if_t<is_integral<_Tp>::value && !is_same<_Tp, bool>::value, int> = 0>
840_LIBCPP_HIDE_FROM_ABI _Tp
841atomic_fetch_xor_explicit(atomic<_Tp>* __o, typename atomic<_Tp>::value_type __op, memory_order __m) _NOEXCEPT {
842 return __o->fetch_xor(__op, __m);
843}
844
845#if _LIBCPP_STD_VER >= 26
846// atomic_fetch_max
847
848template <class _Tp>
849 requires((integral<_Tp> && !same_as<_Tp, bool>) || is_pointer_v<_Tp>)
850_LIBCPP_HIDE_FROM_ABI _Tp atomic_fetch_max(volatile atomic<_Tp>* __o, typename atomic<_Tp>::value_type __op) noexcept {
851 return __o->fetch_max(__op);
852}
853
854template <class _Tp>
855 requires((integral<_Tp> && !same_as<_Tp, bool>) || is_pointer_v<_Tp>)
856_LIBCPP_HIDE_FROM_ABI _Tp atomic_fetch_max(atomic<_Tp>* __o, typename atomic<_Tp>::value_type __op) noexcept {
857 return __o->fetch_max(__op);
858}
859
860// atomic_fetch_max_explicit
861
862template <class _Tp>
863 requires((integral<_Tp> && !same_as<_Tp, bool>) || is_pointer_v<_Tp>)
864_LIBCPP_HIDE_FROM_ABI _Tp
865atomic_fetch_max_explicit(volatile atomic<_Tp>* __o, typename atomic<_Tp>::value_type __op, memory_order __m) noexcept {
866 return __o->fetch_max(__op, __m);
867}
868
869template <class _Tp>
870 requires((integral<_Tp> && !same_as<_Tp, bool>) || is_pointer_v<_Tp>)
871_LIBCPP_HIDE_FROM_ABI _Tp
872atomic_fetch_max_explicit(atomic<_Tp>* __o, typename atomic<_Tp>::value_type __op, memory_order __m) noexcept {
873 return __o->fetch_max(__op, __m);
874}
875
876// atomic_fetch_min
877
878template <class _Tp>
879 requires((integral<_Tp> && !same_as<_Tp, bool>) || is_pointer_v<_Tp>)
880_LIBCPP_HIDE_FROM_ABI _Tp atomic_fetch_min(volatile atomic<_Tp>* __o, typename atomic<_Tp>::value_type __op) noexcept {
881 return __o->fetch_min(__op);
882}
883
884template <class _Tp>
885 requires((integral<_Tp> && !same_as<_Tp, bool>) || is_pointer_v<_Tp>)
886_LIBCPP_HIDE_FROM_ABI _Tp atomic_fetch_min(atomic<_Tp>* __o, typename atomic<_Tp>::value_type __op) noexcept {
887 return __o->fetch_min(__op);
888}
889
890// atomic_fetch_min_explicit
891
892template <class _Tp>
893 requires((integral<_Tp> && !same_as<_Tp, bool>) || is_pointer_v<_Tp>)
894_LIBCPP_HIDE_FROM_ABI _Tp
895atomic_fetch_min_explicit(volatile atomic<_Tp>* __o, typename atomic<_Tp>::value_type __op, memory_order __m) noexcept {
896 return __o->fetch_min(__op, __m);
897}
898
899template <class _Tp>
900 requires((integral<_Tp> && !same_as<_Tp, bool>) || is_pointer_v<_Tp>)
901_LIBCPP_HIDE_FROM_ABI _Tp
902atomic_fetch_min_explicit(atomic<_Tp>* __o, typename atomic<_Tp>::value_type __op, memory_order __m) noexcept {
903 return __o->fetch_min(__op, __m);
904}
905#endif
906
907_LIBCPP_END_NAMESPACE_STD
908
909#endif // _LIBCPP___ATOMIC_ATOMIC_H
910