libstdc++: atomic_base.h Source File

libstdc++

atomic_base.h
Go to the documentation of this file.
1// -*- C++ -*- header.
2
3// Copyright (C) 2008-2026 Free Software Foundation, Inc.
4//
5// This file is part of the GNU ISO C++ Library. This library is free
6// software; you can redistribute it and/or modify it under the
7// terms of the GNU General Public License as published by the
8// Free Software Foundation; either version 3, or (at your option)
9// any later version.
10
11// This library is distributed in the hope that it will be useful,
12// but WITHOUT ANY WARRANTY; without even the implied warranty of
13// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14// GNU General Public License for more details.
15
16// Under Section 7 of GPL version 3, you are granted additional
17// permissions described in the GCC Runtime Library Exception, version
18// 3.1, as published by the Free Software Foundation.
19
20// You should have received a copy of the GNU General Public License and
21// a copy of the GCC Runtime Library Exception along with this program;
22// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
23// <http://www.gnu.org/licenses/>.
24
25/** @file bits/atomic_base.h
26 * This is an internal header file, included by other library headers.
27 * Do not attempt to use it directly. @headername{atomic}
28 */
29
30#ifndef _GLIBCXX_ATOMIC_BASE_H
31#define _GLIBCXX_ATOMIC_BASE_H 1
32
33#ifdef _GLIBCXX_SYSHDR
34#pragma GCC system_header
35#endif
36
37#include <bits/c++config.h>
38#include <new> // For placement new
39#include <bits/atomic_lockfree_defines.h>
40#include <bits/move.h>
41
42#if __cplusplus > 201703L && _GLIBCXX_HOSTED
43#include <bits/atomic_wait.h>
44#endif
45
46#ifndef _GLIBCXX_ALWAYS_INLINE
47#define _GLIBCXX_ALWAYS_INLINE inline __attribute__((__always_inline__))
48#endif
49
50#include <bits/version.h>
51
52namespace std _GLIBCXX_VISIBILITY(default)
53{
54_GLIBCXX_BEGIN_NAMESPACE_VERSION
55
56 /**
57 * @defgroup atomics Atomics
58 *
59 * Components for performing atomic operations.
60 * @{
61 */
62
63 /// Enumeration for memory_order
64#if __cplusplus > 201703L
65 enum class memory_order : int
66 {
67 relaxed = 0,
68 consume _GLIBCXX26_DEPRECATED = 1,
69 acquire = 2,
70 release = 3,
71 acq_rel = 4,
72 seq_cst = 5
73 };
74
75 inline constexpr memory_order memory_order_relaxed = memory_order::relaxed;
76 inline constexpr memory_order memory_order_acquire = memory_order::acquire;
77 inline constexpr memory_order memory_order_release = memory_order::release;
78 inline constexpr memory_order memory_order_acq_rel = memory_order::acq_rel;
79 inline constexpr memory_order memory_order_seq_cst = memory_order::seq_cst;
80
81#pragma GCC diagnostic push
82#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
83 _GLIBCXX26_DEPRECATED
84 inline constexpr memory_order memory_order_consume = memory_order::consume;
85#pragma GCC diagnostic pop
86#else
87 enum memory_order : int
88 {
89 memory_order_relaxed,
90 memory_order_consume,
91 memory_order_acquire,
92 memory_order_release,
93 memory_order_acq_rel,
94 memory_order_seq_cst
95 };
96#endif
97
98 /// @cond undocumented
99 enum __memory_order_modifier
100 {
101 __memory_order_mask = 0x0ffff,
102 __memory_order_modifier_mask = 0xffff0000,
103 __memory_order_hle_acquire = 0x10000,
104 __memory_order_hle_release = 0x20000
105 };
106 /// @endcond
107
108 constexpr memory_order
109 operator|(memory_order __m, __memory_order_modifier __mod) noexcept
110 {
111 return memory_order(int(__m) | int(__mod));
112 }
113
114 constexpr memory_order
115 operator&(memory_order __m, __memory_order_modifier __mod) noexcept
116 {
117 return memory_order(int(__m) & int(__mod));
118 }
119
120 /// @cond undocumented
121
122 // Drop release ordering as per [atomics.types.operations.req]/21
123 constexpr memory_order
124 __cmpexch_failure_order2(memory_order __m) noexcept
125 {
126 return __m == memory_order_acq_rel ? memory_order_acquire
127 : __m == memory_order_release ? memory_order_relaxed : __m;
128 }
129
130 constexpr memory_order
131 __cmpexch_failure_order(memory_order __m) noexcept
132 {
133 return memory_order(__cmpexch_failure_order2(__m & __memory_order_mask)
134 | __memory_order_modifier(__m & __memory_order_modifier_mask));
135 }
136
137 constexpr bool
138 __is_valid_cmpexch_failure_order(memory_order __m) noexcept
139 {
140 return (__m & __memory_order_mask) != memory_order_release
141 && (__m & __memory_order_mask) != memory_order_acq_rel;
142 }
143
144 // Base types for atomics.
145 template<typename _IntTp>
146 struct __atomic_base;
147
148 /// @endcond
149
150 _GLIBCXX_ALWAYS_INLINE void
151 atomic_thread_fence(memory_order __m) noexcept
152 { __atomic_thread_fence(int(__m)); }
153
154 _GLIBCXX_ALWAYS_INLINE void
155 atomic_signal_fence(memory_order __m) noexcept
156 { __atomic_signal_fence(int(__m)); }
157
158 /// kill_dependency
159 template<typename _Tp>
160 _GLIBCXX26_DEPRECATED
161 inline _Tp
162 kill_dependency(_Tp __y) noexcept
163 {
164 _Tp __ret(__y);
165 return __ret;
166 }
167
168/// @cond undocumented
169#if __glibcxx_atomic_value_initialization
170# define _GLIBCXX20_INIT(I) = I
171#else
172# define _GLIBCXX20_INIT(I)
173#endif
174/// @endcond
175
176#define ATOMIC_VAR_INIT(_VI) { _VI }
177
178 template<typename _Tp>
179 struct atomic;
180
181 template<typename _Tp>
182 struct atomic<_Tp*>;
183
184 /* The target's "set" value for test-and-set may not be exactly 1. */
185#if __GCC_ATOMIC_TEST_AND_SET_TRUEVAL == 1
186 typedef bool __atomic_flag_data_type;
187#else
188 typedef unsigned char __atomic_flag_data_type;
189#endif
190
191 /// @cond undocumented
192
193 /*
194 * Base type for atomic_flag.
195 *
196 * Base type is POD with data, allowing atomic_flag to derive from
197 * it and meet the standard layout type requirement. In addition to
198 * compatibility with a C interface, this allows different
199 * implementations of atomic_flag to use the same atomic operation
200 * functions, via a standard conversion to the __atomic_flag_base
201 * argument.
202 */
203 _GLIBCXX_BEGIN_EXTERN_C
204
205 struct __atomic_flag_base
206 {
207 __atomic_flag_data_type _M_i _GLIBCXX20_INIT({});
208 };
209
210 _GLIBCXX_END_EXTERN_C
211
212 /// @endcond
213
214#define ATOMIC_FLAG_INIT { 0 }
215
216 /// atomic_flag
217 struct atomic_flag : public __atomic_flag_base
218 {
219 atomic_flag() noexcept = default;
220 ~atomic_flag() noexcept = default;
221 atomic_flag(const atomic_flag&) = delete;
222 atomic_flag& operator=(const atomic_flag&) = delete;
223 atomic_flag& operator=(const atomic_flag&) volatile = delete;
224
225 // Conversion to ATOMIC_FLAG_INIT.
226 constexpr atomic_flag(bool __i) noexcept
227 : __atomic_flag_base{ _S_init(__i) }
228 { }
229
230 _GLIBCXX_ALWAYS_INLINE bool
231 test_and_set(memory_order __m = memory_order_seq_cst) noexcept
232 {
233 return __atomic_test_and_set (&_M_i, int(__m));
234 }
235
236 _GLIBCXX_ALWAYS_INLINE bool
237 test_and_set(memory_order __m = memory_order_seq_cst) volatile noexcept
238 {
239 return __atomic_test_and_set (&_M_i, int(__m));
240 }
241
242#ifdef __glibcxx_atomic_flag_test // C++ >= 20
243 _GLIBCXX_ALWAYS_INLINE bool
244 test(memory_order __m = memory_order_seq_cst) const noexcept
245 {
246 __atomic_flag_data_type __v;
247 __atomic_load(&_M_i, &__v, int(__m));
248 return __v == __GCC_ATOMIC_TEST_AND_SET_TRUEVAL;
249 }
250
251 _GLIBCXX_ALWAYS_INLINE bool
252 test(memory_order __m = memory_order_seq_cst) const volatile noexcept
253 {
254 __atomic_flag_data_type __v;
255 __atomic_load(&_M_i, &__v, int(__m));
256 return __v == __GCC_ATOMIC_TEST_AND_SET_TRUEVAL;
257 }
258#endif
259
260#if __glibcxx_atomic_wait // C++ >= 20 && (linux_futex || gthread)
261 _GLIBCXX_ALWAYS_INLINE void
262 wait(bool __old,
263 memory_order __m = memory_order_seq_cst) const noexcept
264 {
265 const __atomic_flag_data_type __v
266 = __old ? __GCC_ATOMIC_TEST_AND_SET_TRUEVAL : 0;
267
268 std::__atomic_wait_address_v(&_M_i, __v,
269 [__m, this] { return __atomic_load_n(&_M_i, int(__m)); });
270 }
271
272 // TODO add const volatile overload
273
274 _GLIBCXX_ALWAYS_INLINE void
275 notify_one() noexcept
276 { std::__atomic_notify_address(&_M_i, false); }
277
278 // TODO add const volatile overload
279
280 _GLIBCXX_ALWAYS_INLINE void
281 notify_all() noexcept
282 { std::__atomic_notify_address(&_M_i, true); }
283
284 // TODO add const volatile overload
285#endif // __glibcxx_atomic_wait
286
287#pragma GCC diagnostic push
288#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
289 _GLIBCXX_ALWAYS_INLINE void
290 clear(memory_order __m = memory_order_seq_cst) noexcept
291 {
292 memory_order __b __attribute__ ((__unused__))
293 = __m & __memory_order_mask;
294 __glibcxx_assert(__b != memory_order_consume);
295 __glibcxx_assert(__b != memory_order_acquire);
296 __glibcxx_assert(__b != memory_order_acq_rel);
297
298 __atomic_clear (&_M_i, int(__m));
299 }
300
301 _GLIBCXX_ALWAYS_INLINE void
302 clear(memory_order __m = memory_order_seq_cst) volatile noexcept
303 {
304 memory_order __b __attribute__ ((__unused__))
305 = __m & __memory_order_mask;
306 __glibcxx_assert(__b != memory_order_consume);
307 __glibcxx_assert(__b != memory_order_acquire);
308 __glibcxx_assert(__b != memory_order_acq_rel);
309
310 __atomic_clear (&_M_i, int(__m));
311 }
312#pragma GCC diagnostic pop
313
314 private:
315 static constexpr __atomic_flag_data_type
316 _S_init(bool __i)
317 { return __i ? __GCC_ATOMIC_TEST_AND_SET_TRUEVAL : 0; }
318 };
319
320 /// @cond undocumented
321
322 /// Base class for atomic integrals.
323 //
324 // For each of the integral types, define atomic_[integral type] struct
325 //
326 // atomic_bool bool
327 // atomic_char char
328 // atomic_schar signed char
329 // atomic_uchar unsigned char
330 // atomic_short short
331 // atomic_ushort unsigned short
332 // atomic_int int
333 // atomic_uint unsigned int
334 // atomic_long long
335 // atomic_ulong unsigned long
336 // atomic_llong long long
337 // atomic_ullong unsigned long long
338 // atomic_char8_t char8_t
339 // atomic_char16_t char16_t
340 // atomic_char32_t char32_t
341 // atomic_wchar_t wchar_t
342 //
343 // NB: Assuming _ITp is an integral scalar type that is 1, 2, 4, or
344 // 8 bytes, since that is what GCC built-in functions for atomic
345 // memory access expect.
346
347 namespace __atomic_impl
348 {
349 template<typename _Tp>
350 using _Val = typename remove_volatile<_Tp>::type;
351
352#if __glibcxx_atomic_min_max
353 template<typename _Tp>
354 _Tp
355 __fetch_min(_Tp* __ptr, _Val<_Tp> __i, memory_order __m) noexcept;
356
357 template<typename _Tp>
358 _Tp
359 __fetch_max(_Tp* __ptr, _Val<_Tp> __i, memory_order __m) noexcept;
360#endif
361 }
362
363 template<typename _ITp>
364 struct __atomic_base
365 {
366 using value_type = _ITp;
367 using difference_type = value_type;
368
369 private:
370 typedef _ITp __int_type;
371
372 static constexpr int _S_alignment =
373 sizeof(_ITp) > alignof(_ITp) ? sizeof(_ITp) : alignof(_ITp);
374
375 alignas(_S_alignment) __int_type _M_i _GLIBCXX20_INIT(0);
376
377 public:
378 __atomic_base() noexcept = default;
379 ~__atomic_base() noexcept = default;
380 __atomic_base(const __atomic_base&) = delete;
381 __atomic_base& operator=(const __atomic_base&) = delete;
382 __atomic_base& operator=(const __atomic_base&) volatile = delete;
383
384 constexpr __atomic_base(__int_type __i) noexcept : _M_i (__i) { }
385
386 operator __int_type() const noexcept
387 { return load(); }
388
389 operator __int_type() const volatile noexcept
390 { return load(); }
391
392 __int_type
393 operator=(__int_type __i) noexcept
394 {
395 store(__i);
396 return __i;
397 }
398
399 __int_type
400 operator=(__int_type __i) volatile noexcept
401 {
402 store(__i);
403 return __i;
404 }
405
406 __int_type
407 operator++(int) noexcept
408 { return fetch_add(1); }
409
410 __int_type
411 operator++(int) volatile noexcept
412 { return fetch_add(1); }
413
414 __int_type
415 operator--(int) noexcept
416 { return fetch_sub(1); }
417
418 __int_type
419 operator--(int) volatile noexcept
420 { return fetch_sub(1); }
421
422 __int_type
423 operator++() noexcept
424 { return __atomic_add_fetch(&_M_i, 1, int(memory_order_seq_cst)); }
425
426 __int_type
427 operator++() volatile noexcept
428 { return __atomic_add_fetch(&_M_i, 1, int(memory_order_seq_cst)); }
429
430 __int_type
431 operator--() noexcept
432 { return __atomic_sub_fetch(&_M_i, 1, int(memory_order_seq_cst)); }
433
434 __int_type
435 operator--() volatile noexcept
436 { return __atomic_sub_fetch(&_M_i, 1, int(memory_order_seq_cst)); }
437
438 __int_type
439 operator+=(__int_type __i) noexcept
440 { return __atomic_add_fetch(&_M_i, __i, int(memory_order_seq_cst)); }
441
442 __int_type
443 operator+=(__int_type __i) volatile noexcept
444 { return __atomic_add_fetch(&_M_i, __i, int(memory_order_seq_cst)); }
445
446 __int_type
447 operator-=(__int_type __i) noexcept
448 { return __atomic_sub_fetch(&_M_i, __i, int(memory_order_seq_cst)); }
449
450 __int_type
451 operator-=(__int_type __i) volatile noexcept
452 { return __atomic_sub_fetch(&_M_i, __i, int(memory_order_seq_cst)); }
453
454 __int_type
455 operator&=(__int_type __i) noexcept
456 { return __atomic_and_fetch(&_M_i, __i, int(memory_order_seq_cst)); }
457
458 __int_type
459 operator&=(__int_type __i) volatile noexcept
460 { return __atomic_and_fetch(&_M_i, __i, int(memory_order_seq_cst)); }
461
462 __int_type
463 operator|=(__int_type __i) noexcept
464 { return __atomic_or_fetch(&_M_i, __i, int(memory_order_seq_cst)); }
465
466 __int_type
467 operator|=(__int_type __i) volatile noexcept
468 { return __atomic_or_fetch(&_M_i, __i, int(memory_order_seq_cst)); }
469
470 __int_type
471 operator^=(__int_type __i) noexcept
472 { return __atomic_xor_fetch(&_M_i, __i, int(memory_order_seq_cst)); }
473
474 __int_type
475 operator^=(__int_type __i) volatile noexcept
476 { return __atomic_xor_fetch(&_M_i, __i, int(memory_order_seq_cst)); }
477
478 bool
479 is_lock_free() const noexcept
480 {
481 // Use a fake, minimally aligned pointer.
482 return __atomic_is_lock_free(sizeof(_M_i),
483 reinterpret_cast<void *>(-_S_alignment));
484 }
485
486 bool
487 is_lock_free() const volatile noexcept
488 {
489 // Use a fake, minimally aligned pointer.
490 return __atomic_is_lock_free(sizeof(_M_i),
491 reinterpret_cast<void *>(-_S_alignment));
492 }
493
494#pragma GCC diagnostic push
495#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
496 _GLIBCXX_ALWAYS_INLINE void
497 store(__int_type __i, memory_order __m = memory_order_seq_cst) noexcept
498 {
499 memory_order __b __attribute__ ((__unused__))
500 = __m & __memory_order_mask;
501 __glibcxx_assert(__b != memory_order_acquire);
502 __glibcxx_assert(__b != memory_order_acq_rel);
503 __glibcxx_assert(__b != memory_order_consume);
504
505 __atomic_store_n(&_M_i, __i, int(__m));
506 }
507
508 _GLIBCXX_ALWAYS_INLINE void
509 store(__int_type __i,
510 memory_order __m = memory_order_seq_cst) volatile noexcept
511 {
512 memory_order __b __attribute__ ((__unused__))
513 = __m & __memory_order_mask;
514 __glibcxx_assert(__b != memory_order_acquire);
515 __glibcxx_assert(__b != memory_order_acq_rel);
516 __glibcxx_assert(__b != memory_order_consume);
517
518 __atomic_store_n(&_M_i, __i, int(__m));
519 }
520#pragma GCC diagnostic pop
521
522 _GLIBCXX_ALWAYS_INLINE __int_type
523 load(memory_order __m = memory_order_seq_cst) const noexcept
524 {
525 memory_order __b __attribute__ ((__unused__))
526 = __m & __memory_order_mask;
527 __glibcxx_assert(__b != memory_order_release);
528 __glibcxx_assert(__b != memory_order_acq_rel);
529
530 return __atomic_load_n(&_M_i, int(__m));
531 }
532
533 _GLIBCXX_ALWAYS_INLINE __int_type
534 load(memory_order __m = memory_order_seq_cst) const volatile noexcept
535 {
536 memory_order __b __attribute__ ((__unused__))
537 = __m & __memory_order_mask;
538 __glibcxx_assert(__b != memory_order_release);
539 __glibcxx_assert(__b != memory_order_acq_rel);
540
541 return __atomic_load_n(&_M_i, int(__m));
542 }
543
544 _GLIBCXX_ALWAYS_INLINE __int_type
545 exchange(__int_type __i,
546 memory_order __m = memory_order_seq_cst) noexcept
547 {
548 return __atomic_exchange_n(&_M_i, __i, int(__m));
549 }
550
551
552 _GLIBCXX_ALWAYS_INLINE __int_type
553 exchange(__int_type __i,
554 memory_order __m = memory_order_seq_cst) volatile noexcept
555 {
556 return __atomic_exchange_n(&_M_i, __i, int(__m));
557 }
558
559 _GLIBCXX_ALWAYS_INLINE bool
560 compare_exchange_weak(__int_type& __i1, __int_type __i2,
561 memory_order __m1, memory_order __m2) noexcept
562 {
563 __glibcxx_assert(__is_valid_cmpexch_failure_order(__m2));
564
565 return __atomic_compare_exchange_n(&_M_i, &__i1, __i2, 1,
566 int(__m1), int(__m2));
567 }
568
569 _GLIBCXX_ALWAYS_INLINE bool
570 compare_exchange_weak(__int_type& __i1, __int_type __i2,
571 memory_order __m1,
572 memory_order __m2) volatile noexcept
573 {
574 __glibcxx_assert(__is_valid_cmpexch_failure_order(__m2));
575
576 return __atomic_compare_exchange_n(&_M_i, &__i1, __i2, 1,
577 int(__m1), int(__m2));
578 }
579
580 _GLIBCXX_ALWAYS_INLINE bool
581 compare_exchange_weak(__int_type& __i1, __int_type __i2,
582 memory_order __m = memory_order_seq_cst) noexcept
583 {
584 return compare_exchange_weak(__i1, __i2, __m,
585 __cmpexch_failure_order(__m));
586 }
587
588 _GLIBCXX_ALWAYS_INLINE bool
589 compare_exchange_weak(__int_type& __i1, __int_type __i2,
590 memory_order __m = memory_order_seq_cst) volatile noexcept
591 {
592 return compare_exchange_weak(__i1, __i2, __m,
593 __cmpexch_failure_order(__m));
594 }
595
596 _GLIBCXX_ALWAYS_INLINE bool
597 compare_exchange_strong(__int_type& __i1, __int_type __i2,
598 memory_order __m1, memory_order __m2) noexcept
599 {
600 __glibcxx_assert(__is_valid_cmpexch_failure_order(__m2));
601
602 return __atomic_compare_exchange_n(&_M_i, &__i1, __i2, 0,
603 int(__m1), int(__m2));
604 }
605
606 _GLIBCXX_ALWAYS_INLINE bool
607 compare_exchange_strong(__int_type& __i1, __int_type __i2,
608 memory_order __m1,
609 memory_order __m2) volatile noexcept
610 {
611 __glibcxx_assert(__is_valid_cmpexch_failure_order(__m2));
612
613 return __atomic_compare_exchange_n(&_M_i, &__i1, __i2, 0,
614 int(__m1), int(__m2));
615 }
616
617 _GLIBCXX_ALWAYS_INLINE bool
618 compare_exchange_strong(__int_type& __i1, __int_type __i2,
619 memory_order __m = memory_order_seq_cst) noexcept
620 {
621 return compare_exchange_strong(__i1, __i2, __m,
622 __cmpexch_failure_order(__m));
623 }
624
625 _GLIBCXX_ALWAYS_INLINE bool
626 compare_exchange_strong(__int_type& __i1, __int_type __i2,
627 memory_order __m = memory_order_seq_cst) volatile noexcept
628 {
629 return compare_exchange_strong(__i1, __i2, __m,
630 __cmpexch_failure_order(__m));
631 }
632
633#if __glibcxx_atomic_wait
634 _GLIBCXX_ALWAYS_INLINE void
635 wait(__int_type __old,
636 memory_order __m = memory_order_seq_cst) const noexcept
637 {
638 std::__atomic_wait_address_v(&_M_i, __old,
639 [__m, this] { return this->load(__m); });
640 }
641
642 // TODO add const volatile overload
643
644 _GLIBCXX_ALWAYS_INLINE void
645 notify_one() noexcept
646 { std::__atomic_notify_address(&_M_i, false); }
647
648 // TODO add const volatile overload
649
650 _GLIBCXX_ALWAYS_INLINE void
651 notify_all() noexcept
652 { std::__atomic_notify_address(&_M_i, true); }
653
654 // TODO add const volatile overload
655#endif // __glibcxx_atomic_wait
656
657 _GLIBCXX_ALWAYS_INLINE __int_type
658 fetch_add(__int_type __i,
659 memory_order __m = memory_order_seq_cst) noexcept
660 { return __atomic_fetch_add(&_M_i, __i, int(__m)); }
661
662 _GLIBCXX_ALWAYS_INLINE __int_type
663 fetch_add(__int_type __i,
664 memory_order __m = memory_order_seq_cst) volatile noexcept
665 { return __atomic_fetch_add(&_M_i, __i, int(__m)); }
666
667 _GLIBCXX_ALWAYS_INLINE __int_type
668 fetch_sub(__int_type __i,
669 memory_order __m = memory_order_seq_cst) noexcept
670 { return __atomic_fetch_sub(&_M_i, __i, int(__m)); }
671
672 _GLIBCXX_ALWAYS_INLINE __int_type
673 fetch_sub(__int_type __i,
674 memory_order __m = memory_order_seq_cst) volatile noexcept
675 { return __atomic_fetch_sub(&_M_i, __i, int(__m)); }
676
677 _GLIBCXX_ALWAYS_INLINE __int_type
678 fetch_and(__int_type __i,
679 memory_order __m = memory_order_seq_cst) noexcept
680 { return __atomic_fetch_and(&_M_i, __i, int(__m)); }
681
682 _GLIBCXX_ALWAYS_INLINE __int_type
683 fetch_and(__int_type __i,
684 memory_order __m = memory_order_seq_cst) volatile noexcept
685 { return __atomic_fetch_and(&_M_i, __i, int(__m)); }
686
687 _GLIBCXX_ALWAYS_INLINE __int_type
688 fetch_or(__int_type __i,
689 memory_order __m = memory_order_seq_cst) noexcept
690 { return __atomic_fetch_or(&_M_i, __i, int(__m)); }
691
692 _GLIBCXX_ALWAYS_INLINE __int_type
693 fetch_or(__int_type __i,
694 memory_order __m = memory_order_seq_cst) volatile noexcept
695 { return __atomic_fetch_or(&_M_i, __i, int(__m)); }
696
697 _GLIBCXX_ALWAYS_INLINE __int_type
698 fetch_xor(__int_type __i,
699 memory_order __m = memory_order_seq_cst) noexcept
700 { return __atomic_fetch_xor(&_M_i, __i, int(__m)); }
701
702 _GLIBCXX_ALWAYS_INLINE __int_type
703 fetch_xor(__int_type __i,
704 memory_order __m = memory_order_seq_cst) volatile noexcept
705 { return __atomic_fetch_xor(&_M_i, __i, int(__m)); }
706
707#if __glibcxx_atomic_min_max
708 _GLIBCXX_ALWAYS_INLINE __int_type
709 fetch_min(__int_type __i,
710 memory_order __m = memory_order_seq_cst) noexcept
711 { return __atomic_impl::__fetch_min(&_M_i, __i, __m); }
712
713 _GLIBCXX_ALWAYS_INLINE __int_type
714 fetch_min(__int_type __i,
715 memory_order __m = memory_order_seq_cst) volatile noexcept
716 { return __atomic_impl::__fetch_min(&_M_i, __i, __m); }
717
718 _GLIBCXX_ALWAYS_INLINE __int_type
719 fetch_max(__int_type __i,
720 memory_order __m = memory_order_seq_cst) noexcept
721 { return __atomic_impl::__fetch_max(&_M_i, __i, __m); }
722
723 _GLIBCXX_ALWAYS_INLINE __int_type
724 fetch_max(__int_type __i,
725 memory_order __m = memory_order_seq_cst) volatile noexcept
726 { return __atomic_impl::__fetch_max(&_M_i, __i, __m); }
727#endif
728 };
729
730
731 /// Partial specialization for pointer types.
732 template<typename _PTp>
733 struct __atomic_base<_PTp*>
734 {
735 private:
736 typedef _PTp* __pointer_type;
737
738 __pointer_type _M_p _GLIBCXX20_INIT(nullptr);
739
740 static constexpr ptrdiff_t
741 _S_type_size(ptrdiff_t __d)
742 { return __d * sizeof(_PTp); }
743
744 public:
745 __atomic_base() noexcept = default;
746 ~__atomic_base() noexcept = default;
747 __atomic_base(const __atomic_base&) = delete;
748 __atomic_base& operator=(const __atomic_base&) = delete;
749 __atomic_base& operator=(const __atomic_base&) volatile = delete;
750
751 // Requires __pointer_type convertible to _M_p.
752 constexpr __atomic_base(__pointer_type __p) noexcept : _M_p (__p) { }
753
754 operator __pointer_type() const noexcept
755 { return load(); }
756
757 operator __pointer_type() const volatile noexcept
758 { return load(); }
759
760 __pointer_type
761 operator=(__pointer_type __p) noexcept
762 {
763 store(__p);
764 return __p;
765 }
766
767 __pointer_type
768 operator=(__pointer_type __p) volatile noexcept
769 {
770 store(__p);
771 return __p;
772 }
773
774 __pointer_type
775 operator++(int) noexcept
776 { return fetch_add(1); }
777
778 __pointer_type
779 operator++(int) volatile noexcept
780 { return fetch_add(1); }
781
782 __pointer_type
783 operator--(int) noexcept
784 { return fetch_sub(1); }
785
786 __pointer_type
787 operator--(int) volatile noexcept
788 { return fetch_sub(1); }
789
790 __pointer_type
791 operator++() noexcept
792 { return __atomic_add_fetch(&_M_p, _S_type_size(1),
793 int(memory_order_seq_cst)); }
794
795 __pointer_type
796 operator++() volatile noexcept
797 { return __atomic_add_fetch(&_M_p, _S_type_size(1),
798 int(memory_order_seq_cst)); }
799
800 __pointer_type
801 operator--() noexcept
802 { return __atomic_sub_fetch(&_M_p, _S_type_size(1),
803 int(memory_order_seq_cst)); }
804
805 __pointer_type
806 operator--() volatile noexcept
807 { return __atomic_sub_fetch(&_M_p, _S_type_size(1),
808 int(memory_order_seq_cst)); }
809
810 __pointer_type
811 operator+=(ptrdiff_t __d) noexcept
812 { return __atomic_add_fetch(&_M_p, _S_type_size(__d),
813 int(memory_order_seq_cst)); }
814
815 __pointer_type
816 operator+=(ptrdiff_t __d) volatile noexcept
817 { return __atomic_add_fetch(&_M_p, _S_type_size(__d),
818 int(memory_order_seq_cst)); }
819
820 __pointer_type
821 operator-=(ptrdiff_t __d) noexcept
822 { return __atomic_sub_fetch(&_M_p, _S_type_size(__d),
823 int(memory_order_seq_cst)); }
824
825 __pointer_type
826 operator-=(ptrdiff_t __d) volatile noexcept
827 { return __atomic_sub_fetch(&_M_p, _S_type_size(__d),
828 int(memory_order_seq_cst)); }
829
830 bool
831 is_lock_free() const noexcept
832 {
833 // Produce a fake, minimally aligned pointer.
834 return __atomic_is_lock_free(sizeof(_M_p),
835 reinterpret_cast<void *>(-__alignof(_M_p)));
836 }
837
838 bool
839 is_lock_free() const volatile noexcept
840 {
841 // Produce a fake, minimally aligned pointer.
842 return __atomic_is_lock_free(sizeof(_M_p),
843 reinterpret_cast<void *>(-__alignof(_M_p)));
844 }
845
846#pragma GCC diagnostic push
847#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
848 _GLIBCXX_ALWAYS_INLINE void
849 store(__pointer_type __p,
850 memory_order __m = memory_order_seq_cst) noexcept
851 {
852 memory_order __b __attribute__ ((__unused__))
853 = __m & __memory_order_mask;
854
855 __glibcxx_assert(__b != memory_order_acquire);
856 __glibcxx_assert(__b != memory_order_acq_rel);
857 __glibcxx_assert(__b != memory_order_consume);
858
859 __atomic_store_n(&_M_p, __p, int(__m));
860 }
861
862 _GLIBCXX_ALWAYS_INLINE void
863 store(__pointer_type __p,
864 memory_order __m = memory_order_seq_cst) volatile noexcept
865 {
866 memory_order __b __attribute__ ((__unused__))
867 = __m & __memory_order_mask;
868 __glibcxx_assert(__b != memory_order_acquire);
869 __glibcxx_assert(__b != memory_order_acq_rel);
870 __glibcxx_assert(__b != memory_order_consume);
871
872 __atomic_store_n(&_M_p, __p, int(__m));
873 }
874#pragma GCC diagnostic pop
875
876 _GLIBCXX_ALWAYS_INLINE __pointer_type
877 load(memory_order __m = memory_order_seq_cst) const noexcept
878 {
879 memory_order __b __attribute__ ((__unused__))
880 = __m & __memory_order_mask;
881 __glibcxx_assert(__b != memory_order_release);
882 __glibcxx_assert(__b != memory_order_acq_rel);
883
884 return __atomic_load_n(&_M_p, int(__m));
885 }
886
887 _GLIBCXX_ALWAYS_INLINE __pointer_type
888 load(memory_order __m = memory_order_seq_cst) const volatile noexcept
889 {
890 memory_order __b __attribute__ ((__unused__))
891 = __m & __memory_order_mask;
892 __glibcxx_assert(__b != memory_order_release);
893 __glibcxx_assert(__b != memory_order_acq_rel);
894
895 return __atomic_load_n(&_M_p, int(__m));
896 }
897
898 _GLIBCXX_ALWAYS_INLINE __pointer_type
899 exchange(__pointer_type __p,
900 memory_order __m = memory_order_seq_cst) noexcept
901 {
902 return __atomic_exchange_n(&_M_p, __p, int(__m));
903 }
904
905
906 _GLIBCXX_ALWAYS_INLINE __pointer_type
907 exchange(__pointer_type __p,
908 memory_order __m = memory_order_seq_cst) volatile noexcept
909 {
910 return __atomic_exchange_n(&_M_p, __p, int(__m));
911 }
912
913 _GLIBCXX_ALWAYS_INLINE bool
914 compare_exchange_weak(__pointer_type& __p1, __pointer_type __p2,
915 memory_order __m1,
916 memory_order __m2) noexcept
917 {
918 __glibcxx_assert(__is_valid_cmpexch_failure_order(__m2));
919
920 return __atomic_compare_exchange_n(&_M_p, &__p1, __p2, 1,
921 int(__m1), int(__m2));
922 }
923
924 _GLIBCXX_ALWAYS_INLINE bool
925 compare_exchange_weak(__pointer_type& __p1, __pointer_type __p2,
926 memory_order __m1,
927 memory_order __m2) volatile noexcept
928 {
929 __glibcxx_assert(__is_valid_cmpexch_failure_order(__m2));
930
931 return __atomic_compare_exchange_n(&_M_p, &__p1, __p2, 1,
932 int(__m1), int(__m2));
933 }
934
935 _GLIBCXX_ALWAYS_INLINE bool
936 compare_exchange_strong(__pointer_type& __p1, __pointer_type __p2,
937 memory_order __m1,
938 memory_order __m2) noexcept
939 {
940 __glibcxx_assert(__is_valid_cmpexch_failure_order(__m2));
941
942 return __atomic_compare_exchange_n(&_M_p, &__p1, __p2, 0,
943 int(__m1), int(__m2));
944 }
945
946 _GLIBCXX_ALWAYS_INLINE bool
947 compare_exchange_strong(__pointer_type& __p1, __pointer_type __p2,
948 memory_order __m1,
949 memory_order __m2) volatile noexcept
950 {
951 __glibcxx_assert(__is_valid_cmpexch_failure_order(__m2));
952
953 return __atomic_compare_exchange_n(&_M_p, &__p1, __p2, 0,
954 int(__m1), int(__m2));
955 }
956
957#if __glibcxx_atomic_wait
958 _GLIBCXX_ALWAYS_INLINE void
959 wait(__pointer_type __old,
960 memory_order __m = memory_order_seq_cst) const noexcept
961 {
962 std::__atomic_wait_address_v(&_M_p, __old,
963 [__m, this]
964 { return this->load(__m); });
965 }
966
967 // TODO add const volatile overload
968
969 _GLIBCXX_ALWAYS_INLINE void
970 notify_one() const noexcept
971 { std::__atomic_notify_address(&_M_p, false); }
972
973 // TODO add const volatile overload
974
975 _GLIBCXX_ALWAYS_INLINE void
976 notify_all() const noexcept
977 { std::__atomic_notify_address(&_M_p, true); }
978
979 // TODO add const volatile overload
980#endif // __glibcxx_atomic_wait
981
982 _GLIBCXX_ALWAYS_INLINE __pointer_type
983 fetch_add(ptrdiff_t __d,
984 memory_order __m = memory_order_seq_cst) noexcept
985 { return __atomic_fetch_add(&_M_p, _S_type_size(__d), int(__m)); }
986
987 _GLIBCXX_ALWAYS_INLINE __pointer_type
988 fetch_add(ptrdiff_t __d,
989 memory_order __m = memory_order_seq_cst) volatile noexcept
990 { return __atomic_fetch_add(&_M_p, _S_type_size(__d), int(__m)); }
991
992 _GLIBCXX_ALWAYS_INLINE __pointer_type
993 fetch_sub(ptrdiff_t __d,
994 memory_order __m = memory_order_seq_cst) noexcept
995 { return __atomic_fetch_sub(&_M_p, _S_type_size(__d), int(__m)); }
996
997 _GLIBCXX_ALWAYS_INLINE __pointer_type
998 fetch_sub(ptrdiff_t __d,
999 memory_order __m = memory_order_seq_cst) volatile noexcept
1000 { return __atomic_fetch_sub(&_M_p, _S_type_size(__d), int(__m)); }
1001
1002#if __glibcxx_atomic_min_max
1003 _GLIBCXX_ALWAYS_INLINE __pointer_type
1004 fetch_min(__pointer_type __p,
1005 memory_order __m = memory_order_seq_cst) noexcept
1006 { return __atomic_impl::__fetch_min(&_M_p, __p, __m); }
1007
1008 _GLIBCXX_ALWAYS_INLINE __pointer_type
1009 fetch_min(__pointer_type __p,
1010 memory_order __m = memory_order_seq_cst) volatile noexcept
1011 { return __atomic_impl::__fetch_min(&_M_p, __p, __m); }
1012
1013 _GLIBCXX_ALWAYS_INLINE __pointer_type
1014 fetch_max(__pointer_type __p,
1015 memory_order __m = memory_order_seq_cst) noexcept
1016 { return __atomic_impl::__fetch_max(&_M_p, __p, __m); }
1017
1018 _GLIBCXX_ALWAYS_INLINE __pointer_type
1019 fetch_max(__pointer_type __p,
1020 memory_order __m = memory_order_seq_cst) volatile noexcept
1021 { return __atomic_impl::__fetch_max(&_M_p, __p, __m); }
1022#endif
1023 };
1024
1025 namespace __atomic_impl
1026 {
1027 // Implementation details of atomic padding handling
1028
1029 template<typename _Tp>
1030 constexpr bool
1031 __maybe_has_padding()
1032 {
1033#if ! __has_builtin(__builtin_clear_padding)
1034 return false;
1035#elif __has_builtin(__has_unique_object_representations)
1036 return !__has_unique_object_representations(_Tp)
1037 && !is_same<_Tp, float>::value && !is_same<_Tp, double>::value;
1038#else
1039 return true;
1040#endif
1041 }
1042
1043#pragma GCC diagnostic push
1044#pragma GCC diagnostic ignored "-Wc++17-extensions"
1045
1046 template<typename _Tp>
1047 _GLIBCXX_ALWAYS_INLINE _GLIBCXX14_CONSTEXPR _Tp*
1048 __clear_padding(_Tp& __val) noexcept
1049 {
1050 auto* __ptr = std::__addressof(__val);
1051#if __has_builtin(__builtin_clear_padding)
1052 if constexpr (__atomic_impl::__maybe_has_padding<_Tp>())
1053 __builtin_clear_padding(__ptr);
1054#endif
1055 return __ptr;
1056 }
1057
1058 template<bool _AtomicRef = false, typename _Tp>
1059 _GLIBCXX_ALWAYS_INLINE bool
1060 __compare_exchange(_Tp& __val, _Val<_Tp>& __e, _Val<_Tp>& __i,
1061 bool __is_weak,
1062 memory_order __s, memory_order __f) noexcept
1063 {
1064 __glibcxx_assert(__is_valid_cmpexch_failure_order(__f));
1065
1066 using _Vp = _Val<_Tp>;
1067 _Tp* const __pval = std::__addressof(__val);
1068
1069 if constexpr (!__atomic_impl::__maybe_has_padding<_Vp>())
1070 {
1071 return __atomic_compare_exchange(__pval, std::__addressof(__e),
1072 std::__addressof(__i), __is_weak,
1073 int(__s), int(__f));
1074 }
1075 else if constexpr (!_AtomicRef) // std::atomic<T>
1076 {
1077 // Clear padding of the value we want to set:
1078 _Vp* const __pi = __atomic_impl::__clear_padding(__i);
1079 // Only allowed to modify __e on failure, so make a copy:
1080 _Vp __exp = __e;
1081 // Clear padding of the expected value:
1082 _Vp* const __pexp = __atomic_impl::__clear_padding(__exp);
1083
1084 // For std::atomic<T> we know that the contained value will already
1085 // have zeroed padding, so trivial memcmp semantics are OK.
1086 if (__atomic_compare_exchange(__pval, __pexp, __pi,
1087 __is_weak, int(__s), int(__f)))
1088 return true;
1089 // Value bits must be different, copy from __exp back to __e:
1090 __builtin_memcpy(std::__addressof(__e), __pexp, sizeof(_Vp));
1091 return false;
1092 }
1093 else // std::atomic_ref<T> where T has padding bits.
1094 {
1095 // Clear padding of the value we want to set:
1096 _Vp* const __pi = __atomic_impl::__clear_padding(__i);
1097
1098 // Only allowed to modify __e on failure, so make a copy:
1099 _Vp __exp = __e;
1100 // Optimistically assume that a previous store had zeroed padding
1101 // so that zeroing it in the expected value will match first time.
1102 _Vp* const __pexp = __atomic_impl::__clear_padding(__exp);
1103
1104 // compare_exchange is specified to compare value representations.
1105 // Need to check whether a failure is 'real' or just due to
1106 // differences in padding bits. This loop should run no more than
1107 // three times, because the worst case scenario is:
1108 // First CAS fails because the actual value has non-zero padding.
1109 // Second CAS fails because another thread stored the same value,
1110 // but now with padding cleared. Third CAS succeeds.
1111 // We will never need to loop a fourth time, because any value
1112 // written by another thread (whether via store, exchange or
1113 // compare_exchange) will have had its padding cleared.
1114 while (true)
1115 {
1116 // Copy of the expected value so we can clear its padding.
1117 _Vp __orig = __exp;
1118
1119 if (__atomic_compare_exchange(__pval, __pexp, __pi,
1120 __is_weak, int(__s), int(__f)))
1121 return true;
1122
1123 // Copy of the actual value so we can clear its padding.
1124 _Vp __curr = __exp;
1125
1126 // Compare value representations (i.e. ignoring padding).
1127 if (__builtin_memcmp(__atomic_impl::__clear_padding(__orig),
1128 __atomic_impl::__clear_padding(__curr),
1129 sizeof(_Vp)))
1130 {
1131 // Value representations compare unequal, real failure.
1132 __builtin_memcpy(std::__addressof(__e), __pexp,
1133 sizeof(_Vp));
1134 return false;
1135 }
1136 }
1137 }
1138 }
1139#pragma GCC diagnostic pop
1140 } // namespace __atomic_impl
1141
1142#if __cplusplus > 201703L
1143 // Implementation details of atomic_ref and atomic<floating-point>.
1144 namespace __atomic_impl
1145 {
1146 // Like _Val<T> above, but for difference_type arguments.
1147 template<typename _Tp>
1148 using _Diff = __conditional_t<is_pointer_v<_Tp>, ptrdiff_t, _Val<_Tp>>;
1149
1150 template<size_t _Size, size_t _Align>
1151 _GLIBCXX_ALWAYS_INLINE bool
1152 is_lock_free() noexcept
1153 {
1154 // Produce a fake, minimally aligned pointer.
1155 return __atomic_is_lock_free(_Size, reinterpret_cast<void *>(-_Align));
1156 }
1157
1158 template<typename _Tp>
1159 _GLIBCXX_ALWAYS_INLINE void
1160 store(_Tp* __ptr, _Val<_Tp> __t, memory_order __m) noexcept
1161 {
1162 __atomic_store(__ptr, __atomic_impl::__clear_padding(__t), int(__m));
1163 }
1164
1165 template<typename _Tp>
1166 _GLIBCXX_ALWAYS_INLINE _Val<_Tp>
1167 load(const _Tp* __ptr, memory_order __m) noexcept
1168 {
1169 alignas(_Tp) unsigned char __buf[sizeof(_Tp)];
1170 auto* __dest = reinterpret_cast<_Val<_Tp>*>(__buf);
1171 __atomic_load(__ptr, __dest, int(__m));
1172 return *__dest;
1173 }
1174
1175 template<typename _Tp>
1176 _GLIBCXX_ALWAYS_INLINE _Val<_Tp>
1177 exchange(_Tp* __ptr, _Val<_Tp> __desired, memory_order __m) noexcept
1178 {
1179 alignas(_Tp) unsigned char __buf[sizeof(_Tp)];
1180 auto* __dest = reinterpret_cast<_Val<_Tp>*>(__buf);
1181 __atomic_exchange(__ptr, __atomic_impl::__clear_padding(__desired),
1182 __dest, int(__m));
1183 return *__dest;
1184 }
1185
1186 template<bool _AtomicRef = false, typename _Tp>
1187 _GLIBCXX_ALWAYS_INLINE bool
1188 compare_exchange_weak(_Tp* __ptr, _Val<_Tp>& __expected,
1189 _Val<_Tp> __desired, memory_order __success,
1190 memory_order __failure) noexcept
1191 {
1192 return __atomic_impl::__compare_exchange<_AtomicRef>(
1193 *__ptr, __expected, __desired, true, __success, __failure);
1194 }
1195
1196 template<bool _AtomicRef = false, typename _Tp>
1197 _GLIBCXX_ALWAYS_INLINE bool
1198 compare_exchange_strong(_Tp* __ptr, _Val<_Tp>& __expected,
1199 _Val<_Tp> __desired, memory_order __success,
1200 memory_order __failure) noexcept
1201 {
1202 return __atomic_impl::__compare_exchange<_AtomicRef>(
1203 *__ptr, __expected, __desired, false, __success, __failure);
1204 }
1205
1206#if __glibcxx_atomic_wait
1207 template<typename _Tp>
1208 _GLIBCXX_ALWAYS_INLINE void
1209 wait(const _Tp* __ptr, _Val<_Tp> __old,
1210 memory_order __m = memory_order_seq_cst) noexcept
1211 {
1212 std::__atomic_wait_address_v(__ptr, __old,
1213 [__ptr, __m]() { return __atomic_impl::load(__ptr, __m); });
1214 }
1215
1216 // TODO add const volatile overload
1217
1218 template<typename _Tp>
1219 _GLIBCXX_ALWAYS_INLINE void
1220 notify_one(const _Tp* __ptr) noexcept
1221 { std::__atomic_notify_address(__ptr, false); }
1222
1223 // TODO add const volatile overload
1224
1225 template<typename _Tp>
1226 _GLIBCXX_ALWAYS_INLINE void
1227 notify_all(const _Tp* __ptr) noexcept
1228 { std::__atomic_notify_address(__ptr, true); }
1229
1230 // TODO add const volatile overload
1231#endif // __glibcxx_atomic_wait
1232
1233 template<typename _Tp>
1234 _GLIBCXX_ALWAYS_INLINE _Tp
1235 fetch_add(_Tp* __ptr, _Diff<_Tp> __i, memory_order __m) noexcept
1236 { return __atomic_fetch_add(__ptr, __i, int(__m)); }
1237
1238 template<typename _Tp>
1239 _GLIBCXX_ALWAYS_INLINE _Tp
1240 fetch_sub(_Tp* __ptr, _Diff<_Tp> __i, memory_order __m) noexcept
1241 { return __atomic_fetch_sub(__ptr, __i, int(__m)); }
1242
1243 template<typename _Tp>
1244 _GLIBCXX_ALWAYS_INLINE _Tp
1245 fetch_and(_Tp* __ptr, _Val<_Tp> __i, memory_order __m) noexcept
1246 { return __atomic_fetch_and(__ptr, __i, int(__m)); }
1247
1248 template<typename _Tp>
1249 _GLIBCXX_ALWAYS_INLINE _Tp
1250 fetch_or(_Tp* __ptr, _Val<_Tp> __i, memory_order __m) noexcept
1251 { return __atomic_fetch_or(__ptr, __i, int(__m)); }
1252
1253 template<typename _Tp>
1254 _GLIBCXX_ALWAYS_INLINE _Tp
1255 fetch_xor(_Tp* __ptr, _Val<_Tp> __i, memory_order __m) noexcept
1256 { return __atomic_fetch_xor(__ptr, __i, int(__m)); }
1257
1258 template<typename _Tp>
1259 _GLIBCXX_ALWAYS_INLINE _Tp
1260 __add_fetch(_Tp* __ptr, _Diff<_Tp> __i) noexcept
1261 { return __atomic_add_fetch(__ptr, __i, __ATOMIC_SEQ_CST); }
1262
1263 template<typename _Tp>
1264 _GLIBCXX_ALWAYS_INLINE _Tp
1265 __sub_fetch(_Tp* __ptr, _Diff<_Tp> __i) noexcept
1266 { return __atomic_sub_fetch(__ptr, __i, __ATOMIC_SEQ_CST); }
1267
1268 template<typename _Tp>
1269 _GLIBCXX_ALWAYS_INLINE _Tp
1270 __and_fetch(_Tp* __ptr, _Val<_Tp> __i) noexcept
1271 { return __atomic_and_fetch(__ptr, __i, __ATOMIC_SEQ_CST); }
1272
1273 template<typename _Tp>
1274 _GLIBCXX_ALWAYS_INLINE _Tp
1275 __or_fetch(_Tp* __ptr, _Val<_Tp> __i) noexcept
1276 { return __atomic_or_fetch(__ptr, __i, __ATOMIC_SEQ_CST); }
1277
1278 template<typename _Tp>
1279 _GLIBCXX_ALWAYS_INLINE _Tp
1280 __xor_fetch(_Tp* __ptr, _Val<_Tp> __i) noexcept
1281 { return __atomic_xor_fetch(__ptr, __i, __ATOMIC_SEQ_CST); }
1282
1283 template<typename _Tp>
1284 concept __atomic_fetch_addable
1285 = requires (_Tp __t) { __atomic_fetch_add(&__t, __t, 0); };
1286
1287 template<typename _Tp>
1288 _Tp
1289 __fetch_add_flt(_Tp* __ptr, _Val<_Tp> __i, memory_order __m) noexcept
1290 {
1291 if constexpr (__atomic_fetch_addable<_Tp>)
1292 return __atomic_fetch_add(__ptr, __i, int(__m));
1293 else
1294 {
1295 _Val<_Tp> __oldval = load (__ptr, memory_order_relaxed);
1296 _Val<_Tp> __newval = __oldval + __i;
1297 while (!compare_exchange_weak (__ptr, __oldval, __newval, __m,
1298 memory_order_relaxed))
1299 __newval = __oldval + __i;
1300 return __oldval;
1301 }
1302 }
1303
1304 template<typename _Tp>
1305 concept __atomic_fetch_subtractable
1306 = requires (_Tp __t) { __atomic_fetch_sub(&__t, __t, 0); };
1307
1308 template<typename _Tp>
1309 _Tp
1310 __fetch_sub_flt(_Tp* __ptr, _Val<_Tp> __i, memory_order __m) noexcept
1311 {
1312 if constexpr (__atomic_fetch_subtractable<_Tp>)
1313 return __atomic_fetch_sub(__ptr, __i, int(__m));
1314 else
1315 {
1316 _Val<_Tp> __oldval = load (__ptr, memory_order_relaxed);
1317 _Val<_Tp> __newval = __oldval - __i;
1318 while (!compare_exchange_weak (__ptr, __oldval, __newval, __m,
1319 memory_order_relaxed))
1320 __newval = __oldval - __i;
1321 return __oldval;
1322 }
1323 }
1324
1325 template<typename _Tp>
1326 concept __atomic_add_fetchable
1327 = requires (_Tp __t) { __atomic_add_fetch(&__t, __t, 0); };
1328
1329 template<typename _Tp>
1330 _Tp
1331 __add_fetch_flt(_Tp* __ptr, _Val<_Tp> __i) noexcept
1332 {
1333 if constexpr (__atomic_add_fetchable<_Tp>)
1334 return __atomic_add_fetch(__ptr, __i, __ATOMIC_SEQ_CST);
1335 else
1336 {
1337 _Val<_Tp> __oldval = load (__ptr, memory_order_relaxed);
1338 _Val<_Tp> __newval = __oldval + __i;
1339 while (!compare_exchange_weak (__ptr, __oldval, __newval,
1340 memory_order_seq_cst,
1341 memory_order_relaxed))
1342 __newval = __oldval + __i;
1343 return __newval;
1344 }
1345 }
1346
1347 template<typename _Tp>
1348 concept __atomic_sub_fetchable
1349 = requires (_Tp __t) { __atomic_sub_fetch(&__t, __t, 0); };
1350
1351 template<typename _Tp>
1352 _Tp
1353 __sub_fetch_flt(_Tp* __ptr, _Val<_Tp> __i) noexcept
1354 {
1355 if constexpr (__atomic_sub_fetchable<_Tp>)
1356 return __atomic_sub_fetch(__ptr, __i, __ATOMIC_SEQ_CST);
1357 else
1358 {
1359 _Val<_Tp> __oldval = load (__ptr, memory_order_relaxed);
1360 _Val<_Tp> __newval = __oldval - __i;
1361 while (!compare_exchange_weak (__ptr, __oldval, __newval,
1362 memory_order_seq_cst,
1363 memory_order_relaxed))
1364 __newval = __oldval - __i;
1365 return __newval;
1366 }
1367 }
1368
1369#if __glibcxx_atomic_min_max
1370 template<typename _Tp>
1371 concept __atomic_fetch_minmaxable
1372 = requires (_Tp __t) {
1373 __atomic_fetch_min(&__t, __t, 0);
1374 __atomic_fetch_max(&__t, __t, 0);
1375 };
1376
1377 template<typename _Tp>
1378 _Tp
1379 __fetch_min(_Tp* __ptr, _Val<_Tp> __i, memory_order __m) noexcept
1380 {
1381 if constexpr (__atomic_fetch_minmaxable<_Tp>)
1382 return __atomic_fetch_min(__ptr, __i, int(__m));
1383 else
1384 {
1385 _Val<_Tp> __oldval = load (__ptr, memory_order_relaxed);
1386 _Val<_Tp> __newval = __oldval < __i ? __oldval : __i;
1387 while (!compare_exchange_weak (__ptr, __oldval, __newval, __m,
1388 memory_order_relaxed))
1389 __newval = __oldval < __i ? __oldval : __i;
1390 return __oldval;
1391 }
1392 }
1393
1394 template<typename _Tp>
1395 _Tp
1396 __fetch_max(_Tp* __ptr, _Val<_Tp> __i, memory_order __m) noexcept
1397 {
1398 if constexpr (__atomic_fetch_minmaxable<_Tp>)
1399 return __atomic_fetch_max(__ptr, __i, int(__m));
1400 else
1401 {
1402 _Val<_Tp> __oldval = load (__ptr, memory_order_relaxed);
1403 _Val<_Tp> __newval = __oldval > __i ? __oldval : __i;
1404 while (!compare_exchange_weak (__ptr, __oldval, __newval, __m,
1405 memory_order_relaxed))
1406 __newval = __oldval > __i ? __oldval : __i;
1407 return __oldval;
1408 }
1409 }
1410#endif
1411 } // namespace __atomic_impl
1412
1413 // base class for atomic<floating-point-type>
1414 template<typename _Fp>
1415 struct __atomic_float
1416 {
1417 static_assert(is_floating_point_v<_Fp>);
1418
1419 static constexpr size_t _S_alignment = __alignof__(_Fp);
1420
1421 public:
1422 using value_type = _Fp;
1423 using difference_type = value_type;
1424
1425 static constexpr bool is_always_lock_free
1426 = __atomic_always_lock_free(sizeof(_Fp), 0);
1427
1428 __atomic_float() = default;
1429
1430 constexpr
1431 __atomic_float(_Fp __t) : _M_fp(__t)
1432 {
1433 if (!std::__is_constant_evaluated())
1434 __atomic_impl::__clear_padding(_M_fp);
1435 }
1436
1437 __atomic_float(const __atomic_float&) = delete;
1438 __atomic_float& operator=(const __atomic_float&) = delete;
1439 __atomic_float& operator=(const __atomic_float&) volatile = delete;
1440
1441 _Fp
1442 operator=(_Fp __t) volatile noexcept
1443 {
1444 this->store(__t);
1445 return __t;
1446 }
1447
1448 _Fp
1449 operator=(_Fp __t) noexcept
1450 {
1451 this->store(__t);
1452 return __t;
1453 }
1454
1455 bool
1456 is_lock_free() const volatile noexcept
1457 { return __atomic_impl::is_lock_free<sizeof(_Fp), _S_alignment>(); }
1458
1459 bool
1460 is_lock_free() const noexcept
1461 { return __atomic_impl::is_lock_free<sizeof(_Fp), _S_alignment>(); }
1462
1463 void
1464 store(_Fp __t, memory_order __m = memory_order_seq_cst) volatile noexcept
1465 { __atomic_impl::store(&_M_fp, __t, __m); }
1466
1467 void
1468 store(_Fp __t, memory_order __m = memory_order_seq_cst) noexcept
1469 { __atomic_impl::store(&_M_fp, __t, __m); }
1470
1471 _Fp
1472 load(memory_order __m = memory_order_seq_cst) const volatile noexcept
1473 { return __atomic_impl::load(&_M_fp, __m); }
1474
1475 _Fp
1476 load(memory_order __m = memory_order_seq_cst) const noexcept
1477 { return __atomic_impl::load(&_M_fp, __m); }
1478
1479 operator _Fp() const volatile noexcept { return this->load(); }
1480 operator _Fp() const noexcept { return this->load(); }
1481
1482 _Fp
1483 exchange(_Fp __desired,
1484 memory_order __m = memory_order_seq_cst) volatile noexcept
1485 { return __atomic_impl::exchange(&_M_fp, __desired, __m); }
1486
1487 _Fp
1488 exchange(_Fp __desired,
1489 memory_order __m = memory_order_seq_cst) noexcept
1490 { return __atomic_impl::exchange(&_M_fp, __desired, __m); }
1491
1492 bool
1493 compare_exchange_weak(_Fp& __expected, _Fp __desired,
1494 memory_order __success,
1495 memory_order __failure) noexcept
1496 {
1497 return __atomic_impl::compare_exchange_weak(&_M_fp,
1498 __expected, __desired,
1499 __success, __failure);
1500 }
1501
1502 bool
1503 compare_exchange_weak(_Fp& __expected, _Fp __desired,
1504 memory_order __success,
1505 memory_order __failure) volatile noexcept
1506 {
1507 return __atomic_impl::compare_exchange_weak(&_M_fp,
1508 __expected, __desired,
1509 __success, __failure);
1510 }
1511
1512 bool
1513 compare_exchange_strong(_Fp& __expected, _Fp __desired,
1514 memory_order __success,
1515 memory_order __failure) noexcept
1516 {
1517 return __atomic_impl::compare_exchange_strong(&_M_fp,
1518 __expected, __desired,
1519 __success, __failure);
1520 }
1521
1522 bool
1523 compare_exchange_strong(_Fp& __expected, _Fp __desired,
1524 memory_order __success,
1525 memory_order __failure) volatile noexcept
1526 {
1527 return __atomic_impl::compare_exchange_strong(&_M_fp,
1528 __expected, __desired,
1529 __success, __failure);
1530 }
1531
1532 bool
1533 compare_exchange_weak(_Fp& __expected, _Fp __desired,
1534 memory_order __order = memory_order_seq_cst)
1535 noexcept
1536 {
1537 return compare_exchange_weak(__expected, __desired, __order,
1538 __cmpexch_failure_order(__order));
1539 }
1540
1541 bool
1542 compare_exchange_weak(_Fp& __expected, _Fp __desired,
1543 memory_order __order = memory_order_seq_cst)
1544 volatile noexcept
1545 {
1546 return compare_exchange_weak(__expected, __desired, __order,
1547 __cmpexch_failure_order(__order));
1548 }
1549
1550 bool
1551 compare_exchange_strong(_Fp& __expected, _Fp __desired,
1552 memory_order __order = memory_order_seq_cst)
1553 noexcept
1554 {
1555 return compare_exchange_strong(__expected, __desired, __order,
1556 __cmpexch_failure_order(__order));
1557 }
1558
1559 bool
1560 compare_exchange_strong(_Fp& __expected, _Fp __desired,
1561 memory_order __order = memory_order_seq_cst)
1562 volatile noexcept
1563 {
1564 return compare_exchange_strong(__expected, __desired, __order,
1565 __cmpexch_failure_order(__order));
1566 }
1567
1568#if __glibcxx_atomic_wait
1569 _GLIBCXX_ALWAYS_INLINE void
1570 wait(_Fp __old, memory_order __m = memory_order_seq_cst) const noexcept
1571 { __atomic_impl::wait(&_M_fp, __old, __m); }
1572
1573 // TODO add const volatile overload
1574
1575 _GLIBCXX_ALWAYS_INLINE void
1576 notify_one() const noexcept
1577 { __atomic_impl::notify_one(&_M_fp); }
1578
1579 // TODO add const volatile overload
1580
1581 _GLIBCXX_ALWAYS_INLINE void
1582 notify_all() const noexcept
1583 { __atomic_impl::notify_all(&_M_fp); }
1584
1585 // TODO add const volatile overload
1586#endif // __glibcxx_atomic_wait
1587
1588 value_type
1589 fetch_add(value_type __i,
1590 memory_order __m = memory_order_seq_cst) noexcept
1591 { return __atomic_impl::__fetch_add_flt(&_M_fp, __i, __m); }
1592
1593 value_type
1594 fetch_add(value_type __i,
1595 memory_order __m = memory_order_seq_cst) volatile noexcept
1596 { return __atomic_impl::__fetch_add_flt(&_M_fp, __i, __m); }
1597
1598 value_type
1599 fetch_sub(value_type __i,
1600 memory_order __m = memory_order_seq_cst) noexcept
1601 { return __atomic_impl::__fetch_sub_flt(&_M_fp, __i, __m); }
1602
1603 value_type
1604 fetch_sub(value_type __i,
1605 memory_order __m = memory_order_seq_cst) volatile noexcept
1606 { return __atomic_impl::__fetch_sub_flt(&_M_fp, __i, __m); }
1607
1608#if __glibcxx_atomic_min_max
1609 value_type
1610 fetch_min(value_type __i,
1611 memory_order __m = memory_order_seq_cst) noexcept
1612 { return __atomic_impl::__fetch_min(&_M_fp, __i, __m); }
1613
1614 value_type
1615 fetch_min(value_type __i,
1616 memory_order __m = memory_order_seq_cst) volatile noexcept
1617 { return __atomic_impl::__fetch_min(&_M_fp, __i, __m); }
1618
1619 value_type
1620 fetch_max(value_type __i,
1621 memory_order __m = memory_order_seq_cst) noexcept
1622 { return __atomic_impl::__fetch_max(&_M_fp, __i, __m); }
1623
1624 value_type
1625 fetch_max(value_type __i,
1626 memory_order __m = memory_order_seq_cst) volatile noexcept
1627 { return __atomic_impl::__fetch_max(&_M_fp, __i, __m); }
1628#endif
1629
1630 value_type
1631 operator+=(value_type __i) noexcept
1632 { return __atomic_impl::__add_fetch_flt(&_M_fp, __i); }
1633
1634 value_type
1635 operator+=(value_type __i) volatile noexcept
1636 { return __atomic_impl::__add_fetch_flt(&_M_fp, __i); }
1637
1638 value_type
1639 operator-=(value_type __i) noexcept
1640 { return __atomic_impl::__sub_fetch_flt(&_M_fp, __i); }
1641
1642 value_type
1643 operator-=(value_type __i) volatile noexcept
1644 { return __atomic_impl::__sub_fetch_flt(&_M_fp, __i); }
1645
1646 private:
1647 alignas(_S_alignment) _Fp _M_fp _GLIBCXX20_INIT(0);
1648 };
1649#undef _GLIBCXX20_INIT
1650
1651 // __atomic_ref_base<const _Tp> provides the common APIs for const and
1652 // non-const types,
1653 // __atomic_ref_base<_Tp> inherits from __atomic_ref_base<const _Tp>,
1654 // and provides the common APIs implementing constraints in [atomic.ref].
1655 // __atomic_ref<_Tp> inherits from __atomic_ref_base<_Tp> (const or non-const)
1656 // adds type-specific mutating APIs.
1657 // atomic_ref inherits from __atomic_ref;
1658
1659 template<typename _Tp>
1660 struct __atomic_ref_base;
1661
1662 template<typename _Tp>
1663 struct __atomic_ref_base<const _Tp>
1664 {
1665 private:
1666 using _Vt = remove_cv_t<_Tp>;
1667 using _Address_return_t = __conditional_t<is_volatile_v<_Tp>,
1668 const volatile void*, const void*>;
1669
1670 static consteval bool
1671 _S_is_always_lock_free()
1672 {
1673 if constexpr (is_pointer_v<_Vt>)
1674 return ATOMIC_POINTER_LOCK_FREE == 2;
1675 else
1676 return __atomic_always_lock_free(sizeof(_Vt), 0);
1677 }
1678
1679 static consteval int
1680 _S_required_alignment()
1681 {
1682 if constexpr (is_floating_point_v<_Vt> || is_pointer_v<_Vt>)
1683 return __alignof__(_Vt);
1684 else if constexpr ((sizeof(_Vt) & (sizeof(_Vt) - 1)) || sizeof(_Vt) > 16)
1685 return alignof(_Vt);
1686 else
1687 // 1/2/4/8/16-byte types, including integral types,
1688 // must be aligned to at least their size.
1689 return (sizeof(_Vt) > alignof(_Vt)) ? sizeof(_Vt) : alignof(_Vt);
1690 }
1691
1692 public:
1693 using value_type = _Vt;
1694 static_assert(is_trivially_copyable_v<value_type>);
1695
1696 static constexpr bool is_always_lock_free = _S_is_always_lock_free();
1697 static_assert(is_always_lock_free || !is_volatile_v<_Tp>,
1698 "atomic operations on volatile T must be lock-free");
1699
1700 static constexpr size_t required_alignment = _S_required_alignment();
1701
1702 __atomic_ref_base() = delete;
1703 __atomic_ref_base& operator=(const __atomic_ref_base&) = delete;
1704
1705 explicit
1706 __atomic_ref_base(const _Tp* __ptr) noexcept
1707 : _M_ptr(const_cast<_Tp*>(__ptr))
1708 { }
1709
1710 __atomic_ref_base(const __atomic_ref_base&) noexcept = default;
1711
1712 operator value_type() const noexcept { return this->load(); }
1713
1714 bool
1715 is_lock_free() const noexcept
1716 { return __atomic_impl::is_lock_free<sizeof(_Tp), required_alignment>(); }
1717
1718 value_type
1719 load(memory_order __m = memory_order_seq_cst) const noexcept
1720 { return __atomic_impl::load(_M_ptr, __m); }
1721
1722#if __glibcxx_atomic_wait
1723 _GLIBCXX_ALWAYS_INLINE void
1724 wait(value_type __old, memory_order __m = memory_order_seq_cst) const noexcept
1725 {
1726 // TODO remove when volatile is supported
1727 static_assert(!is_volatile_v<_Tp>,
1728 "atomic waits on volatile are not supported");
1729 __atomic_impl::wait(_M_ptr, __old, __m);
1730 }
1731#endif // __glibcxx_atomic_wait
1732
1733#if __glibcxx_atomic_ref >= 202603L
1734 _GLIBCXX_ALWAYS_INLINE constexpr _Address_return_t
1735 address() const noexcept
1736 { return _M_ptr; }
1737#endif // __glibcxx_atomic_ref >= 202411L
1738
1739 protected:
1740 _Tp* _M_ptr;
1741 };
1742
1743 template<typename _Tp>
1744 struct __atomic_ref_base
1745 : __atomic_ref_base<const _Tp>
1746 {
1747 using _Address_return_t = __conditional_t<is_volatile_v<_Tp>,
1748 volatile void*, void*>;
1749
1750 public:
1751 using value_type = typename __atomic_ref_base<const _Tp>::value_type;
1752
1753 explicit
1754 __atomic_ref_base(_Tp* __ptr) noexcept
1755 : __atomic_ref_base<const _Tp>(__ptr)
1756 { }
1757
1758 value_type
1759 operator=(value_type __t) const noexcept
1760 {
1761 this->store(__t);
1762 return __t;
1763 }
1764
1765 void
1766 store(value_type __t, memory_order __m = memory_order_seq_cst) const noexcept
1767 { __atomic_impl::store(this->_M_ptr, __t, __m); }
1768
1769 value_type
1770 exchange(value_type __desired, memory_order __m = memory_order_seq_cst)
1771 const noexcept
1772 { return __atomic_impl::exchange(this->_M_ptr, __desired, __m); }
1773
1774 bool
1775 compare_exchange_weak(value_type& __expected, value_type __desired,
1776 memory_order __success,
1777 memory_order __failure) const noexcept
1778 {
1779 return __atomic_impl::compare_exchange_weak<true>(
1780 this->_M_ptr, __expected, __desired, __success, __failure);
1781 }
1782
1783 bool
1784 compare_exchange_strong(value_type& __expected, value_type __desired,
1785 memory_order __success,
1786 memory_order __failure) const noexcept
1787 {
1788 return __atomic_impl::compare_exchange_strong<true>(
1789 this->_M_ptr, __expected, __desired, __success, __failure);
1790 }
1791
1792 bool
1793 compare_exchange_weak(value_type& __expected, value_type __desired,
1794 memory_order __order = memory_order_seq_cst)
1795 const noexcept
1796 {
1797 return compare_exchange_weak(__expected, __desired, __order,
1798 __cmpexch_failure_order(__order));
1799 }
1800
1801 bool
1802 compare_exchange_strong(value_type& __expected, value_type __desired,
1803 memory_order __order = memory_order_seq_cst)
1804 const noexcept
1805 {
1806 return compare_exchange_strong(__expected, __desired, __order,
1807 __cmpexch_failure_order(__order));
1808 }
1809
1810#if __glibcxx_atomic_wait
1811 _GLIBCXX_ALWAYS_INLINE void
1812 notify_one() const noexcept
1813 {
1814 // TODO remove when volatile is supported
1815 static_assert(!is_volatile_v<_Tp>,
1816 "atomic waits on volatile are not supported");
1817 __atomic_impl::notify_one(this->_M_ptr);
1818 }
1819
1820 _GLIBCXX_ALWAYS_INLINE void
1821 notify_all() const noexcept
1822 {
1823 // TODO remove when volatile is supported
1824 static_assert(!is_volatile_v<_Tp>,
1825 "atomic waits on volatile are not supported");
1826 __atomic_impl::notify_all(this->_M_ptr);
1827 }
1828#endif // __glibcxx_atomic_wait
1829
1830#if __glibcxx_atomic_ref >= 202603L
1831 _GLIBCXX_ALWAYS_INLINE constexpr _Address_return_t
1832 address() const noexcept
1833 { return this->_M_ptr; }
1834#endif // __glibcxx_atomic_ref >= 202411L
1835 };
1836
1837 template<typename _Tp,
1838 bool = is_integral_v<_Tp> && !is_same_v<remove_cv_t<_Tp>, bool>,
1839 bool = is_floating_point_v<_Tp>,
1840 bool = is_pointer_v<_Tp>>
1841 struct __atomic_ref;
1842
1843 // base class for non-integral, non-floating-point, non-pointer types
1844 template<typename _Tp>
1845 struct __atomic_ref<_Tp, false, false, false>
1846 : __atomic_ref_base<_Tp>
1847 {
1848 using __atomic_ref_base<_Tp>::__atomic_ref_base;
1849 using __atomic_ref_base<_Tp>::operator=;
1850 };
1851
1852 template<typename _Tp>
1853 struct __atomic_ref<const _Tp, false, false, false>
1854 : __atomic_ref_base<const _Tp>
1855 {
1856 using __atomic_ref_base<const _Tp>::__atomic_ref_base;
1857 };
1858
1859 // base class for atomic_ref<integral-type>
1860 template<typename _Tp>
1861 struct __atomic_ref<_Tp, true, false, false>
1862 : __atomic_ref_base<_Tp>
1863 {
1864 using value_type = typename __atomic_ref_base<_Tp>::value_type;
1865 using difference_type = value_type;
1866
1867 using __atomic_ref_base<_Tp>::__atomic_ref_base;
1868 using __atomic_ref_base<_Tp>::operator=;
1869
1870 value_type
1871 fetch_add(value_type __i,
1872 memory_order __m = memory_order_seq_cst) const noexcept
1873 { return __atomic_impl::fetch_add(this->_M_ptr, __i, __m); }
1874
1875 value_type
1876 fetch_sub(value_type __i,
1877 memory_order __m = memory_order_seq_cst) const noexcept
1878 { return __atomic_impl::fetch_sub(this->_M_ptr, __i, __m); }
1879
1880 value_type
1881 fetch_and(value_type __i,
1882 memory_order __m = memory_order_seq_cst) const noexcept
1883 { return __atomic_impl::fetch_and(this->_M_ptr, __i, __m); }
1884
1885 value_type
1886 fetch_or(value_type __i,
1887 memory_order __m = memory_order_seq_cst) const noexcept
1888 { return __atomic_impl::fetch_or(this->_M_ptr, __i, __m); }
1889
1890 value_type
1891 fetch_xor(value_type __i,
1892 memory_order __m = memory_order_seq_cst) const noexcept
1893 { return __atomic_impl::fetch_xor(this->_M_ptr, __i, __m); }
1894
1895#if __glibcxx_atomic_min_max
1896 value_type
1897 fetch_min(value_type __i,
1898 memory_order __m = memory_order_seq_cst) const noexcept
1899 { return __atomic_impl::__fetch_min(this->_M_ptr, __i, __m); }
1900
1901 value_type
1902 fetch_max(value_type __i,
1903 memory_order __m = memory_order_seq_cst) const noexcept
1904 { return __atomic_impl::__fetch_max(this->_M_ptr, __i, __m); }
1905#endif
1906
1907 _GLIBCXX_ALWAYS_INLINE value_type
1908 operator++(int) const noexcept
1909 { return fetch_add(1); }
1910
1911 _GLIBCXX_ALWAYS_INLINE value_type
1912 operator--(int) const noexcept
1913 { return fetch_sub(1); }
1914
1915 value_type
1916 operator++() const noexcept
1917 { return __atomic_impl::__add_fetch(this->_M_ptr, value_type(1)); }
1918
1919 value_type
1920 operator--() const noexcept
1921 { return __atomic_impl::__sub_fetch(this->_M_ptr, value_type(1)); }
1922
1923 value_type
1924 operator+=(value_type __i) const noexcept
1925 { return __atomic_impl::__add_fetch(this->_M_ptr, __i); }
1926
1927 value_type
1928 operator-=(value_type __i) const noexcept
1929 { return __atomic_impl::__sub_fetch(this->_M_ptr, __i); }
1930
1931 value_type
1932 operator&=(value_type __i) const noexcept
1933 { return __atomic_impl::__and_fetch(this->_M_ptr, __i); }
1934
1935 value_type
1936 operator|=(value_type __i) const noexcept
1937 { return __atomic_impl::__or_fetch(this->_M_ptr, __i); }
1938
1939 value_type
1940 operator^=(value_type __i) const noexcept
1941 { return __atomic_impl::__xor_fetch(this->_M_ptr, __i); }
1942 };
1943
1944 template<typename _Tp>
1945 struct __atomic_ref<const _Tp, true, false, false>
1946 : __atomic_ref_base<const _Tp>
1947 {
1948 using difference_type = typename __atomic_ref_base<const _Tp>::value_type;
1949 using __atomic_ref_base<const _Tp>::__atomic_ref_base;
1950 };
1951
1952 // base class for atomic_ref<floating-point-type>
1953 template<typename _Fp>
1954 struct __atomic_ref<_Fp, false, true, false>
1955 : __atomic_ref_base<_Fp>
1956 {
1957 using value_type = typename __atomic_ref_base<_Fp>::value_type;
1958 using difference_type = value_type;
1959
1960 using __atomic_ref_base<_Fp>::__atomic_ref_base;
1961 using __atomic_ref_base<_Fp>::operator=;
1962
1963 value_type
1964 fetch_add(value_type __i,
1965 memory_order __m = memory_order_seq_cst) const noexcept
1966 { return __atomic_impl::__fetch_add_flt(this->_M_ptr, __i, __m); }
1967
1968 value_type
1969 fetch_sub(value_type __i,
1970 memory_order __m = memory_order_seq_cst) const noexcept
1971 { return __atomic_impl::__fetch_sub_flt(this->_M_ptr, __i, __m); }
1972
1973#if __glibcxx_atomic_min_max
1974 value_type
1975 fetch_min(value_type __i,
1976 memory_order __m = memory_order_seq_cst) const noexcept
1977 { return __atomic_impl::__fetch_min(this->_M_ptr, __i, __m); }
1978
1979 value_type
1980 fetch_max(value_type __i,
1981 memory_order __m = memory_order_seq_cst) const noexcept
1982 { return __atomic_impl::__fetch_max(this->_M_ptr, __i, __m); }
1983#endif
1984
1985 value_type
1986 operator+=(value_type __i) const noexcept
1987 { return __atomic_impl::__add_fetch_flt(this->_M_ptr, __i); }
1988
1989 value_type
1990 operator-=(value_type __i) const noexcept
1991 { return __atomic_impl::__sub_fetch_flt(this->_M_ptr, __i); }
1992 };
1993
1994 template<typename _Fp>
1995 struct __atomic_ref<const _Fp, false, true, false>
1996 : __atomic_ref_base<const _Fp>
1997 {
1998 using difference_type = typename __atomic_ref_base<const _Fp>::value_type;
1999 using __atomic_ref_base<const _Fp>::__atomic_ref_base;
2000 };
2001
2002 // base class for atomic_ref<pointer-type>
2003 template<typename _Pt>
2004 struct __atomic_ref<_Pt, false, false, true>
2005 : __atomic_ref_base<_Pt>
2006 {
2007 using value_type = typename __atomic_ref_base<_Pt>::value_type;
2008 using difference_type = ptrdiff_t;
2009
2010 using __atomic_ref_base<_Pt>::__atomic_ref_base;
2011 using __atomic_ref_base<_Pt>::operator=;
2012 _GLIBCXX_ALWAYS_INLINE value_type
2013 fetch_add(difference_type __d,
2014 memory_order __m = memory_order_seq_cst) const noexcept
2015 { return __atomic_impl::fetch_add(this->_M_ptr, _S_type_size(__d), __m); }
2016
2017 _GLIBCXX_ALWAYS_INLINE value_type
2018 fetch_sub(difference_type __d,
2019 memory_order __m = memory_order_seq_cst) const noexcept
2020 { return __atomic_impl::fetch_sub(this->_M_ptr, _S_type_size(__d), __m); }
2021
2022#if __glibcxx_atomic_min_max
2023 _GLIBCXX_ALWAYS_INLINE value_type
2024 fetch_min(value_type __i,
2025 memory_order __m = memory_order_seq_cst) const noexcept
2026 { return __atomic_impl::__fetch_min(this->_M_ptr, __i, __m); }
2027
2028 _GLIBCXX_ALWAYS_INLINE value_type
2029 fetch_max(value_type __i,
2030 memory_order __m = memory_order_seq_cst) const noexcept
2031 { return __atomic_impl::__fetch_max(this->_M_ptr, __i, __m); }
2032#endif
2033
2034 value_type
2035 operator++(int) const noexcept
2036 { return fetch_add(1); }
2037
2038 value_type
2039 operator--(int) const noexcept
2040 { return fetch_sub(1); }
2041
2042 value_type
2043 operator++() const noexcept
2044 {
2045 return __atomic_impl::__add_fetch(this->_M_ptr, _S_type_size(1));
2046 }
2047
2048 value_type
2049 operator--() const noexcept
2050 {
2051 return __atomic_impl::__sub_fetch(this->_M_ptr, _S_type_size(1));
2052 }
2053
2054 value_type
2055 operator+=(difference_type __d) const noexcept
2056 {
2057 return __atomic_impl::__add_fetch(this->_M_ptr, _S_type_size(__d));
2058 }
2059
2060 value_type
2061 operator-=(difference_type __d) const noexcept
2062 {
2063 return __atomic_impl::__sub_fetch(this->_M_ptr, _S_type_size(__d));
2064 }
2065
2066 private:
2067 static constexpr ptrdiff_t
2068 _S_type_size(ptrdiff_t __d) noexcept
2069 {
2070 using _Et = remove_pointer_t<value_type>;
2071 static_assert(is_object_v<_Et>);
2072 return __d * sizeof(_Et);
2073 }
2074 };
2075
2076 template<typename _Pt>
2077 struct __atomic_ref<const _Pt, false, false, true>
2078 : __atomic_ref_base<const _Pt>
2079 {
2080 using difference_type = ptrdiff_t;
2081 using __atomic_ref_base<const _Pt>::__atomic_ref_base;
2082 };
2083#endif // C++2a
2084
2085 /// @endcond
2086
2087 /// @} group atomics
2088
2089_GLIBCXX_END_NAMESPACE_VERSION
2090} // namespace std
2091
2092#endif
new
move.h
version.h
atomic_wait.h
atomic_lockfree_defines.h
c++config.h
std::__addressof
constexpr _Tp * __addressof(_Tp &__r) noexcept
Same as C++11 std::addressof.
Definition move.h:52
std::kill_dependency
_Tp kill_dependency(_Tp __y) noexcept
kill_dependency
Definition atomic_base.h:162
std::memory_order
memory_order
Enumeration for memory_order.
Definition atomic_base.h:66
std
ISO C++ entities toplevel namespace is std.
std::operator|
constexpr bitset< _Nb > operator|(const bitset< _Nb > &__x, const bitset< _Nb > &__y) noexcept
Global bitwise operations on bitsets.
Definition bitset:1629
std::operator&
constexpr bitset< _Nb > operator&(const bitset< _Nb > &__x, const bitset< _Nb > &__y) noexcept
Global bitwise operations on bitsets.
Definition bitset:1619