libstdc++
atomic_base.h
Go to the documentation of this file.
1 // -*- C++ -*- header.
2 
3 // Copyright (C) 2008-2023 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 
49 namespace 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
87  } memory_order;
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
atomic_lockfree_defines.h
std::operator&
constexpr bitset< _Nb > operator&(const bitset< _Nb > &__x, const bitset< _Nb > &__y) noexcept
Global bitwise operations on bitsets.
Definition: bitset:1553
std::__addressof
constexpr _Tp * __addressof(_Tp &__r) noexcept
Same as C++11 std::addressof.
Definition: move.h:51
std::kill_dependency
_Tp kill_dependency(_Tp __y) noexcept
kill_dependency
Definition: atomic_base.h:153
std::exchange
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:97
move.h
c++config.h
std::memory_order
memory_order
Enumeration for memory_order.
Definition: atomic_base.h:62
new
atomic_wait.h
std::operator|
constexpr bitset< _Nb > operator|(const bitset< _Nb > &__x, const bitset< _Nb > &__y) noexcept
Global bitwise operations on bitsets.
Definition: bitset:1563
std
ISO C++ entities toplevel namespace is std.
std::atomic_flag
atomic_flag
Definition: atomic_base.h:212