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