mirror of
https://github.com/gcc-mirror/gcc.git
synced 2026-05-06 23:25:24 +02:00
Currently for the types T that contains padding bits, std::atomic<T>(T) constructor was not usable at compile-time in C++14 or later modes. This regression caused by use of __builtin_clear_padding introduced in r13-2548-g157236dbd62164. This leads to two regressions when switching from C++11 to C++14 standard (or switching from GCC-12 to later version for C++14 standard), where for type X that contains padding * constexpr std::atomic<X> cx(X(...)) becomes ill-formed, * std::atomic<X> gx(X(...)) with static storage duration, switch from static to dynamic initialization. The latter breakage is silent and may introduced very hard to localize order of initialization issues. This patch mitigates above issue by not invoking the __builtin_clear_padding, during constant initialization (std::__is_constant_evaluated() is false). This is considered to be safe, as: * for objects with static storage duration, padding bits are already cleared by zero-initialization * for constexpr objects with non-static storage duration, there is no API that would allow user to observe padding bits on const atomic objects To elaborate on the second point, values of padding bits in atomic can be observed by: * The compare_exchange_weak/compare_exchange_strong operations are mutating, so cannot be invoked on const objects. * As atomic<X> is not required to store actual object of type X, observing its object representation does (via bitcast, memcpy), does not provide values of object representation of X. Furthermore, the operations are defined only for trivially_copyable types, and atomic specializations meets above requirement only due to bug in libstdc++ (see PR67572). Note that above will no longer hold, and the solution will need to be revisited during implementation of C++26 paper P3309R3: constexpr atomic and atomic_ref (it will be possible to call compare_exchange during constant evaluation). PR libstdc++/123875 libstdc++-v3/ChangeLog: * include/bits/atomic_base.h (__atomic_impl::__clear_padding): Use if constexpr unconditionally. (__atomic_float<_Fp>::__atomic_float(_Fp)): Skip __clear_padding call for constant evaluation. * include/std/atomic (atomic<_Tp>::atomic(_Tp)): Likewise. * testsuite/29_atomics/atomic/cons/static_zero_padding.cc: New test. Reviewed-by: Patrick Palka <ppalka@redhat.com> Reviewed-by: Jonathan Wakely <jwakely@redhat.com> Signed-off-by: Tomasz Kamiński <tkaminsk@redhat.com>
1883 lines
54 KiB
C++
1883 lines
54 KiB
C++
// -*- C++ -*- header.
|
|
|
|
// Copyright (C) 2008-2026 Free Software Foundation, Inc.
|
|
//
|
|
// This file is part of the GNU ISO C++ Library. This library is free
|
|
// software; you can redistribute it and/or modify it under the
|
|
// terms of the GNU General Public License as published by the
|
|
// Free Software Foundation; either version 3, or (at your option)
|
|
// any later version.
|
|
|
|
// This library is distributed in the hope that it will be useful,
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
// GNU General Public License for more details.
|
|
|
|
// Under Section 7 of GPL version 3, you are granted additional
|
|
// permissions described in the GCC Runtime Library Exception, version
|
|
// 3.1, as published by the Free Software Foundation.
|
|
|
|
// You should have received a copy of the GNU General Public License and
|
|
// a copy of the GCC Runtime Library Exception along with this program;
|
|
// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
|
|
// <http://www.gnu.org/licenses/>.
|
|
|
|
/** @file include/atomic
|
|
* This is a Standard C++ Library header.
|
|
*/
|
|
|
|
// Based on "C++ Atomic Types and Operations" by Hans Boehm and Lawrence Crowl.
|
|
// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2427.html
|
|
|
|
#ifndef _GLIBCXX_ATOMIC
|
|
#define _GLIBCXX_ATOMIC 1
|
|
|
|
#ifdef _GLIBCXX_SYSHDR
|
|
#pragma GCC system_header
|
|
#endif
|
|
|
|
#if __cplusplus < 201103L
|
|
# include <bits/c++0x_warning.h>
|
|
#else
|
|
|
|
#define __glibcxx_want_atomic_is_always_lock_free
|
|
#define __glibcxx_want_atomic_flag_test
|
|
#define __glibcxx_want_atomic_float
|
|
#define __glibcxx_want_atomic_min_max
|
|
#define __glibcxx_want_atomic_ref
|
|
#define __glibcxx_want_atomic_lock_free_type_aliases
|
|
#define __glibcxx_want_atomic_value_initialization
|
|
#define __glibcxx_want_atomic_wait
|
|
#include <bits/version.h>
|
|
|
|
#include <bits/atomic_base.h>
|
|
#include <cstdint>
|
|
#include <type_traits>
|
|
|
|
namespace std _GLIBCXX_VISIBILITY(default)
|
|
{
|
|
_GLIBCXX_BEGIN_NAMESPACE_VERSION
|
|
|
|
/**
|
|
* @addtogroup atomics
|
|
* @{
|
|
*/
|
|
|
|
template<typename _Tp>
|
|
struct atomic;
|
|
|
|
/// atomic<bool>
|
|
// NB: No operators or fetch-operations for this type.
|
|
template<>
|
|
struct atomic<bool>
|
|
{
|
|
using value_type = bool;
|
|
|
|
private:
|
|
__atomic_base<bool> _M_base;
|
|
|
|
public:
|
|
atomic() noexcept = default;
|
|
~atomic() noexcept = default;
|
|
atomic(const atomic&) = delete;
|
|
atomic& operator=(const atomic&) = delete;
|
|
atomic& operator=(const atomic&) volatile = delete;
|
|
|
|
constexpr atomic(bool __i) noexcept : _M_base(__i) { }
|
|
|
|
bool
|
|
operator=(bool __i) noexcept
|
|
{ return _M_base.operator=(__i); }
|
|
|
|
bool
|
|
operator=(bool __i) volatile noexcept
|
|
{ return _M_base.operator=(__i); }
|
|
|
|
operator bool() const noexcept
|
|
{ return _M_base.load(); }
|
|
|
|
operator bool() const volatile noexcept
|
|
{ return _M_base.load(); }
|
|
|
|
bool
|
|
is_lock_free() const noexcept { return _M_base.is_lock_free(); }
|
|
|
|
bool
|
|
is_lock_free() const volatile noexcept { return _M_base.is_lock_free(); }
|
|
|
|
#ifdef __cpp_lib_atomic_is_always_lock_free // C++ >= 17
|
|
static constexpr bool is_always_lock_free = ATOMIC_BOOL_LOCK_FREE == 2;
|
|
#endif
|
|
|
|
void
|
|
store(bool __i, memory_order __m = memory_order_seq_cst) noexcept
|
|
{ _M_base.store(__i, __m); }
|
|
|
|
void
|
|
store(bool __i, memory_order __m = memory_order_seq_cst) volatile noexcept
|
|
{ _M_base.store(__i, __m); }
|
|
|
|
bool
|
|
load(memory_order __m = memory_order_seq_cst) const noexcept
|
|
{ return _M_base.load(__m); }
|
|
|
|
bool
|
|
load(memory_order __m = memory_order_seq_cst) const volatile noexcept
|
|
{ return _M_base.load(__m); }
|
|
|
|
bool
|
|
exchange(bool __i, memory_order __m = memory_order_seq_cst) noexcept
|
|
{ return _M_base.exchange(__i, __m); }
|
|
|
|
bool
|
|
exchange(bool __i,
|
|
memory_order __m = memory_order_seq_cst) volatile noexcept
|
|
{ return _M_base.exchange(__i, __m); }
|
|
|
|
bool
|
|
compare_exchange_weak(bool& __i1, bool __i2, memory_order __m1,
|
|
memory_order __m2) noexcept
|
|
{ return _M_base.compare_exchange_weak(__i1, __i2, __m1, __m2); }
|
|
|
|
bool
|
|
compare_exchange_weak(bool& __i1, bool __i2, memory_order __m1,
|
|
memory_order __m2) volatile noexcept
|
|
{ return _M_base.compare_exchange_weak(__i1, __i2, __m1, __m2); }
|
|
|
|
bool
|
|
compare_exchange_weak(bool& __i1, bool __i2,
|
|
memory_order __m = memory_order_seq_cst) noexcept
|
|
{ return _M_base.compare_exchange_weak(__i1, __i2, __m); }
|
|
|
|
bool
|
|
compare_exchange_weak(bool& __i1, bool __i2,
|
|
memory_order __m = memory_order_seq_cst) volatile noexcept
|
|
{ return _M_base.compare_exchange_weak(__i1, __i2, __m); }
|
|
|
|
bool
|
|
compare_exchange_strong(bool& __i1, bool __i2, memory_order __m1,
|
|
memory_order __m2) noexcept
|
|
{ return _M_base.compare_exchange_strong(__i1, __i2, __m1, __m2); }
|
|
|
|
bool
|
|
compare_exchange_strong(bool& __i1, bool __i2, memory_order __m1,
|
|
memory_order __m2) volatile noexcept
|
|
{ return _M_base.compare_exchange_strong(__i1, __i2, __m1, __m2); }
|
|
|
|
bool
|
|
compare_exchange_strong(bool& __i1, bool __i2,
|
|
memory_order __m = memory_order_seq_cst) noexcept
|
|
{ return _M_base.compare_exchange_strong(__i1, __i2, __m); }
|
|
|
|
bool
|
|
compare_exchange_strong(bool& __i1, bool __i2,
|
|
memory_order __m = memory_order_seq_cst) volatile noexcept
|
|
{ return _M_base.compare_exchange_strong(__i1, __i2, __m); }
|
|
|
|
#if __cpp_lib_atomic_wait
|
|
void
|
|
wait(bool __old, memory_order __m = memory_order_seq_cst) const noexcept
|
|
{ _M_base.wait(__old, __m); }
|
|
|
|
// TODO add const volatile overload
|
|
|
|
void
|
|
notify_one() noexcept
|
|
{ _M_base.notify_one(); }
|
|
|
|
void
|
|
notify_all() noexcept
|
|
{ _M_base.notify_all(); }
|
|
#endif // __cpp_lib_atomic_wait
|
|
};
|
|
|
|
/**
|
|
* @brief Generic atomic type, primary class template.
|
|
*
|
|
* @tparam _Tp Type to be made atomic, must be trivially copyable.
|
|
*/
|
|
template<typename _Tp>
|
|
struct atomic
|
|
{
|
|
using value_type = _Tp;
|
|
|
|
private:
|
|
// Align 1/2/4/8/16-byte types to at least their size.
|
|
static constexpr int _S_min_alignment
|
|
= (sizeof(_Tp) & (sizeof(_Tp) - 1)) || sizeof(_Tp) > 16
|
|
? 0 : sizeof(_Tp);
|
|
|
|
static constexpr int _S_alignment
|
|
= _S_min_alignment > alignof(_Tp) ? _S_min_alignment : alignof(_Tp);
|
|
|
|
alignas(_S_alignment) _Tp _M_i;
|
|
|
|
static_assert(__is_trivially_copyable(_Tp),
|
|
"std::atomic requires a trivially copyable type");
|
|
|
|
static_assert(sizeof(_Tp) > 0,
|
|
"Incomplete or zero-sized types are not supported");
|
|
|
|
// _GLIBCXX_RESOLVE_LIB_DEFECTS
|
|
// 4069. std::atomic<volatile T> should be ill-formed
|
|
static_assert(is_same<_Tp, typename remove_cv<_Tp>::type>::value,
|
|
"template argument for std::atomic must not be const or volatile");
|
|
|
|
#if __cplusplus > 201703L
|
|
static_assert(is_copy_constructible_v<_Tp>);
|
|
static_assert(is_move_constructible_v<_Tp>);
|
|
static_assert(is_copy_assignable_v<_Tp>);
|
|
static_assert(is_move_assignable_v<_Tp>);
|
|
#endif
|
|
|
|
public:
|
|
#if __cpp_lib_atomic_value_initialization
|
|
// _GLIBCXX_RESOLVE_LIB_DEFECTS
|
|
// 4169. std::atomic<T>'s default constructor should be constrained
|
|
constexpr atomic() noexcept(is_nothrow_default_constructible_v<_Tp>)
|
|
requires is_default_constructible_v<_Tp>
|
|
: _M_i()
|
|
{}
|
|
#else
|
|
atomic() = default;
|
|
#endif
|
|
|
|
~atomic() noexcept = default;
|
|
atomic(const atomic&) = delete;
|
|
atomic& operator=(const atomic&) = delete;
|
|
atomic& operator=(const atomic&) volatile = delete;
|
|
|
|
constexpr atomic(_Tp __i) noexcept : _M_i(__i)
|
|
{
|
|
#if __cplusplus >= 201402L && __has_builtin(__builtin_clear_padding)
|
|
if _GLIBCXX17_CONSTEXPR (__atomic_impl::__maybe_has_padding<_Tp>())
|
|
if (!std::__is_constant_evaluated())
|
|
__builtin_clear_padding(std::__addressof(_M_i));
|
|
#endif
|
|
}
|
|
|
|
operator _Tp() const noexcept
|
|
{ return load(); }
|
|
|
|
operator _Tp() const volatile noexcept
|
|
{ return load(); }
|
|
|
|
_Tp
|
|
operator=(_Tp __i) noexcept
|
|
{ store(__i); return __i; }
|
|
|
|
_Tp
|
|
operator=(_Tp __i) volatile noexcept
|
|
{ store(__i); return __i; }
|
|
|
|
bool
|
|
is_lock_free() const noexcept
|
|
{
|
|
// Produce a fake, minimally aligned pointer.
|
|
return __atomic_is_lock_free(sizeof(_M_i),
|
|
reinterpret_cast<void *>(-_S_alignment));
|
|
}
|
|
|
|
bool
|
|
is_lock_free() const volatile noexcept
|
|
{
|
|
// Produce a fake, minimally aligned pointer.
|
|
return __atomic_is_lock_free(sizeof(_M_i),
|
|
reinterpret_cast<void *>(-_S_alignment));
|
|
}
|
|
|
|
#ifdef __cpp_lib_atomic_is_always_lock_free // C++ >= 17
|
|
static constexpr bool is_always_lock_free
|
|
= __atomic_always_lock_free(sizeof(_M_i), 0);
|
|
#endif
|
|
|
|
void
|
|
store(_Tp __i, memory_order __m = memory_order_seq_cst) noexcept
|
|
{
|
|
__atomic_store(std::__addressof(_M_i),
|
|
__atomic_impl::__clear_padding(__i),
|
|
int(__m));
|
|
}
|
|
|
|
void
|
|
store(_Tp __i, memory_order __m = memory_order_seq_cst) volatile noexcept
|
|
{
|
|
__atomic_store(std::__addressof(_M_i),
|
|
__atomic_impl::__clear_padding(__i),
|
|
int(__m));
|
|
}
|
|
|
|
_Tp
|
|
load(memory_order __m = memory_order_seq_cst) const noexcept
|
|
{
|
|
alignas(_Tp) unsigned char __buf[sizeof(_Tp)];
|
|
_Tp* __ptr = reinterpret_cast<_Tp*>(__buf);
|
|
__atomic_load(std::__addressof(_M_i), __ptr, int(__m));
|
|
return *__ptr;
|
|
}
|
|
|
|
_Tp
|
|
load(memory_order __m = memory_order_seq_cst) const volatile noexcept
|
|
{
|
|
alignas(_Tp) unsigned char __buf[sizeof(_Tp)];
|
|
_Tp* __ptr = reinterpret_cast<_Tp*>(__buf);
|
|
__atomic_load(std::__addressof(_M_i), __ptr, int(__m));
|
|
return *__ptr;
|
|
}
|
|
|
|
_Tp
|
|
exchange(_Tp __i, memory_order __m = memory_order_seq_cst) noexcept
|
|
{
|
|
alignas(_Tp) unsigned char __buf[sizeof(_Tp)];
|
|
_Tp* __ptr = reinterpret_cast<_Tp*>(__buf);
|
|
__atomic_exchange(std::__addressof(_M_i),
|
|
__atomic_impl::__clear_padding(__i),
|
|
__ptr, int(__m));
|
|
return *__ptr;
|
|
}
|
|
|
|
_Tp
|
|
exchange(_Tp __i,
|
|
memory_order __m = memory_order_seq_cst) volatile noexcept
|
|
{
|
|
alignas(_Tp) unsigned char __buf[sizeof(_Tp)];
|
|
_Tp* __ptr = reinterpret_cast<_Tp*>(__buf);
|
|
__atomic_exchange(std::__addressof(_M_i),
|
|
__atomic_impl::__clear_padding(__i),
|
|
__ptr, int(__m));
|
|
return *__ptr;
|
|
}
|
|
|
|
bool
|
|
compare_exchange_weak(_Tp& __e, _Tp __i, memory_order __s,
|
|
memory_order __f) noexcept
|
|
{
|
|
return __atomic_impl::__compare_exchange(_M_i, __e, __i, true,
|
|
__s, __f);
|
|
}
|
|
|
|
bool
|
|
compare_exchange_weak(_Tp& __e, _Tp __i, memory_order __s,
|
|
memory_order __f) volatile noexcept
|
|
{
|
|
return __atomic_impl::__compare_exchange(_M_i, __e, __i, true,
|
|
__s, __f);
|
|
}
|
|
|
|
bool
|
|
compare_exchange_weak(_Tp& __e, _Tp __i,
|
|
memory_order __m = memory_order_seq_cst) noexcept
|
|
{ return compare_exchange_weak(__e, __i, __m,
|
|
__cmpexch_failure_order(__m)); }
|
|
|
|
bool
|
|
compare_exchange_weak(_Tp& __e, _Tp __i,
|
|
memory_order __m = memory_order_seq_cst) volatile noexcept
|
|
{ return compare_exchange_weak(__e, __i, __m,
|
|
__cmpexch_failure_order(__m)); }
|
|
|
|
bool
|
|
compare_exchange_strong(_Tp& __e, _Tp __i, memory_order __s,
|
|
memory_order __f) noexcept
|
|
{
|
|
return __atomic_impl::__compare_exchange(_M_i, __e, __i, false,
|
|
__s, __f);
|
|
}
|
|
|
|
bool
|
|
compare_exchange_strong(_Tp& __e, _Tp __i, memory_order __s,
|
|
memory_order __f) volatile noexcept
|
|
{
|
|
return __atomic_impl::__compare_exchange(_M_i, __e, __i, false,
|
|
__s, __f);
|
|
}
|
|
|
|
bool
|
|
compare_exchange_strong(_Tp& __e, _Tp __i,
|
|
memory_order __m = memory_order_seq_cst) noexcept
|
|
{ return compare_exchange_strong(__e, __i, __m,
|
|
__cmpexch_failure_order(__m)); }
|
|
|
|
bool
|
|
compare_exchange_strong(_Tp& __e, _Tp __i,
|
|
memory_order __m = memory_order_seq_cst) volatile noexcept
|
|
{ return compare_exchange_strong(__e, __i, __m,
|
|
__cmpexch_failure_order(__m)); }
|
|
|
|
#if __cpp_lib_atomic_wait // C++ >= 20
|
|
void
|
|
wait(_Tp __old, memory_order __m = memory_order_seq_cst) const noexcept
|
|
{
|
|
std::__atomic_wait_address_v(std::addressof(_M_i), __old,
|
|
[__m, this] { return this->load(__m); });
|
|
}
|
|
|
|
// TODO add const volatile overload
|
|
|
|
void
|
|
notify_one() noexcept
|
|
{ std::__atomic_notify_address(std::addressof(_M_i), false); }
|
|
|
|
void
|
|
notify_all() noexcept
|
|
{ std::__atomic_notify_address(std::addressof(_M_i), true); }
|
|
#endif // __cpp_lib_atomic_wait
|
|
};
|
|
|
|
/// Partial specialization for pointer types.
|
|
template<typename _Tp>
|
|
struct atomic<_Tp*>
|
|
{
|
|
using value_type = _Tp*;
|
|
using difference_type = ptrdiff_t;
|
|
|
|
typedef _Tp* __pointer_type;
|
|
typedef __atomic_base<_Tp*> __base_type;
|
|
__base_type _M_b;
|
|
|
|
atomic() noexcept = default;
|
|
~atomic() noexcept = default;
|
|
atomic(const atomic&) = delete;
|
|
atomic& operator=(const atomic&) = delete;
|
|
atomic& operator=(const atomic&) volatile = delete;
|
|
|
|
constexpr atomic(__pointer_type __p) noexcept : _M_b(__p) { }
|
|
|
|
operator __pointer_type() const noexcept
|
|
{ return __pointer_type(_M_b); }
|
|
|
|
operator __pointer_type() const volatile noexcept
|
|
{ return __pointer_type(_M_b); }
|
|
|
|
__pointer_type
|
|
operator=(__pointer_type __p) noexcept
|
|
{ return _M_b.operator=(__p); }
|
|
|
|
__pointer_type
|
|
operator=(__pointer_type __p) volatile noexcept
|
|
{ return _M_b.operator=(__p); }
|
|
|
|
__pointer_type
|
|
operator++(int) noexcept
|
|
{
|
|
#if __cplusplus >= 201703L
|
|
static_assert( is_object_v<_Tp>, "pointer to object type" );
|
|
#endif
|
|
return _M_b++;
|
|
}
|
|
|
|
__pointer_type
|
|
operator++(int) volatile noexcept
|
|
{
|
|
#if __cplusplus >= 201703L
|
|
static_assert( is_object_v<_Tp>, "pointer to object type" );
|
|
#endif
|
|
return _M_b++;
|
|
}
|
|
|
|
__pointer_type
|
|
operator--(int) noexcept
|
|
{
|
|
#if __cplusplus >= 201703L
|
|
static_assert( is_object_v<_Tp>, "pointer to object type" );
|
|
#endif
|
|
return _M_b--;
|
|
}
|
|
|
|
__pointer_type
|
|
operator--(int) volatile noexcept
|
|
{
|
|
#if __cplusplus >= 201703L
|
|
static_assert( is_object_v<_Tp>, "pointer to object type" );
|
|
#endif
|
|
return _M_b--;
|
|
}
|
|
|
|
__pointer_type
|
|
operator++() noexcept
|
|
{
|
|
#if __cplusplus >= 201703L
|
|
static_assert( is_object_v<_Tp>, "pointer to object type" );
|
|
#endif
|
|
return ++_M_b;
|
|
}
|
|
|
|
__pointer_type
|
|
operator++() volatile noexcept
|
|
{
|
|
#if __cplusplus >= 201703L
|
|
static_assert( is_object_v<_Tp>, "pointer to object type" );
|
|
#endif
|
|
return ++_M_b;
|
|
}
|
|
|
|
__pointer_type
|
|
operator--() noexcept
|
|
{
|
|
#if __cplusplus >= 201703L
|
|
static_assert( is_object_v<_Tp>, "pointer to object type" );
|
|
#endif
|
|
return --_M_b;
|
|
}
|
|
|
|
__pointer_type
|
|
operator--() volatile noexcept
|
|
{
|
|
#if __cplusplus >= 201703L
|
|
static_assert( is_object_v<_Tp>, "pointer to object type" );
|
|
#endif
|
|
return --_M_b;
|
|
}
|
|
|
|
__pointer_type
|
|
operator+=(ptrdiff_t __d) noexcept
|
|
{
|
|
#if __cplusplus >= 201703L
|
|
static_assert( is_object_v<_Tp>, "pointer to object type" );
|
|
#endif
|
|
return _M_b.operator+=(__d);
|
|
}
|
|
|
|
__pointer_type
|
|
operator+=(ptrdiff_t __d) volatile noexcept
|
|
{
|
|
#if __cplusplus >= 201703L
|
|
static_assert( is_object_v<_Tp>, "pointer to object type" );
|
|
#endif
|
|
return _M_b.operator+=(__d);
|
|
}
|
|
|
|
__pointer_type
|
|
operator-=(ptrdiff_t __d) noexcept
|
|
{
|
|
#if __cplusplus >= 201703L
|
|
static_assert( is_object_v<_Tp>, "pointer to object type" );
|
|
#endif
|
|
return _M_b.operator-=(__d);
|
|
}
|
|
|
|
__pointer_type
|
|
operator-=(ptrdiff_t __d) volatile noexcept
|
|
{
|
|
#if __cplusplus >= 201703L
|
|
static_assert( is_object_v<_Tp>, "pointer to object type" );
|
|
#endif
|
|
return _M_b.operator-=(__d);
|
|
}
|
|
|
|
bool
|
|
is_lock_free() const noexcept
|
|
{ return _M_b.is_lock_free(); }
|
|
|
|
bool
|
|
is_lock_free() const volatile noexcept
|
|
{ return _M_b.is_lock_free(); }
|
|
|
|
#ifdef __cpp_lib_atomic_is_always_lock_free // C++ >= 17
|
|
static constexpr bool is_always_lock_free
|
|
= ATOMIC_POINTER_LOCK_FREE == 2;
|
|
#endif
|
|
|
|
void
|
|
store(__pointer_type __p,
|
|
memory_order __m = memory_order_seq_cst) noexcept
|
|
{ return _M_b.store(__p, __m); }
|
|
|
|
void
|
|
store(__pointer_type __p,
|
|
memory_order __m = memory_order_seq_cst) volatile noexcept
|
|
{ return _M_b.store(__p, __m); }
|
|
|
|
__pointer_type
|
|
load(memory_order __m = memory_order_seq_cst) const noexcept
|
|
{ return _M_b.load(__m); }
|
|
|
|
__pointer_type
|
|
load(memory_order __m = memory_order_seq_cst) const volatile noexcept
|
|
{ return _M_b.load(__m); }
|
|
|
|
__pointer_type
|
|
exchange(__pointer_type __p,
|
|
memory_order __m = memory_order_seq_cst) noexcept
|
|
{ return _M_b.exchange(__p, __m); }
|
|
|
|
__pointer_type
|
|
exchange(__pointer_type __p,
|
|
memory_order __m = memory_order_seq_cst) volatile noexcept
|
|
{ return _M_b.exchange(__p, __m); }
|
|
|
|
bool
|
|
compare_exchange_weak(__pointer_type& __p1, __pointer_type __p2,
|
|
memory_order __m1, memory_order __m2) noexcept
|
|
{ return _M_b.compare_exchange_weak(__p1, __p2, __m1, __m2); }
|
|
|
|
bool
|
|
compare_exchange_weak(__pointer_type& __p1, __pointer_type __p2,
|
|
memory_order __m1,
|
|
memory_order __m2) volatile noexcept
|
|
{ return _M_b.compare_exchange_weak(__p1, __p2, __m1, __m2); }
|
|
|
|
bool
|
|
compare_exchange_weak(__pointer_type& __p1, __pointer_type __p2,
|
|
memory_order __m = memory_order_seq_cst) noexcept
|
|
{
|
|
return compare_exchange_weak(__p1, __p2, __m,
|
|
__cmpexch_failure_order(__m));
|
|
}
|
|
|
|
bool
|
|
compare_exchange_weak(__pointer_type& __p1, __pointer_type __p2,
|
|
memory_order __m = memory_order_seq_cst) volatile noexcept
|
|
{
|
|
return compare_exchange_weak(__p1, __p2, __m,
|
|
__cmpexch_failure_order(__m));
|
|
}
|
|
|
|
bool
|
|
compare_exchange_strong(__pointer_type& __p1, __pointer_type __p2,
|
|
memory_order __m1, memory_order __m2) noexcept
|
|
{ return _M_b.compare_exchange_strong(__p1, __p2, __m1, __m2); }
|
|
|
|
bool
|
|
compare_exchange_strong(__pointer_type& __p1, __pointer_type __p2,
|
|
memory_order __m1,
|
|
memory_order __m2) volatile noexcept
|
|
{ return _M_b.compare_exchange_strong(__p1, __p2, __m1, __m2); }
|
|
|
|
bool
|
|
compare_exchange_strong(__pointer_type& __p1, __pointer_type __p2,
|
|
memory_order __m = memory_order_seq_cst) noexcept
|
|
{
|
|
return _M_b.compare_exchange_strong(__p1, __p2, __m,
|
|
__cmpexch_failure_order(__m));
|
|
}
|
|
|
|
bool
|
|
compare_exchange_strong(__pointer_type& __p1, __pointer_type __p2,
|
|
memory_order __m = memory_order_seq_cst) volatile noexcept
|
|
{
|
|
return _M_b.compare_exchange_strong(__p1, __p2, __m,
|
|
__cmpexch_failure_order(__m));
|
|
}
|
|
|
|
#if __cpp_lib_atomic_wait
|
|
void
|
|
wait(__pointer_type __old, memory_order __m = memory_order_seq_cst) const noexcept
|
|
{ _M_b.wait(__old, __m); }
|
|
|
|
// TODO add const volatile overload
|
|
|
|
void
|
|
notify_one() noexcept
|
|
{ _M_b.notify_one(); }
|
|
|
|
void
|
|
notify_all() noexcept
|
|
{ _M_b.notify_all(); }
|
|
#endif // __cpp_lib_atomic_wait
|
|
|
|
__pointer_type
|
|
fetch_add(ptrdiff_t __d,
|
|
memory_order __m = memory_order_seq_cst) noexcept
|
|
{
|
|
#if __cplusplus >= 201703L
|
|
static_assert( is_object_v<_Tp>, "pointer to object type" );
|
|
#endif
|
|
return _M_b.fetch_add(__d, __m);
|
|
}
|
|
|
|
__pointer_type
|
|
fetch_add(ptrdiff_t __d,
|
|
memory_order __m = memory_order_seq_cst) volatile noexcept
|
|
{
|
|
#if __cplusplus >= 201703L
|
|
static_assert( is_object_v<_Tp>, "pointer to object type" );
|
|
#endif
|
|
return _M_b.fetch_add(__d, __m);
|
|
}
|
|
|
|
__pointer_type
|
|
fetch_sub(ptrdiff_t __d,
|
|
memory_order __m = memory_order_seq_cst) noexcept
|
|
{
|
|
#if __cplusplus >= 201703L
|
|
static_assert( is_object_v<_Tp>, "pointer to object type" );
|
|
#endif
|
|
return _M_b.fetch_sub(__d, __m);
|
|
}
|
|
|
|
__pointer_type
|
|
fetch_sub(ptrdiff_t __d,
|
|
memory_order __m = memory_order_seq_cst) volatile noexcept
|
|
{
|
|
#if __cplusplus >= 201703L
|
|
static_assert( is_object_v<_Tp>, "pointer to object type" );
|
|
#endif
|
|
return _M_b.fetch_sub(__d, __m);
|
|
}
|
|
};
|
|
|
|
|
|
/// Explicit specialization for char.
|
|
template<>
|
|
struct atomic<char> : __atomic_base<char>
|
|
{
|
|
typedef char __integral_type;
|
|
typedef __atomic_base<char> __base_type;
|
|
|
|
atomic() noexcept = default;
|
|
~atomic() noexcept = default;
|
|
atomic(const atomic&) = delete;
|
|
atomic& operator=(const atomic&) = delete;
|
|
atomic& operator=(const atomic&) volatile = delete;
|
|
|
|
constexpr atomic(__integral_type __i) noexcept : __base_type(__i) { }
|
|
|
|
using __base_type::operator __integral_type;
|
|
using __base_type::operator=;
|
|
|
|
#ifdef __cpp_lib_atomic_is_always_lock_free // C++ >= 17
|
|
static constexpr bool is_always_lock_free = ATOMIC_CHAR_LOCK_FREE == 2;
|
|
#endif
|
|
};
|
|
|
|
/// Explicit specialization for signed char.
|
|
template<>
|
|
struct atomic<signed char> : __atomic_base<signed char>
|
|
{
|
|
typedef signed char __integral_type;
|
|
typedef __atomic_base<signed char> __base_type;
|
|
|
|
atomic() noexcept= default;
|
|
~atomic() noexcept = default;
|
|
atomic(const atomic&) = delete;
|
|
atomic& operator=(const atomic&) = delete;
|
|
atomic& operator=(const atomic&) volatile = delete;
|
|
|
|
constexpr atomic(__integral_type __i) noexcept : __base_type(__i) { }
|
|
|
|
using __base_type::operator __integral_type;
|
|
using __base_type::operator=;
|
|
|
|
#ifdef __cpp_lib_atomic_is_always_lock_free // C++ >= 17
|
|
static constexpr bool is_always_lock_free = ATOMIC_CHAR_LOCK_FREE == 2;
|
|
#endif
|
|
};
|
|
|
|
/// Explicit specialization for unsigned char.
|
|
template<>
|
|
struct atomic<unsigned char> : __atomic_base<unsigned char>
|
|
{
|
|
typedef unsigned char __integral_type;
|
|
typedef __atomic_base<unsigned char> __base_type;
|
|
|
|
atomic() noexcept= default;
|
|
~atomic() noexcept = default;
|
|
atomic(const atomic&) = delete;
|
|
atomic& operator=(const atomic&) = delete;
|
|
atomic& operator=(const atomic&) volatile = delete;
|
|
|
|
constexpr atomic(__integral_type __i) noexcept : __base_type(__i) { }
|
|
|
|
using __base_type::operator __integral_type;
|
|
using __base_type::operator=;
|
|
|
|
#ifdef __cpp_lib_atomic_is_always_lock_free // C++ >= 17
|
|
static constexpr bool is_always_lock_free = ATOMIC_CHAR_LOCK_FREE == 2;
|
|
#endif
|
|
};
|
|
|
|
/// Explicit specialization for short.
|
|
template<>
|
|
struct atomic<short> : __atomic_base<short>
|
|
{
|
|
typedef short __integral_type;
|
|
typedef __atomic_base<short> __base_type;
|
|
|
|
atomic() noexcept = default;
|
|
~atomic() noexcept = default;
|
|
atomic(const atomic&) = delete;
|
|
atomic& operator=(const atomic&) = delete;
|
|
atomic& operator=(const atomic&) volatile = delete;
|
|
|
|
constexpr atomic(__integral_type __i) noexcept : __base_type(__i) { }
|
|
|
|
using __base_type::operator __integral_type;
|
|
using __base_type::operator=;
|
|
|
|
#ifdef __cpp_lib_atomic_is_always_lock_free // C++ >= 17
|
|
static constexpr bool is_always_lock_free = ATOMIC_SHORT_LOCK_FREE == 2;
|
|
#endif
|
|
};
|
|
|
|
/// Explicit specialization for unsigned short.
|
|
template<>
|
|
struct atomic<unsigned short> : __atomic_base<unsigned short>
|
|
{
|
|
typedef unsigned short __integral_type;
|
|
typedef __atomic_base<unsigned short> __base_type;
|
|
|
|
atomic() noexcept = default;
|
|
~atomic() noexcept = default;
|
|
atomic(const atomic&) = delete;
|
|
atomic& operator=(const atomic&) = delete;
|
|
atomic& operator=(const atomic&) volatile = delete;
|
|
|
|
constexpr atomic(__integral_type __i) noexcept : __base_type(__i) { }
|
|
|
|
using __base_type::operator __integral_type;
|
|
using __base_type::operator=;
|
|
|
|
#ifdef __cpp_lib_atomic_is_always_lock_free // C++ >= 17
|
|
static constexpr bool is_always_lock_free = ATOMIC_SHORT_LOCK_FREE == 2;
|
|
#endif
|
|
};
|
|
|
|
/// Explicit specialization for int.
|
|
template<>
|
|
struct atomic<int> : __atomic_base<int>
|
|
{
|
|
typedef int __integral_type;
|
|
typedef __atomic_base<int> __base_type;
|
|
|
|
atomic() noexcept = default;
|
|
~atomic() noexcept = default;
|
|
atomic(const atomic&) = delete;
|
|
atomic& operator=(const atomic&) = delete;
|
|
atomic& operator=(const atomic&) volatile = delete;
|
|
|
|
constexpr atomic(__integral_type __i) noexcept : __base_type(__i) { }
|
|
|
|
using __base_type::operator __integral_type;
|
|
using __base_type::operator=;
|
|
|
|
#ifdef __cpp_lib_atomic_is_always_lock_free // C++ >= 17
|
|
static constexpr bool is_always_lock_free = ATOMIC_INT_LOCK_FREE == 2;
|
|
#endif
|
|
};
|
|
|
|
/// Explicit specialization for unsigned int.
|
|
template<>
|
|
struct atomic<unsigned int> : __atomic_base<unsigned int>
|
|
{
|
|
typedef unsigned int __integral_type;
|
|
typedef __atomic_base<unsigned int> __base_type;
|
|
|
|
atomic() noexcept = default;
|
|
~atomic() noexcept = default;
|
|
atomic(const atomic&) = delete;
|
|
atomic& operator=(const atomic&) = delete;
|
|
atomic& operator=(const atomic&) volatile = delete;
|
|
|
|
constexpr atomic(__integral_type __i) noexcept : __base_type(__i) { }
|
|
|
|
using __base_type::operator __integral_type;
|
|
using __base_type::operator=;
|
|
|
|
#ifdef __cpp_lib_atomic_is_always_lock_free // C++ >= 17
|
|
static constexpr bool is_always_lock_free = ATOMIC_INT_LOCK_FREE == 2;
|
|
#endif
|
|
};
|
|
|
|
/// Explicit specialization for long.
|
|
template<>
|
|
struct atomic<long> : __atomic_base<long>
|
|
{
|
|
typedef long __integral_type;
|
|
typedef __atomic_base<long> __base_type;
|
|
|
|
atomic() noexcept = default;
|
|
~atomic() noexcept = default;
|
|
atomic(const atomic&) = delete;
|
|
atomic& operator=(const atomic&) = delete;
|
|
atomic& operator=(const atomic&) volatile = delete;
|
|
|
|
constexpr atomic(__integral_type __i) noexcept : __base_type(__i) { }
|
|
|
|
using __base_type::operator __integral_type;
|
|
using __base_type::operator=;
|
|
|
|
#ifdef __cpp_lib_atomic_is_always_lock_free // C++ >= 17
|
|
static constexpr bool is_always_lock_free = ATOMIC_LONG_LOCK_FREE == 2;
|
|
#endif
|
|
};
|
|
|
|
/// Explicit specialization for unsigned long.
|
|
template<>
|
|
struct atomic<unsigned long> : __atomic_base<unsigned long>
|
|
{
|
|
typedef unsigned long __integral_type;
|
|
typedef __atomic_base<unsigned long> __base_type;
|
|
|
|
atomic() noexcept = default;
|
|
~atomic() noexcept = default;
|
|
atomic(const atomic&) = delete;
|
|
atomic& operator=(const atomic&) = delete;
|
|
atomic& operator=(const atomic&) volatile = delete;
|
|
|
|
constexpr atomic(__integral_type __i) noexcept : __base_type(__i) { }
|
|
|
|
using __base_type::operator __integral_type;
|
|
using __base_type::operator=;
|
|
|
|
#ifdef __cpp_lib_atomic_is_always_lock_free // C++ >= 17
|
|
static constexpr bool is_always_lock_free = ATOMIC_LONG_LOCK_FREE == 2;
|
|
#endif
|
|
};
|
|
|
|
/// Explicit specialization for long long.
|
|
template<>
|
|
struct atomic<long long> : __atomic_base<long long>
|
|
{
|
|
typedef long long __integral_type;
|
|
typedef __atomic_base<long long> __base_type;
|
|
|
|
atomic() noexcept = default;
|
|
~atomic() noexcept = default;
|
|
atomic(const atomic&) = delete;
|
|
atomic& operator=(const atomic&) = delete;
|
|
atomic& operator=(const atomic&) volatile = delete;
|
|
|
|
constexpr atomic(__integral_type __i) noexcept : __base_type(__i) { }
|
|
|
|
using __base_type::operator __integral_type;
|
|
using __base_type::operator=;
|
|
|
|
#ifdef __cpp_lib_atomic_is_always_lock_free // C++ >= 17
|
|
static constexpr bool is_always_lock_free = ATOMIC_LLONG_LOCK_FREE == 2;
|
|
#endif
|
|
};
|
|
|
|
/// Explicit specialization for unsigned long long.
|
|
template<>
|
|
struct atomic<unsigned long long> : __atomic_base<unsigned long long>
|
|
{
|
|
typedef unsigned long long __integral_type;
|
|
typedef __atomic_base<unsigned long long> __base_type;
|
|
|
|
atomic() noexcept = default;
|
|
~atomic() noexcept = default;
|
|
atomic(const atomic&) = delete;
|
|
atomic& operator=(const atomic&) = delete;
|
|
atomic& operator=(const atomic&) volatile = delete;
|
|
|
|
constexpr atomic(__integral_type __i) noexcept : __base_type(__i) { }
|
|
|
|
using __base_type::operator __integral_type;
|
|
using __base_type::operator=;
|
|
|
|
#ifdef __cpp_lib_atomic_is_always_lock_free // C++ >= 17
|
|
static constexpr bool is_always_lock_free = ATOMIC_LLONG_LOCK_FREE == 2;
|
|
#endif
|
|
};
|
|
|
|
/// Explicit specialization for wchar_t.
|
|
template<>
|
|
struct atomic<wchar_t> : __atomic_base<wchar_t>
|
|
{
|
|
typedef wchar_t __integral_type;
|
|
typedef __atomic_base<wchar_t> __base_type;
|
|
|
|
atomic() noexcept = default;
|
|
~atomic() noexcept = default;
|
|
atomic(const atomic&) = delete;
|
|
atomic& operator=(const atomic&) = delete;
|
|
atomic& operator=(const atomic&) volatile = delete;
|
|
|
|
constexpr atomic(__integral_type __i) noexcept : __base_type(__i) { }
|
|
|
|
using __base_type::operator __integral_type;
|
|
using __base_type::operator=;
|
|
|
|
#ifdef __cpp_lib_atomic_is_always_lock_free // C++ >= 17
|
|
static constexpr bool is_always_lock_free = ATOMIC_WCHAR_T_LOCK_FREE == 2;
|
|
#endif
|
|
};
|
|
|
|
#ifdef _GLIBCXX_USE_CHAR8_T
|
|
/// Explicit specialization for char8_t.
|
|
template<>
|
|
struct atomic<char8_t> : __atomic_base<char8_t>
|
|
{
|
|
typedef char8_t __integral_type;
|
|
typedef __atomic_base<char8_t> __base_type;
|
|
|
|
atomic() noexcept = default;
|
|
~atomic() noexcept = default;
|
|
atomic(const atomic&) = delete;
|
|
atomic& operator=(const atomic&) = delete;
|
|
atomic& operator=(const atomic&) volatile = delete;
|
|
|
|
constexpr atomic(__integral_type __i) noexcept : __base_type(__i) { }
|
|
|
|
using __base_type::operator __integral_type;
|
|
using __base_type::operator=;
|
|
|
|
#ifdef __cpp_lib_atomic_is_always_lock_free // C++ >= 17
|
|
static constexpr bool is_always_lock_free
|
|
= ATOMIC_CHAR8_T_LOCK_FREE == 2;
|
|
#endif
|
|
};
|
|
#endif
|
|
|
|
/// Explicit specialization for char16_t.
|
|
template<>
|
|
struct atomic<char16_t> : __atomic_base<char16_t>
|
|
{
|
|
typedef char16_t __integral_type;
|
|
typedef __atomic_base<char16_t> __base_type;
|
|
|
|
atomic() noexcept = default;
|
|
~atomic() noexcept = default;
|
|
atomic(const atomic&) = delete;
|
|
atomic& operator=(const atomic&) = delete;
|
|
atomic& operator=(const atomic&) volatile = delete;
|
|
|
|
constexpr atomic(__integral_type __i) noexcept : __base_type(__i) { }
|
|
|
|
using __base_type::operator __integral_type;
|
|
using __base_type::operator=;
|
|
|
|
#ifdef __cpp_lib_atomic_is_always_lock_free // C++ >= 17
|
|
static constexpr bool is_always_lock_free
|
|
= ATOMIC_CHAR16_T_LOCK_FREE == 2;
|
|
#endif
|
|
};
|
|
|
|
/// Explicit specialization for char32_t.
|
|
template<>
|
|
struct atomic<char32_t> : __atomic_base<char32_t>
|
|
{
|
|
typedef char32_t __integral_type;
|
|
typedef __atomic_base<char32_t> __base_type;
|
|
|
|
atomic() noexcept = default;
|
|
~atomic() noexcept = default;
|
|
atomic(const atomic&) = delete;
|
|
atomic& operator=(const atomic&) = delete;
|
|
atomic& operator=(const atomic&) volatile = delete;
|
|
|
|
constexpr atomic(__integral_type __i) noexcept : __base_type(__i) { }
|
|
|
|
using __base_type::operator __integral_type;
|
|
using __base_type::operator=;
|
|
|
|
#ifdef __cpp_lib_atomic_is_always_lock_free // C++ >= 17
|
|
static constexpr bool is_always_lock_free
|
|
= ATOMIC_CHAR32_T_LOCK_FREE == 2;
|
|
#endif
|
|
};
|
|
|
|
|
|
/// atomic_bool
|
|
typedef atomic<bool> atomic_bool;
|
|
|
|
/// atomic_char
|
|
typedef atomic<char> atomic_char;
|
|
|
|
/// atomic_schar
|
|
typedef atomic<signed char> atomic_schar;
|
|
|
|
/// atomic_uchar
|
|
typedef atomic<unsigned char> atomic_uchar;
|
|
|
|
/// atomic_short
|
|
typedef atomic<short> atomic_short;
|
|
|
|
/// atomic_ushort
|
|
typedef atomic<unsigned short> atomic_ushort;
|
|
|
|
/// atomic_int
|
|
typedef atomic<int> atomic_int;
|
|
|
|
/// atomic_uint
|
|
typedef atomic<unsigned int> atomic_uint;
|
|
|
|
/// atomic_long
|
|
typedef atomic<long> atomic_long;
|
|
|
|
/// atomic_ulong
|
|
typedef atomic<unsigned long> atomic_ulong;
|
|
|
|
/// atomic_llong
|
|
typedef atomic<long long> atomic_llong;
|
|
|
|
/// atomic_ullong
|
|
typedef atomic<unsigned long long> atomic_ullong;
|
|
|
|
/// atomic_wchar_t
|
|
typedef atomic<wchar_t> atomic_wchar_t;
|
|
|
|
#ifdef _GLIBCXX_USE_CHAR8_T
|
|
/// atomic_char8_t
|
|
typedef atomic<char8_t> atomic_char8_t;
|
|
#endif
|
|
|
|
/// atomic_char16_t
|
|
typedef atomic<char16_t> atomic_char16_t;
|
|
|
|
/// atomic_char32_t
|
|
typedef atomic<char32_t> atomic_char32_t;
|
|
|
|
#ifdef _GLIBCXX_USE_C99_STDINT
|
|
// _GLIBCXX_RESOLVE_LIB_DEFECTS
|
|
// 2441. Exact-width atomic typedefs should be provided
|
|
|
|
/// atomic_int8_t
|
|
typedef atomic<int8_t> atomic_int8_t;
|
|
|
|
/// atomic_uint8_t
|
|
typedef atomic<uint8_t> atomic_uint8_t;
|
|
|
|
/// atomic_int16_t
|
|
typedef atomic<int16_t> atomic_int16_t;
|
|
|
|
/// atomic_uint16_t
|
|
typedef atomic<uint16_t> atomic_uint16_t;
|
|
|
|
/// atomic_int32_t
|
|
typedef atomic<int32_t> atomic_int32_t;
|
|
|
|
/// atomic_uint32_t
|
|
typedef atomic<uint32_t> atomic_uint32_t;
|
|
|
|
/// atomic_int64_t
|
|
typedef atomic<int64_t> atomic_int64_t;
|
|
|
|
/// atomic_uint64_t
|
|
typedef atomic<uint64_t> atomic_uint64_t;
|
|
#endif
|
|
|
|
/// atomic_int_least8_t
|
|
typedef atomic<int_least8_t> atomic_int_least8_t;
|
|
|
|
/// atomic_uint_least8_t
|
|
typedef atomic<uint_least8_t> atomic_uint_least8_t;
|
|
|
|
/// atomic_int_least16_t
|
|
typedef atomic<int_least16_t> atomic_int_least16_t;
|
|
|
|
/// atomic_uint_least16_t
|
|
typedef atomic<uint_least16_t> atomic_uint_least16_t;
|
|
|
|
/// atomic_int_least32_t
|
|
typedef atomic<int_least32_t> atomic_int_least32_t;
|
|
|
|
/// atomic_uint_least32_t
|
|
typedef atomic<uint_least32_t> atomic_uint_least32_t;
|
|
|
|
/// atomic_int_least64_t
|
|
typedef atomic<int_least64_t> atomic_int_least64_t;
|
|
|
|
/// atomic_uint_least64_t
|
|
typedef atomic<uint_least64_t> atomic_uint_least64_t;
|
|
|
|
|
|
/// atomic_int_fast8_t
|
|
typedef atomic<int_fast8_t> atomic_int_fast8_t;
|
|
|
|
/// atomic_uint_fast8_t
|
|
typedef atomic<uint_fast8_t> atomic_uint_fast8_t;
|
|
|
|
/// atomic_int_fast16_t
|
|
typedef atomic<int_fast16_t> atomic_int_fast16_t;
|
|
|
|
/// atomic_uint_fast16_t
|
|
typedef atomic<uint_fast16_t> atomic_uint_fast16_t;
|
|
|
|
/// atomic_int_fast32_t
|
|
typedef atomic<int_fast32_t> atomic_int_fast32_t;
|
|
|
|
/// atomic_uint_fast32_t
|
|
typedef atomic<uint_fast32_t> atomic_uint_fast32_t;
|
|
|
|
/// atomic_int_fast64_t
|
|
typedef atomic<int_fast64_t> atomic_int_fast64_t;
|
|
|
|
/// atomic_uint_fast64_t
|
|
typedef atomic<uint_fast64_t> atomic_uint_fast64_t;
|
|
|
|
|
|
/// atomic_intptr_t
|
|
typedef atomic<intptr_t> atomic_intptr_t;
|
|
|
|
/// atomic_uintptr_t
|
|
typedef atomic<uintptr_t> atomic_uintptr_t;
|
|
|
|
/// atomic_size_t
|
|
typedef atomic<size_t> atomic_size_t;
|
|
|
|
/// atomic_ptrdiff_t
|
|
typedef atomic<ptrdiff_t> atomic_ptrdiff_t;
|
|
|
|
/// atomic_intmax_t
|
|
typedef atomic<intmax_t> atomic_intmax_t;
|
|
|
|
/// atomic_uintmax_t
|
|
typedef atomic<uintmax_t> atomic_uintmax_t;
|
|
|
|
// Function definitions, atomic_flag operations.
|
|
inline bool
|
|
atomic_flag_test_and_set_explicit(atomic_flag* __a,
|
|
memory_order __m) noexcept
|
|
{ return __a->test_and_set(__m); }
|
|
|
|
inline bool
|
|
atomic_flag_test_and_set_explicit(volatile atomic_flag* __a,
|
|
memory_order __m) noexcept
|
|
{ return __a->test_and_set(__m); }
|
|
|
|
#if __cpp_lib_atomic_flag_test
|
|
inline bool
|
|
atomic_flag_test(const atomic_flag* __a) noexcept
|
|
{ return __a->test(); }
|
|
|
|
inline bool
|
|
atomic_flag_test(const volatile atomic_flag* __a) noexcept
|
|
{ return __a->test(); }
|
|
|
|
inline bool
|
|
atomic_flag_test_explicit(const atomic_flag* __a,
|
|
memory_order __m) noexcept
|
|
{ return __a->test(__m); }
|
|
|
|
inline bool
|
|
atomic_flag_test_explicit(const volatile atomic_flag* __a,
|
|
memory_order __m) noexcept
|
|
{ return __a->test(__m); }
|
|
#endif
|
|
|
|
inline void
|
|
atomic_flag_clear_explicit(atomic_flag* __a, memory_order __m) noexcept
|
|
{ __a->clear(__m); }
|
|
|
|
inline void
|
|
atomic_flag_clear_explicit(volatile atomic_flag* __a,
|
|
memory_order __m) noexcept
|
|
{ __a->clear(__m); }
|
|
|
|
inline bool
|
|
atomic_flag_test_and_set(atomic_flag* __a) noexcept
|
|
{ return atomic_flag_test_and_set_explicit(__a, memory_order_seq_cst); }
|
|
|
|
inline bool
|
|
atomic_flag_test_and_set(volatile atomic_flag* __a) noexcept
|
|
{ return atomic_flag_test_and_set_explicit(__a, memory_order_seq_cst); }
|
|
|
|
inline void
|
|
atomic_flag_clear(atomic_flag* __a) noexcept
|
|
{ atomic_flag_clear_explicit(__a, memory_order_seq_cst); }
|
|
|
|
inline void
|
|
atomic_flag_clear(volatile atomic_flag* __a) noexcept
|
|
{ atomic_flag_clear_explicit(__a, memory_order_seq_cst); }
|
|
|
|
#if __cpp_lib_atomic_wait
|
|
inline void
|
|
atomic_flag_wait(atomic_flag* __a, bool __old) noexcept
|
|
{ __a->wait(__old); }
|
|
|
|
inline void
|
|
atomic_flag_wait_explicit(atomic_flag* __a, bool __old,
|
|
memory_order __m) noexcept
|
|
{ __a->wait(__old, __m); }
|
|
|
|
inline void
|
|
atomic_flag_notify_one(atomic_flag* __a) noexcept
|
|
{ __a->notify_one(); }
|
|
|
|
inline void
|
|
atomic_flag_notify_all(atomic_flag* __a) noexcept
|
|
{ __a->notify_all(); }
|
|
#endif // __cpp_lib_atomic_wait
|
|
|
|
/// @cond undocumented
|
|
// _GLIBCXX_RESOLVE_LIB_DEFECTS
|
|
// 3220. P0558 broke conforming C++14 uses of atomic shared_ptr
|
|
template<typename _Tp>
|
|
using __atomic_val_t = __type_identity_t<_Tp>;
|
|
template<typename _Tp>
|
|
using __atomic_diff_t = typename atomic<_Tp>::difference_type;
|
|
/// @endcond
|
|
|
|
// [atomics.nonmembers] Non-member functions.
|
|
// Function templates generally applicable to atomic types.
|
|
template<typename _ITp>
|
|
inline bool
|
|
atomic_is_lock_free(const atomic<_ITp>* __a) noexcept
|
|
{ return __a->is_lock_free(); }
|
|
|
|
template<typename _ITp>
|
|
inline bool
|
|
atomic_is_lock_free(const volatile atomic<_ITp>* __a) noexcept
|
|
{ return __a->is_lock_free(); }
|
|
|
|
template<typename _ITp>
|
|
inline void
|
|
atomic_init(atomic<_ITp>* __a, __atomic_val_t<_ITp> __i) noexcept
|
|
{ __a->store(__i, memory_order_relaxed); }
|
|
|
|
template<typename _ITp>
|
|
inline void
|
|
atomic_init(volatile atomic<_ITp>* __a, __atomic_val_t<_ITp> __i) noexcept
|
|
{ __a->store(__i, memory_order_relaxed); }
|
|
|
|
template<typename _ITp>
|
|
inline void
|
|
atomic_store_explicit(atomic<_ITp>* __a, __atomic_val_t<_ITp> __i,
|
|
memory_order __m) noexcept
|
|
{ __a->store(__i, __m); }
|
|
|
|
template<typename _ITp>
|
|
inline void
|
|
atomic_store_explicit(volatile atomic<_ITp>* __a, __atomic_val_t<_ITp> __i,
|
|
memory_order __m) noexcept
|
|
{ __a->store(__i, __m); }
|
|
|
|
template<typename _ITp>
|
|
inline _ITp
|
|
atomic_load_explicit(const atomic<_ITp>* __a, memory_order __m) noexcept
|
|
{ return __a->load(__m); }
|
|
|
|
template<typename _ITp>
|
|
inline _ITp
|
|
atomic_load_explicit(const volatile atomic<_ITp>* __a,
|
|
memory_order __m) noexcept
|
|
{ return __a->load(__m); }
|
|
|
|
template<typename _ITp>
|
|
inline _ITp
|
|
atomic_exchange_explicit(atomic<_ITp>* __a, __atomic_val_t<_ITp> __i,
|
|
memory_order __m) noexcept
|
|
{ return __a->exchange(__i, __m); }
|
|
|
|
template<typename _ITp>
|
|
inline _ITp
|
|
atomic_exchange_explicit(volatile atomic<_ITp>* __a,
|
|
__atomic_val_t<_ITp> __i,
|
|
memory_order __m) noexcept
|
|
{ return __a->exchange(__i, __m); }
|
|
|
|
template<typename _ITp>
|
|
inline bool
|
|
atomic_compare_exchange_weak_explicit(atomic<_ITp>* __a,
|
|
__atomic_val_t<_ITp>* __i1,
|
|
__atomic_val_t<_ITp> __i2,
|
|
memory_order __m1,
|
|
memory_order __m2) noexcept
|
|
{ return __a->compare_exchange_weak(*__i1, __i2, __m1, __m2); }
|
|
|
|
template<typename _ITp>
|
|
inline bool
|
|
atomic_compare_exchange_weak_explicit(volatile atomic<_ITp>* __a,
|
|
__atomic_val_t<_ITp>* __i1,
|
|
__atomic_val_t<_ITp> __i2,
|
|
memory_order __m1,
|
|
memory_order __m2) noexcept
|
|
{ return __a->compare_exchange_weak(*__i1, __i2, __m1, __m2); }
|
|
|
|
template<typename _ITp>
|
|
inline bool
|
|
atomic_compare_exchange_strong_explicit(atomic<_ITp>* __a,
|
|
__atomic_val_t<_ITp>* __i1,
|
|
__atomic_val_t<_ITp> __i2,
|
|
memory_order __m1,
|
|
memory_order __m2) noexcept
|
|
{ return __a->compare_exchange_strong(*__i1, __i2, __m1, __m2); }
|
|
|
|
template<typename _ITp>
|
|
inline bool
|
|
atomic_compare_exchange_strong_explicit(volatile atomic<_ITp>* __a,
|
|
__atomic_val_t<_ITp>* __i1,
|
|
__atomic_val_t<_ITp> __i2,
|
|
memory_order __m1,
|
|
memory_order __m2) noexcept
|
|
{ return __a->compare_exchange_strong(*__i1, __i2, __m1, __m2); }
|
|
|
|
|
|
template<typename _ITp>
|
|
inline void
|
|
atomic_store(atomic<_ITp>* __a, __atomic_val_t<_ITp> __i) noexcept
|
|
{ atomic_store_explicit(__a, __i, memory_order_seq_cst); }
|
|
|
|
template<typename _ITp>
|
|
inline void
|
|
atomic_store(volatile atomic<_ITp>* __a, __atomic_val_t<_ITp> __i) noexcept
|
|
{ atomic_store_explicit(__a, __i, memory_order_seq_cst); }
|
|
|
|
template<typename _ITp>
|
|
inline _ITp
|
|
atomic_load(const atomic<_ITp>* __a) noexcept
|
|
{ return atomic_load_explicit(__a, memory_order_seq_cst); }
|
|
|
|
template<typename _ITp>
|
|
inline _ITp
|
|
atomic_load(const volatile atomic<_ITp>* __a) noexcept
|
|
{ return atomic_load_explicit(__a, memory_order_seq_cst); }
|
|
|
|
template<typename _ITp>
|
|
inline _ITp
|
|
atomic_exchange(atomic<_ITp>* __a, __atomic_val_t<_ITp> __i) noexcept
|
|
{ return atomic_exchange_explicit(__a, __i, memory_order_seq_cst); }
|
|
|
|
template<typename _ITp>
|
|
inline _ITp
|
|
atomic_exchange(volatile atomic<_ITp>* __a,
|
|
__atomic_val_t<_ITp> __i) noexcept
|
|
{ return atomic_exchange_explicit(__a, __i, memory_order_seq_cst); }
|
|
|
|
template<typename _ITp>
|
|
inline bool
|
|
atomic_compare_exchange_weak(atomic<_ITp>* __a,
|
|
__atomic_val_t<_ITp>* __i1,
|
|
__atomic_val_t<_ITp> __i2) noexcept
|
|
{
|
|
return atomic_compare_exchange_weak_explicit(__a, __i1, __i2,
|
|
memory_order_seq_cst,
|
|
memory_order_seq_cst);
|
|
}
|
|
|
|
template<typename _ITp>
|
|
inline bool
|
|
atomic_compare_exchange_weak(volatile atomic<_ITp>* __a,
|
|
__atomic_val_t<_ITp>* __i1,
|
|
__atomic_val_t<_ITp> __i2) noexcept
|
|
{
|
|
return atomic_compare_exchange_weak_explicit(__a, __i1, __i2,
|
|
memory_order_seq_cst,
|
|
memory_order_seq_cst);
|
|
}
|
|
|
|
template<typename _ITp>
|
|
inline bool
|
|
atomic_compare_exchange_strong(atomic<_ITp>* __a,
|
|
__atomic_val_t<_ITp>* __i1,
|
|
__atomic_val_t<_ITp> __i2) noexcept
|
|
{
|
|
return atomic_compare_exchange_strong_explicit(__a, __i1, __i2,
|
|
memory_order_seq_cst,
|
|
memory_order_seq_cst);
|
|
}
|
|
|
|
template<typename _ITp>
|
|
inline bool
|
|
atomic_compare_exchange_strong(volatile atomic<_ITp>* __a,
|
|
__atomic_val_t<_ITp>* __i1,
|
|
__atomic_val_t<_ITp> __i2) noexcept
|
|
{
|
|
return atomic_compare_exchange_strong_explicit(__a, __i1, __i2,
|
|
memory_order_seq_cst,
|
|
memory_order_seq_cst);
|
|
}
|
|
|
|
|
|
#if __cpp_lib_atomic_wait
|
|
template<typename _Tp>
|
|
inline void
|
|
atomic_wait(const atomic<_Tp>* __a,
|
|
typename std::atomic<_Tp>::value_type __old) noexcept
|
|
{ __a->wait(__old); }
|
|
|
|
template<typename _Tp>
|
|
inline void
|
|
atomic_wait_explicit(const atomic<_Tp>* __a,
|
|
typename std::atomic<_Tp>::value_type __old,
|
|
std::memory_order __m) noexcept
|
|
{ __a->wait(__old, __m); }
|
|
|
|
template<typename _Tp>
|
|
inline void
|
|
atomic_notify_one(atomic<_Tp>* __a) noexcept
|
|
{ __a->notify_one(); }
|
|
|
|
template<typename _Tp>
|
|
inline void
|
|
atomic_notify_all(atomic<_Tp>* __a) noexcept
|
|
{ __a->notify_all(); }
|
|
#endif // __cpp_lib_atomic_wait
|
|
|
|
// Function templates for atomic_integral and atomic_pointer operations only.
|
|
// Some operations (and, or, xor) are only available for atomic integrals,
|
|
// which is implemented by taking a parameter of type __atomic_base<_ITp>*.
|
|
|
|
template<typename _ITp>
|
|
inline _ITp
|
|
atomic_fetch_add_explicit(atomic<_ITp>* __a,
|
|
__atomic_diff_t<_ITp> __i,
|
|
memory_order __m) noexcept
|
|
{ return __a->fetch_add(__i, __m); }
|
|
|
|
template<typename _ITp>
|
|
inline _ITp
|
|
atomic_fetch_add_explicit(volatile atomic<_ITp>* __a,
|
|
__atomic_diff_t<_ITp> __i,
|
|
memory_order __m) noexcept
|
|
{ return __a->fetch_add(__i, __m); }
|
|
|
|
template<typename _ITp>
|
|
inline _ITp
|
|
atomic_fetch_sub_explicit(atomic<_ITp>* __a,
|
|
__atomic_diff_t<_ITp> __i,
|
|
memory_order __m) noexcept
|
|
{ return __a->fetch_sub(__i, __m); }
|
|
|
|
template<typename _ITp>
|
|
inline _ITp
|
|
atomic_fetch_sub_explicit(volatile atomic<_ITp>* __a,
|
|
__atomic_diff_t<_ITp> __i,
|
|
memory_order __m) noexcept
|
|
{ return __a->fetch_sub(__i, __m); }
|
|
|
|
template<typename _ITp>
|
|
inline _ITp
|
|
atomic_fetch_and_explicit(__atomic_base<_ITp>* __a,
|
|
__atomic_val_t<_ITp> __i,
|
|
memory_order __m) noexcept
|
|
{ return __a->fetch_and(__i, __m); }
|
|
|
|
template<typename _ITp>
|
|
inline _ITp
|
|
atomic_fetch_and_explicit(volatile __atomic_base<_ITp>* __a,
|
|
__atomic_val_t<_ITp> __i,
|
|
memory_order __m) noexcept
|
|
{ return __a->fetch_and(__i, __m); }
|
|
|
|
template<typename _ITp>
|
|
inline _ITp
|
|
atomic_fetch_or_explicit(__atomic_base<_ITp>* __a,
|
|
__atomic_val_t<_ITp> __i,
|
|
memory_order __m) noexcept
|
|
{ return __a->fetch_or(__i, __m); }
|
|
|
|
template<typename _ITp>
|
|
inline _ITp
|
|
atomic_fetch_or_explicit(volatile __atomic_base<_ITp>* __a,
|
|
__atomic_val_t<_ITp> __i,
|
|
memory_order __m) noexcept
|
|
{ return __a->fetch_or(__i, __m); }
|
|
|
|
template<typename _ITp>
|
|
inline _ITp
|
|
atomic_fetch_xor_explicit(__atomic_base<_ITp>* __a,
|
|
__atomic_val_t<_ITp> __i,
|
|
memory_order __m) noexcept
|
|
{ return __a->fetch_xor(__i, __m); }
|
|
|
|
template<typename _ITp>
|
|
inline _ITp
|
|
atomic_fetch_xor_explicit(volatile __atomic_base<_ITp>* __a,
|
|
__atomic_val_t<_ITp> __i,
|
|
memory_order __m) noexcept
|
|
{ return __a->fetch_xor(__i, __m); }
|
|
|
|
#ifdef __cpp_lib_atomic_min_max
|
|
template<typename _ITp>
|
|
inline _ITp
|
|
atomic_fetch_min_explicit(__atomic_base<_ITp>* __a,
|
|
__atomic_val_t<_ITp> __i,
|
|
memory_order __m) noexcept
|
|
{ return __a->fetch_min(__i, __m); }
|
|
|
|
template<typename _ITp>
|
|
inline _ITp
|
|
atomic_fetch_min_explicit(volatile __atomic_base<_ITp>* __a,
|
|
__atomic_val_t<_ITp> __i,
|
|
memory_order __m) noexcept
|
|
{ return __a->fetch_min(__i, __m); }
|
|
|
|
template<typename _ITp>
|
|
inline _ITp
|
|
atomic_fetch_max_explicit(__atomic_base<_ITp>* __a,
|
|
__atomic_val_t<_ITp> __i,
|
|
memory_order __m) noexcept
|
|
{ return __a->fetch_max(__i, __m); }
|
|
|
|
template<typename _ITp>
|
|
inline _ITp
|
|
atomic_fetch_max_explicit(volatile __atomic_base<_ITp>* __a,
|
|
__atomic_val_t<_ITp> __i,
|
|
memory_order __m) noexcept
|
|
{ return __a->fetch_max(__i, __m); }
|
|
#endif
|
|
|
|
template<typename _ITp>
|
|
inline _ITp
|
|
atomic_fetch_add(atomic<_ITp>* __a,
|
|
__atomic_diff_t<_ITp> __i) noexcept
|
|
{ return atomic_fetch_add_explicit(__a, __i, memory_order_seq_cst); }
|
|
|
|
template<typename _ITp>
|
|
inline _ITp
|
|
atomic_fetch_add(volatile atomic<_ITp>* __a,
|
|
__atomic_diff_t<_ITp> __i) noexcept
|
|
{ return atomic_fetch_add_explicit(__a, __i, memory_order_seq_cst); }
|
|
|
|
template<typename _ITp>
|
|
inline _ITp
|
|
atomic_fetch_sub(atomic<_ITp>* __a,
|
|
__atomic_diff_t<_ITp> __i) noexcept
|
|
{ return atomic_fetch_sub_explicit(__a, __i, memory_order_seq_cst); }
|
|
|
|
template<typename _ITp>
|
|
inline _ITp
|
|
atomic_fetch_sub(volatile atomic<_ITp>* __a,
|
|
__atomic_diff_t<_ITp> __i) noexcept
|
|
{ return atomic_fetch_sub_explicit(__a, __i, memory_order_seq_cst); }
|
|
|
|
template<typename _ITp>
|
|
inline _ITp
|
|
atomic_fetch_and(__atomic_base<_ITp>* __a,
|
|
__atomic_val_t<_ITp> __i) noexcept
|
|
{ return atomic_fetch_and_explicit(__a, __i, memory_order_seq_cst); }
|
|
|
|
template<typename _ITp>
|
|
inline _ITp
|
|
atomic_fetch_and(volatile __atomic_base<_ITp>* __a,
|
|
__atomic_val_t<_ITp> __i) noexcept
|
|
{ return atomic_fetch_and_explicit(__a, __i, memory_order_seq_cst); }
|
|
|
|
template<typename _ITp>
|
|
inline _ITp
|
|
atomic_fetch_or(__atomic_base<_ITp>* __a,
|
|
__atomic_val_t<_ITp> __i) noexcept
|
|
{ return atomic_fetch_or_explicit(__a, __i, memory_order_seq_cst); }
|
|
|
|
template<typename _ITp>
|
|
inline _ITp
|
|
atomic_fetch_or(volatile __atomic_base<_ITp>* __a,
|
|
__atomic_val_t<_ITp> __i) noexcept
|
|
{ return atomic_fetch_or_explicit(__a, __i, memory_order_seq_cst); }
|
|
|
|
template<typename _ITp>
|
|
inline _ITp
|
|
atomic_fetch_xor(__atomic_base<_ITp>* __a,
|
|
__atomic_val_t<_ITp> __i) noexcept
|
|
{ return atomic_fetch_xor_explicit(__a, __i, memory_order_seq_cst); }
|
|
|
|
template<typename _ITp>
|
|
inline _ITp
|
|
atomic_fetch_xor(volatile __atomic_base<_ITp>* __a,
|
|
__atomic_val_t<_ITp> __i) noexcept
|
|
{ return atomic_fetch_xor_explicit(__a, __i, memory_order_seq_cst); }
|
|
|
|
#ifdef __cpp_lib_atomic_min_max
|
|
template<typename _ITp>
|
|
inline _ITp
|
|
atomic_fetch_min(__atomic_base<_ITp>* __a,
|
|
__atomic_val_t<_ITp> __i) noexcept
|
|
{ return atomic_fetch_min_explicit(__a, __i, memory_order_seq_cst); }
|
|
|
|
template<typename _ITp>
|
|
inline _ITp
|
|
atomic_fetch_min(volatile __atomic_base<_ITp>* __a,
|
|
__atomic_val_t<_ITp> __i) noexcept
|
|
{ return atomic_fetch_min_explicit(__a, __i, memory_order_seq_cst); }
|
|
|
|
template<typename _ITp>
|
|
inline _ITp
|
|
atomic_fetch_max(__atomic_base<_ITp>* __a,
|
|
__atomic_val_t<_ITp> __i) noexcept
|
|
{ return atomic_fetch_max_explicit(__a, __i, memory_order_seq_cst); }
|
|
|
|
template<typename _ITp>
|
|
inline _ITp
|
|
atomic_fetch_max(volatile __atomic_base<_ITp>* __a,
|
|
__atomic_val_t<_ITp> __i) noexcept
|
|
{ return atomic_fetch_max_explicit(__a, __i, memory_order_seq_cst); }
|
|
#endif
|
|
|
|
#ifdef __cpp_lib_atomic_float
|
|
template<>
|
|
struct atomic<float> : __atomic_float<float>
|
|
{
|
|
atomic() noexcept = default;
|
|
|
|
constexpr
|
|
atomic(float __fp) noexcept : __atomic_float<float>(__fp)
|
|
{ }
|
|
|
|
atomic& operator=(const atomic&) volatile = delete;
|
|
atomic& operator=(const atomic&) = delete;
|
|
|
|
using __atomic_float<float>::operator=;
|
|
};
|
|
|
|
template<>
|
|
struct atomic<double> : __atomic_float<double>
|
|
{
|
|
atomic() noexcept = default;
|
|
|
|
constexpr
|
|
atomic(double __fp) noexcept : __atomic_float<double>(__fp)
|
|
{ }
|
|
|
|
atomic& operator=(const atomic&) volatile = delete;
|
|
atomic& operator=(const atomic&) = delete;
|
|
|
|
using __atomic_float<double>::operator=;
|
|
};
|
|
|
|
template<>
|
|
struct atomic<long double> : __atomic_float<long double>
|
|
{
|
|
atomic() noexcept = default;
|
|
|
|
constexpr
|
|
atomic(long double __fp) noexcept : __atomic_float<long double>(__fp)
|
|
{ }
|
|
|
|
atomic& operator=(const atomic&) volatile = delete;
|
|
atomic& operator=(const atomic&) = delete;
|
|
|
|
using __atomic_float<long double>::operator=;
|
|
};
|
|
|
|
#ifdef __STDCPP_FLOAT16_T__
|
|
template<>
|
|
struct atomic<_Float16> : __atomic_float<_Float16>
|
|
{
|
|
atomic() noexcept = default;
|
|
|
|
constexpr
|
|
atomic(_Float16 __fp) noexcept : __atomic_float<_Float16>(__fp)
|
|
{ }
|
|
|
|
atomic& operator=(const atomic&) volatile = delete;
|
|
atomic& operator=(const atomic&) = delete;
|
|
|
|
using __atomic_float<_Float16>::operator=;
|
|
};
|
|
#endif
|
|
|
|
#ifdef __STDCPP_FLOAT32_T__
|
|
template<>
|
|
struct atomic<_Float32> : __atomic_float<_Float32>
|
|
{
|
|
atomic() noexcept = default;
|
|
|
|
constexpr
|
|
atomic(_Float32 __fp) noexcept : __atomic_float<_Float32>(__fp)
|
|
{ }
|
|
|
|
atomic& operator=(const atomic&) volatile = delete;
|
|
atomic& operator=(const atomic&) = delete;
|
|
|
|
using __atomic_float<_Float32>::operator=;
|
|
};
|
|
#endif
|
|
|
|
#ifdef __STDCPP_FLOAT64_T__
|
|
template<>
|
|
struct atomic<_Float64> : __atomic_float<_Float64>
|
|
{
|
|
atomic() noexcept = default;
|
|
|
|
constexpr
|
|
atomic(_Float64 __fp) noexcept : __atomic_float<_Float64>(__fp)
|
|
{ }
|
|
|
|
atomic& operator=(const atomic&) volatile = delete;
|
|
atomic& operator=(const atomic&) = delete;
|
|
|
|
using __atomic_float<_Float64>::operator=;
|
|
};
|
|
#endif
|
|
|
|
#ifdef __STDCPP_FLOAT128_T__
|
|
template<>
|
|
struct atomic<_Float128> : __atomic_float<_Float128>
|
|
{
|
|
atomic() noexcept = default;
|
|
|
|
constexpr
|
|
atomic(_Float128 __fp) noexcept : __atomic_float<_Float128>(__fp)
|
|
{ }
|
|
|
|
atomic& operator=(const atomic&) volatile = delete;
|
|
atomic& operator=(const atomic&) = delete;
|
|
|
|
using __atomic_float<_Float128>::operator=;
|
|
};
|
|
#endif
|
|
|
|
#ifdef __STDCPP_BFLOAT16_T__
|
|
template<>
|
|
struct atomic<__gnu_cxx::__bfloat16_t> : __atomic_float<__gnu_cxx::__bfloat16_t>
|
|
{
|
|
atomic() noexcept = default;
|
|
|
|
constexpr
|
|
atomic(__gnu_cxx::__bfloat16_t __fp) noexcept : __atomic_float<__gnu_cxx::__bfloat16_t>(__fp)
|
|
{ }
|
|
|
|
atomic& operator=(const atomic&) volatile = delete;
|
|
atomic& operator=(const atomic&) = delete;
|
|
|
|
using __atomic_float<__gnu_cxx::__bfloat16_t>::operator=;
|
|
};
|
|
#endif
|
|
#endif // __cpp_lib_atomic_float
|
|
|
|
#ifdef __cpp_lib_atomic_ref
|
|
/// Class template to provide atomic operations on a non-atomic variable.
|
|
template<typename _Tp>
|
|
struct atomic_ref : __atomic_ref<_Tp>
|
|
{
|
|
explicit
|
|
atomic_ref(_Tp& __t) noexcept
|
|
: __atomic_ref<_Tp>(std::addressof(__t))
|
|
{
|
|
__glibcxx_assert(((__UINTPTR_TYPE__)this->_M_ptr % this->required_alignment) == 0);
|
|
}
|
|
|
|
// _GLIBCXX_RESOLVE_LIB_DEFECTS
|
|
// 4472. std::atomic_ref<const T> can be constructed from temporaries
|
|
explicit
|
|
atomic_ref(_Tp&&) = delete;
|
|
|
|
template<typename _Up>
|
|
requires is_convertible_v<_Up(*)[1], _Tp(*)[1]>
|
|
atomic_ref(atomic_ref<_Up> __other) noexcept
|
|
: __atomic_ref<_Tp>(__other._M_ptr)
|
|
{ }
|
|
|
|
atomic_ref& operator=(const atomic_ref&) = delete;
|
|
|
|
atomic_ref(const atomic_ref&) = default;
|
|
|
|
using __atomic_ref<_Tp>::operator=;
|
|
|
|
template<typename>
|
|
friend struct atomic_ref;
|
|
};
|
|
#endif // __cpp_lib_atomic_ref
|
|
|
|
#ifdef __cpp_lib_atomic_lock_free_type_aliases
|
|
# ifdef _GLIBCXX_HAVE_PLATFORM_WAIT
|
|
using atomic_signed_lock_free
|
|
= atomic<make_signed_t<__detail::__platform_wait_t>>;
|
|
using atomic_unsigned_lock_free
|
|
= atomic<make_unsigned_t<__detail::__platform_wait_t>>;
|
|
# elif ATOMIC_INT_LOCK_FREE == 2
|
|
using atomic_signed_lock_free = atomic<signed int>;
|
|
using atomic_unsigned_lock_free = atomic<unsigned int>;
|
|
# elif ATOMIC_LONG_LOCK_FREE == 2
|
|
using atomic_signed_lock_free = atomic<signed long>;
|
|
using atomic_unsigned_lock_free = atomic<unsigned long>;
|
|
# elif ATOMIC_CHAR_LOCK_FREE == 2
|
|
using atomic_signed_lock_free = atomic<signed char>;
|
|
using atomic_unsigned_lock_free = atomic<unsigned char>;
|
|
# else
|
|
# error "libstdc++ bug: no lock-free atomics but they were emitted in <version>"
|
|
# endif
|
|
#endif
|
|
|
|
/// @} group atomics
|
|
|
|
_GLIBCXX_END_NAMESPACE_VERSION
|
|
} // namespace
|
|
|
|
#endif // C++11
|
|
|
|
#endif // _GLIBCXX_ATOMIC
|