LCOV - code coverage report
Current view: top level - 11/bits - atomic_base.h (source / functions) Hit Total Coverage
Test: jami-coverage-filtered.info Lines: 46 48 95.8 %
Date: 2025-08-24 09:11:10 Functions: 31 35 88.6 %

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

Generated by: LCOV version 1.14