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