mirror of
https://github.com/gcc-mirror/gcc.git
synced 2026-05-06 23:25:24 +02:00
The following patch is partial support for std::float{16,32,64,128}_t
and std::bfloat16_t in libstdc++.
https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2022/p1467r9.html
says that <ostream>, <istream>, <charconv> and <complex>
need changes toom, but that isn't implemented so far.
In <cmath> the only thing missing I'm aware of is
std::nextafter std::float16_t and std::bfloat16_t overloads (I think
we probably need to implement that out of line somewhere, or inline? - might
need inline asm barriers) and std::nexttoward overloads (those are
intentional, you said there is a LWG issue about that).
Also, this patch has the glibc 2.26+ std::float128_t support for platforms
where long double isn't IEEE quad format temporarily disabled
because it depends on
https://gcc.gnu.org/pipermail/gcc-patches/2022-October/603665.html
changes which aren't in yet.
The patch also doesn't include any testcases to cover the <type_traits>
changes, it isn't clear to me where to put that.
2022-10-18 Jakub Jelinek <jakub@redhat.com>
PR c++/106652
* include/std/stdfloat: New file.
* include/std/numbers (__glibcxx_numbers): Define and use it
for __float128 explicit instantiations as well as
_Float{16,32,64,128} and __gnu_cxx::__bfloat16_t.
* include/std/atomic (atomic<_Float16>, atomic<_Float32>,
atomic<_Float64>, atomic<_Float128>, atomic<__gnu_cxx::__bfloat16_t>):
New explicit instantiations.
* include/std/type_traits (__is_floating_point_helper<_Float16>,
__is_floating_point_helper<_Float32>,
__is_floating_point_helper<_Float64>,
__is_floating_point_helper<_Float128>,
__is_floating_point_helper<__gnu_cxx::__bfloat16_t>): Likewise.
* include/std/limits (__glibcxx_concat3_, __glibcxx_concat3,
__glibcxx_float_n): Define.
(numeric_limits<_Float16>, numeric_limits<_Float32>,
numeric_limits<_Float64>, numeric_limits<_Float128>,
numeric_limits<__gnu_cxx::__bfloat16_t>): New explicit instantiations.
* include/bits/std_abs.h (abs): New overloads for
_Float{16,32,64,128} and __gnu_cxx::__bfloat16_t.
* include/bits/c++config (_GLIBCXX_LDOUBLE_IS_IEEE_BINARY128): Define
if long double is IEEE quad.
(__gnu_cxx::__bfloat16_t): New using.
* include/c_global/cmath (acos, asin, atan, atan2, ceil, cos, cosh,
exp, fabs, floor, fmod, frexp, ldexp, log, log10, modf, pow, sin,
sinh, sqrt, tan, tanh, fpclassify, isfinite, isinf, isnan, isnormal,
signbit, isgreater, isgreaterequal, isless, islessequal,
islessgreater, isunordered, acosh, asinh, atanh, cbrt, copysign, erf,
erfc, exp2, expm1, fdim, fma, fmax, fmin, hypot, ilogb, lgamma,
llrint, llround, log1p, log2, logb, lrint, lround, nearbyint,
nextafter, remainder, rint, round, scalbln, scalbn, tgamma, trunc,
lerp): New overloads with _Float{16,32,64,128} or
__gnu_cxx::__bfloat16_t types.
* config/os/gnu-linux/os_defines.h (_GLIBCXX_HAVE_FLOAT128_MATH):
Prepare for definition if glibc 2.26 and later implements *f128 APIs
but comment out the actual definition for now.
* include/ext/type_traits.h (__promote<_Float16>, __promote<_Float32>,
__promote<_Float64>, __promote<_Float128>,
__promote<__gnu_cxx::__bfloat16_t>): New specializations.
* include/Makefile.am (std_headers): Add stdfloat.
* include/Makefile.in: Regenerated.
* include/precompiled/stdc++.h: Include stdfloat.
* testsuite/18_support/headers/stdfloat/types_std.cc: New test.
* testsuite/18_support/headers/limits/synopsis_cxx23.cc: New test.
* testsuite/26_numerics/headers/cmath/c99_classification_macros_c++23.cc:
New test.
* testsuite/26_numerics/headers/cmath/functions_std_c++23.cc: New test.
* testsuite/26_numerics/numbers/4.cc: New test.
* testsuite/29_atomics/atomic_float/requirements_cxx23.cc: New test.
1740 lines
49 KiB
C++
1740 lines
49 KiB
C++
// -*- C++ -*- header.
|
|
|
|
// Copyright (C) 2008-2022 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
|
|
|
|
#pragma GCC system_header
|
|
|
|
#if __cplusplus < 201103L
|
|
# include <bits/c++0x_warning.h>
|
|
#else
|
|
|
|
#include <bits/atomic_base.h>
|
|
|
|
namespace std _GLIBCXX_VISIBILITY(default)
|
|
{
|
|
_GLIBCXX_BEGIN_NAMESPACE_VERSION
|
|
|
|
/**
|
|
* @addtogroup atomics
|
|
* @{
|
|
*/
|
|
|
|
#if __cplusplus >= 201703L
|
|
# define __cpp_lib_atomic_is_always_lock_free 201603L
|
|
#endif
|
|
|
|
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(); }
|
|
|
|
#if __cplusplus >= 201703L
|
|
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
|
|
};
|
|
|
|
/// @cond undocumented
|
|
#if __cpp_lib_atomic_value_initialization
|
|
# define _GLIBCXX20_INIT(I) = I
|
|
#else
|
|
# define _GLIBCXX20_INIT(I)
|
|
#endif
|
|
/// @endcond
|
|
|
|
/**
|
|
* @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 _GLIBCXX20_INIT(_Tp());
|
|
|
|
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");
|
|
|
|
#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:
|
|
atomic() = default;
|
|
~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>())
|
|
__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));
|
|
}
|
|
|
|
#if __cplusplus >= 201703L
|
|
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
|
|
void
|
|
wait(_Tp __old, memory_order __m = memory_order_seq_cst) const noexcept
|
|
{
|
|
std::__atomic_wait_address_v(&_M_i, __old,
|
|
[__m, this] { return this->load(__m); });
|
|
}
|
|
|
|
// TODO add const volatile overload
|
|
|
|
void
|
|
notify_one() noexcept
|
|
{ std::__atomic_notify_address(&_M_i, false); }
|
|
|
|
void
|
|
notify_all() noexcept
|
|
{ std::__atomic_notify_address(&_M_i, true); }
|
|
#endif // __cpp_lib_atomic_wait
|
|
|
|
};
|
|
#undef _GLIBCXX20_INIT
|
|
|
|
/// 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<_Tp>::value, "pointer to object type" );
|
|
#endif
|
|
return _M_b++;
|
|
}
|
|
|
|
__pointer_type
|
|
operator++(int) volatile noexcept
|
|
{
|
|
#if __cplusplus >= 201703L
|
|
static_assert( is_object<_Tp>::value, "pointer to object type" );
|
|
#endif
|
|
return _M_b++;
|
|
}
|
|
|
|
__pointer_type
|
|
operator--(int) noexcept
|
|
{
|
|
#if __cplusplus >= 201703L
|
|
static_assert( is_object<_Tp>::value, "pointer to object type" );
|
|
#endif
|
|
return _M_b--;
|
|
}
|
|
|
|
__pointer_type
|
|
operator--(int) volatile noexcept
|
|
{
|
|
#if __cplusplus >= 201703L
|
|
static_assert( is_object<_Tp>::value, "pointer to object type" );
|
|
#endif
|
|
return _M_b--;
|
|
}
|
|
|
|
__pointer_type
|
|
operator++() noexcept
|
|
{
|
|
#if __cplusplus >= 201703L
|
|
static_assert( is_object<_Tp>::value, "pointer to object type" );
|
|
#endif
|
|
return ++_M_b;
|
|
}
|
|
|
|
__pointer_type
|
|
operator++() volatile noexcept
|
|
{
|
|
#if __cplusplus >= 201703L
|
|
static_assert( is_object<_Tp>::value, "pointer to object type" );
|
|
#endif
|
|
return ++_M_b;
|
|
}
|
|
|
|
__pointer_type
|
|
operator--() noexcept
|
|
{
|
|
#if __cplusplus >= 201703L
|
|
static_assert( is_object<_Tp>::value, "pointer to object type" );
|
|
#endif
|
|
return --_M_b;
|
|
}
|
|
|
|
__pointer_type
|
|
operator--() volatile noexcept
|
|
{
|
|
#if __cplusplus >= 201703L
|
|
static_assert( is_object<_Tp>::value, "pointer to object type" );
|
|
#endif
|
|
return --_M_b;
|
|
}
|
|
|
|
__pointer_type
|
|
operator+=(ptrdiff_t __d) noexcept
|
|
{
|
|
#if __cplusplus >= 201703L
|
|
static_assert( is_object<_Tp>::value, "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<_Tp>::value, "pointer to object type" );
|
|
#endif
|
|
return _M_b.operator+=(__d);
|
|
}
|
|
|
|
__pointer_type
|
|
operator-=(ptrdiff_t __d) noexcept
|
|
{
|
|
#if __cplusplus >= 201703L
|
|
static_assert( is_object<_Tp>::value, "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<_Tp>::value, "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(); }
|
|
|
|
#if __cplusplus >= 201703L
|
|
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<_Tp>::value, "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<_Tp>::value, "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<_Tp>::value, "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<_Tp>::value, "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=;
|
|
|
|
#if __cplusplus >= 201703L
|
|
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=;
|
|
|
|
#if __cplusplus >= 201703L
|
|
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=;
|
|
|
|
#if __cplusplus >= 201703L
|
|
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=;
|
|
|
|
#if __cplusplus >= 201703L
|
|
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=;
|
|
|
|
#if __cplusplus >= 201703L
|
|
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=;
|
|
|
|
#if __cplusplus >= 201703L
|
|
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=;
|
|
|
|
#if __cplusplus >= 201703L
|
|
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=;
|
|
|
|
#if __cplusplus >= 201703L
|
|
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=;
|
|
|
|
#if __cplusplus >= 201703L
|
|
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=;
|
|
|
|
#if __cplusplus >= 201703L
|
|
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=;
|
|
|
|
#if __cplusplus >= 201703L
|
|
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=;
|
|
|
|
#if __cplusplus >= 201703L
|
|
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=;
|
|
|
|
#if __cplusplus > 201402L
|
|
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=;
|
|
|
|
#if __cplusplus >= 201703L
|
|
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=;
|
|
|
|
#if __cplusplus >= 201703L
|
|
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_TR1
|
|
// _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;
|
|
|
|
|
|
/// 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;
|
|
#endif
|
|
|
|
|
|
/// 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;
|
|
|
|
#ifdef _GLIBCXX_USE_C99_STDINT_TR1
|
|
/// atomic_intmax_t
|
|
typedef atomic<intmax_t> atomic_intmax_t;
|
|
|
|
/// atomic_uintmax_t
|
|
typedef atomic<uintmax_t> atomic_uintmax_t;
|
|
#endif
|
|
|
|
// 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); }
|
|
|
|
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); }
|
|
|
|
/// @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); }
|
|
|
|
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); }
|
|
|
|
#if __cplusplus > 201703L
|
|
#define __cpp_lib_atomic_float 201711L
|
|
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
|
|
|
|
#define __cpp_lib_atomic_ref 201806L
|
|
|
|
/// 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>(__t)
|
|
{ }
|
|
|
|
atomic_ref& operator=(const atomic_ref&) = delete;
|
|
|
|
atomic_ref(const atomic_ref&) = default;
|
|
|
|
using __atomic_ref<_Tp>::operator=;
|
|
};
|
|
|
|
#endif // C++2a
|
|
|
|
/// @} group atomics
|
|
|
|
_GLIBCXX_END_NAMESPACE_VERSION
|
|
} // namespace
|
|
|
|
#endif // C++11
|
|
|
|
#endif // _GLIBCXX_ATOMIC
|