Commit a90fe12c by Jonathan Wakely Committed by Jonathan Wakely

Define std::atomic_ref and std::atomic<floating-point> for C++20

This adds the new atomic types from C++2a, as proposed by P0019 and
P0020. To reduce duplication the calls to the compiler's atomic
built-ins are wrapped in new functions in the __atomic_impl namespace.
These functions are currently only used by std::atomic<floating-point>
and std::atomic_ref but could also be used for all other specializations
of std::atomic.

	* include/bits/atomic_base.h (__atomic_impl): New namespace for
	wrappers around atomic built-ins.
	(__atomic_float, __atomic_ref): New class templates for use as base
	classes.
	* include/std/atomic (atomic<float>, atomic<double>)
	(atomic<long double>): New explicit specializations.
	(atomic_ref): New class template.
	(__cpp_lib_atomic_ref): Define.
	* include/std/version (__cpp_lib_atomic_ref): Define.
	* testsuite/29_atomics/atomic/60695.cc: Adjust dg-error.
    	* testsuite/29_atomics/atomic_float/1.cc: New test.
    	* testsuite/29_atomics/atomic_float/requirements.cc: New test.
    	* testsuite/29_atomics/atomic_ref/deduction.cc: New test.
    	* testsuite/29_atomics/atomic_ref/float.cc: New test.
    	* testsuite/29_atomics/atomic_ref/generic.cc: New test.
    	* testsuite/29_atomics/atomic_ref/integral.cc: New test.
    	* testsuite/29_atomics/atomic_ref/pointer.cc: New test.
    	* testsuite/29_atomics/atomic_ref/requirements.cc: New test.

From-SVN: r273420
parent 4c98bdad
2019-07-11 Jonathan Wakely <jwakely@redhat.com>
* include/bits/atomic_base.h (__atomic_impl): New namespace for
wrappers around atomic built-ins.
(__atomic_float, __atomic_ref): New class templates for use as base
classes.
* include/std/atomic (atomic<float>, atomic<double>)
(atomic<long double>): New explicit specializations.
(atomic_ref): New class template.
(__cpp_lib_atomic_ref): Define.
* include/std/version (__cpp_lib_atomic_ref): Define.
* testsuite/29_atomics/atomic/60695.cc: Adjust dg-error.
* testsuite/29_atomics/atomic_float/1.cc: New test.
* testsuite/29_atomics/atomic_float/requirements.cc: New test.
* testsuite/29_atomics/atomic_ref/deduction.cc: New test.
* testsuite/29_atomics/atomic_ref/float.cc: New test.
* testsuite/29_atomics/atomic_ref/generic.cc: New test.
* testsuite/29_atomics/atomic_ref/integral.cc: New test.
* testsuite/29_atomics/atomic_ref/pointer.cc: New test.
* testsuite/29_atomics/atomic_ref/requirements.cc: New test.
2019-07-06 Jonathan Wakely <jwakely@redhat.com>
* include/ext/atomicity.h (__exchange_and_add, __atomic_add): Replace
......
......@@ -39,7 +39,6 @@
#else
#include <bits/atomic_base.h>
#include <bits/move.h>
namespace std _GLIBCXX_VISIBILITY(default)
{
......@@ -1472,6 +1471,71 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
__atomic_val_t<_ITp> __i) noexcept
{ return atomic_fetch_xor_explicit(__a, __i, memory_order_seq_cst); }
#if __cplusplus > 201703L
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=;
};
#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
......
......@@ -150,6 +150,7 @@
#if __cplusplus > 201703L
// c++2a
#define __cpp_lib_atomic_ref 201806L
#define __cpp_lib_bind_front 201902L
#define __cpp_lib_bounded_array_traits 201902L
#if __cpp_impl_destroying_delete
......
......@@ -27,4 +27,4 @@ struct X {
char stuff[0]; // GNU extension, type has zero size
};
std::atomic<X> a; // { dg-error "not supported" "" { target *-*-* } 194 }
std::atomic<X> a; // { dg-error "zero-sized types" "" { target *-*-* } 0 }
// Copyright (C) 2019 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.
// You should have received a copy of the GNU General Public License along
// with this library; see the file COPYING3. If not see
// <http://www.gnu.org/licenses/>.
// { dg-options "-std=gnu++2a" }
// { dg-do compile { target c++2a } }
#include <atomic>
void
test01()
{
using A = std::atomic<float>;
static_assert( std::is_standard_layout_v<A> );
static_assert( std::is_trivially_default_constructible_v<A> );
static_assert( std::is_trivially_destructible_v<A> );
static_assert( std::is_same_v<A::value_type, float> );
static_assert( std::is_same_v<A::difference_type, A::value_type> );
static_assert( !std::is_copy_constructible_v<A> );
static_assert( !std::is_move_constructible_v<A> );
static_assert( !std::is_copy_assignable_v<A> );
static_assert( !std::is_move_assignable_v<A> );
static_assert( !std::is_assignable_v<volatile A&, const A&> );
}
void
test02()
{
using A = std::atomic<double>;
static_assert( std::is_standard_layout_v<A> );
static_assert( std::is_trivially_default_constructible_v<A> );
static_assert( std::is_trivially_destructible_v<A> );
static_assert( std::is_same_v<A::value_type, double> );
static_assert( std::is_same_v<A::difference_type, A::value_type> );
static_assert( !std::is_copy_constructible_v<A> );
static_assert( !std::is_move_constructible_v<A> );
static_assert( !std::is_copy_assignable_v<A> );
static_assert( !std::is_move_assignable_v<A> );
static_assert( !std::is_assignable_v<volatile A&, const A&> );
}
void
test03()
{
using A = std::atomic<long double>;
static_assert( std::is_standard_layout_v<A> );
static_assert( std::is_trivially_default_constructible_v<A> );
static_assert( std::is_trivially_destructible_v<A> );
static_assert( std::is_same_v<A::value_type, long double> );
static_assert( std::is_same_v<A::difference_type, A::value_type> );
static_assert( !std::is_copy_constructible_v<A> );
static_assert( !std::is_move_constructible_v<A> );
static_assert( !std::is_copy_assignable_v<A> );
static_assert( !std::is_move_assignable_v<A> );
static_assert( !std::is_assignable_v<volatile A&, const A&> );
}
// Copyright (C) 2019 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.
// You should have received a copy of the GNU General Public License along
// with this library; see the file COPYING3. If not see
// <http://www.gnu.org/licenses/>.
// { dg-options "-std=gnu++2a" }
// { dg-do compile { target c++2a } }
#include <atomic>
void
test01()
{
int i = 0;
std::atomic_ref a0(i);
static_assert(std::is_same_v<decltype(a0), std::atomic_ref<int>>);
float f = 1.0f;
std::atomic_ref a1(f);
static_assert(std::is_same_v<decltype(a1), std::atomic_ref<float>>);
int* p = &i;
std::atomic_ref a2(p);
static_assert(std::is_same_v<decltype(a2), std::atomic_ref<int*>>);
struct X { } x;
std::atomic_ref a3(x);
static_assert(std::is_same_v<decltype(a3), std::atomic_ref<X>>);
}
// Copyright (C) 2019 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.
// You should have received a copy of the GNU General Public License along
// with this library; see the file COPYING3. If not see
// <http://www.gnu.org/licenses/>.
// { dg-options "-std=gnu++2a" }
// { dg-do run { target c++2a } }
// { dg-add-options libatomic }
#include <atomic>
#include <limits.h>
#include <testsuite_hooks.h>
struct X
{
X() = default;
X(int i) : i(i) { }
bool operator==(int rhs) const { return i == rhs; }
int i;
};
void
test01()
{
X value;
{
const auto mo = std::memory_order_relaxed;
std::atomic_ref<X> a(value);
bool ok = a.is_lock_free();
if constexpr (std::atomic_ref<X>::is_always_lock_free)
VERIFY( ok );
a = X{};
VERIFY( a.load() == 0 );
VERIFY( a.load(mo) == 0 );
a.store(1);
VERIFY( a.load() == 1 );
auto v = a.exchange(2);
VERIFY( a.load() == 2 );
VERIFY( v == 1 );
v = a.exchange(3, mo);
VERIFY( a.load() == 3 );
VERIFY( v == 2 );
auto expected = a.load();
while (!a.compare_exchange_weak(expected, 4, mo, mo))
{ /* weak form can fail spuriously */ }
VERIFY( a.load() == 4 );
VERIFY( expected == 3 );
expected = 1;
ok = a.compare_exchange_weak(expected, 5, mo, mo);
VERIFY( !ok && a.load() == 4 && expected == 4 );
ok = a.compare_exchange_strong(expected, 5, mo, mo);
VERIFY( ok && a.load() == 5 && expected == 4 );
expected = 0;
ok = a.compare_exchange_strong(expected, 3, mo, mo);
VERIFY( !ok && a.load() == 5 && expected == 5 );
while (!a.compare_exchange_weak(expected, 4))
{ /* weak form can fail spuriously */ }
VERIFY( a.load() == 4 && expected == 5 );
expected = a.load();
while (!a.compare_exchange_weak(expected, 6, mo))
{ /* weak form can fail spuriously */ }
VERIFY( a.load() == 6 && expected == 4 );
expected = a.load();
expected.i += 1;
ok = a.compare_exchange_weak(expected, -8);
VERIFY( !ok && a.load() == 6 && expected == 6 );
expected = a.load();
expected.i += 1;
ok = a.compare_exchange_weak(expected, 8, mo);
VERIFY( !ok && a.load() == 6 && expected == 6 );
ok = a.compare_exchange_strong(expected, -6);
VERIFY( ok && a.load() == -6 && expected == 6 );
expected = a.load();
ok = a.compare_exchange_strong(expected, 7, mo);
VERIFY( ok && a.load() == 7 && expected == -6 );
expected = a.load();
expected.i += 1;
ok = a.compare_exchange_strong(expected, 2);
VERIFY( !ok && a.load() == 7 && expected == 7 );
expected = a.load();
expected.i += 1;
ok = a.compare_exchange_strong(expected, 2, mo);
VERIFY( !ok && a.load() == 7 && expected == 7 );
}
VERIFY( value == 7 );
}
void
test02()
{
X i;
std::atomic_ref<X> a0(i);
std::atomic_ref<X> a1(i);
std::atomic_ref<X> a2(a0);
a0 = 42;
VERIFY( a1.load() == 42 );
VERIFY( a2.load() == 42 );
}
int
main()
{
test01();
test02();
}
// Copyright (C) 2019 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.
// You should have received a copy of the GNU General Public License along
// with this library; see the file COPYING3. If not see
// <http://www.gnu.org/licenses/>.
// { dg-options "-std=gnu++2a" }
// { dg-do run { target c++2a } }
// { dg-add-options libatomic }
#include <atomic>
#include <limits.h>
#include <testsuite_hooks.h>
void
test01()
{
int value;
{
const auto mo = std::memory_order_relaxed;
std::atomic_ref<int> a(value);
bool ok = a.is_lock_free();
if constexpr (std::atomic_ref<int>::is_always_lock_free)
VERIFY( ok );
a = 0;
VERIFY( a.load() == 0 );
VERIFY( a.load(mo) == 0 );
a.store(1);
VERIFY( a.load() == 1 );
auto v = a.exchange(2);
VERIFY( a == 2 );
VERIFY( v == 1 );
v = a.exchange(3, mo);
VERIFY( a == 3 );
VERIFY( v == 2 );
auto expected = a.load();
while (!a.compare_exchange_weak(expected, 4, mo, mo))
{ /* weak form can fail spuriously */ }
VERIFY( a.load() == 4 );
VERIFY( expected == 3 );
expected = 1;
ok = a.compare_exchange_weak(expected, 5, mo, mo);
VERIFY( !ok && a.load() == 4 && expected == 4 );
ok = a.compare_exchange_strong(expected, 5, mo, mo);
VERIFY( ok && a.load() == 5 && expected == 4 );
expected = 0;
ok = a.compare_exchange_strong(expected, 3, mo, mo);
VERIFY( !ok && a.load() == 5 && expected == 5 );
while (!a.compare_exchange_weak(expected, 4))
{ /* weak form can fail spuriously */ }
VERIFY( a.load() == 4 && expected == 5 );
expected = a.load();
while (!a.compare_exchange_weak(expected, 6, mo))
{ /* weak form can fail spuriously */ }
VERIFY( a.load() == 6 && expected == 4 );
expected = a.load() + 1;
ok = a.compare_exchange_weak(expected, -8);
VERIFY( !ok && a.load() == 6 && expected == 6 );
expected = a.load() + 1;
ok = a.compare_exchange_weak(expected, 8, mo);
VERIFY( !ok && a.load() == 6 && expected == 6 );
ok = a.compare_exchange_strong(expected, -6);
VERIFY( ok && a.load() == -6 && expected == 6 );
expected = a.load();
ok = a.compare_exchange_strong(expected, 7, mo);
VERIFY( ok && a.load() == 7 && expected == -6 );
expected = a.load() + 1;
ok = a.compare_exchange_strong(expected, 2);
VERIFY( !ok && a.load() == 7 && expected == 7 );
expected = a.load() + 1;
ok = a.compare_exchange_strong(expected, 2, mo);
VERIFY( !ok && a.load() == 7 && expected == 7 );
v = a.fetch_add(2);
VERIFY( v == 7 );
VERIFY( a == 9 );
v = a.fetch_add(-30, mo);
VERIFY( v == 9 );
VERIFY( a == -21 );
v = a.fetch_sub(3);
VERIFY( v == -21 );
VERIFY( a == -24 );
v = a.fetch_sub(-41, mo);
VERIFY( v == -24 );
VERIFY( a == 17 );
v = a.fetch_and(0x101);
VERIFY( v == 17 );
VERIFY( a == 1 );
a = 0x17;
v = a.fetch_and(0x23, mo);
VERIFY( v == 0x17 );
VERIFY( a == 3 );
v = a.fetch_or(0x101);
VERIFY( v == 3 );
VERIFY( a == 0x103 );
v = a.fetch_or(0x23, mo);
VERIFY( v == 0x103 );
VERIFY( a == 0x123 );
v = a.fetch_xor(0x101);
VERIFY( v == 0x123 );
VERIFY( a == 0x022 );
v = a.fetch_xor(0x123, mo);
VERIFY( v == 0x022 );
VERIFY( a == 0x101 );
v = a++;
VERIFY( v == 0x101 );
VERIFY( a == 0x102 );
v = a--;
VERIFY( v == 0x102 );
VERIFY( a == 0x101 );
v = ++a;
VERIFY( v == 0x102 );
VERIFY( a == 0x102 );
v = --a;
VERIFY( v == 0x101 );
VERIFY( a == 0x101 );
v = a += -10;
VERIFY( v == 247 );
VERIFY( a == 247 );
v = a -= 250;
VERIFY( v == -3 );
VERIFY( a == -3 );
a = 0x17;
v = a &= 0x102;
VERIFY( v == 2 );
VERIFY( a == 2 );
v = a |= 0x101;
VERIFY( v == 0x103 );
VERIFY( a == 0x103 );
v = a ^= 0x121;
VERIFY( v == 0x022 );
VERIFY( a == 0x022 );
}
VERIFY( value == 0x022 );
}
void
test02()
{
unsigned short value;
{
const auto mo = std::memory_order_relaxed;
std::atomic_ref<unsigned short> a(value);
bool ok = a.is_lock_free();
if constexpr (std::atomic_ref<unsigned short>::is_always_lock_free)
VERIFY( ok );
a = 0;
VERIFY( a.load() == 0 );
VERIFY( a.load(mo) == 0 );
a.store(1);
VERIFY( a.load() == 1 );
auto v = a.exchange(2);
VERIFY( a == 2 );
VERIFY( v == 1 );
v = a.exchange(3, mo);
VERIFY( a == 3 );
VERIFY( v == 2 );
auto expected = a.load();
while (!a.compare_exchange_weak(expected, 4, mo, mo))
{ /* weak form can fail spuriously */ }
VERIFY( a.load() == 4 );
VERIFY( expected == 3 );
expected = 1;
ok = a.compare_exchange_weak(expected, 5, mo, mo);
VERIFY( !ok && a.load() == 4 && expected == 4 );
ok = a.compare_exchange_strong(expected, 5, mo, mo);
VERIFY( ok && a.load() == 5 && expected == 4 );
expected = 0;
ok = a.compare_exchange_strong(expected, 3, mo, mo);
VERIFY( !ok && a.load() == 5 && expected == 5 );
while (!a.compare_exchange_weak(expected, 4))
{ /* weak form can fail spuriously */ }
VERIFY( a.load() == 4 && expected == 5 );
expected = a.load();
while (!a.compare_exchange_weak(expected, 6, mo))
{ /* weak form can fail spuriously */ }
VERIFY( a.load() == 6 && expected == 4 );
expected = a.load() + 1;
ok = a.compare_exchange_weak(expected, -8);
VERIFY( !ok && a.load() == 6 && expected == 6 );
expected = a.load() + 1;
ok = a.compare_exchange_weak(expected, 8, mo);
VERIFY( !ok && a.load() == 6 && expected == 6 );
ok = a.compare_exchange_strong(expected, -6);
VERIFY( ok && a.load() == (unsigned short)-6 && expected == 6 );
expected = a.load();
ok = a.compare_exchange_strong(expected, 7, mo);
VERIFY( ok && a.load() == 7 && expected == (unsigned short)-6 );
expected = a.load() + 1;
ok = a.compare_exchange_strong(expected, 2);
VERIFY( !ok && a.load() == 7 && expected == 7 );
expected = a.load() + 1;
ok = a.compare_exchange_strong(expected, 2, mo);
VERIFY( !ok && a.load() == 7 && expected == 7 );
v = a.fetch_add(2);
VERIFY( v == 7 );
VERIFY( a == 9 );
v = a.fetch_add(-30, mo);
VERIFY( v == 9 );
VERIFY( a == (unsigned short)-21 );
v = a.fetch_sub(3);
VERIFY( v == (unsigned short)-21 );
VERIFY( a == (unsigned short)-24 );
v = a.fetch_sub((unsigned short)-41, mo);
VERIFY( v == (unsigned short)-24 );
VERIFY( a == 17 );
v = a.fetch_and(0x21);
VERIFY( v == 17 );
VERIFY( a == 1 );
a = 0x17;
v = a.fetch_and(0x23, mo);
VERIFY( v == 0x17 );
VERIFY( a == 3 );
v = a.fetch_or(0x21);
VERIFY( v == 3 );
VERIFY( a == 0x23 );
v = a.fetch_or(0x44, mo);
VERIFY( v == 0x23 );
VERIFY( a == 0x67 );
v = a.fetch_xor(0x21);
VERIFY( v == 0x67 );
VERIFY( a == 0x46 );
v = a.fetch_xor(0x12, mo);
VERIFY( v == 0x46 );
VERIFY( a == 0x54 );
v = a++;
VERIFY( v == 0x54 );
VERIFY( a == 0x55 );
v = a--;
VERIFY( v == 0x55 );
VERIFY( a == 0x54 );
v = ++a;
VERIFY( v == 0x55 );
VERIFY( a == 0x55 );
v = --a;
VERIFY( v == 0x54 );
VERIFY( a == 0x54 );
v = a += -10;
VERIFY( v == 0x4a );
VERIFY( a == 0x4a );
v = a -= 15;
VERIFY( v == 0x3b );
VERIFY( a == 0x3b );
a = 0x17;
v = a &= 0x12;
VERIFY( v == 0x12 );
VERIFY( a == 0x12 );
v = a |= 0x34;
VERIFY( v == 0x36 );
VERIFY( a == 0x36 );
v = a ^= 0x12;
VERIFY( v == 0x24 );
VERIFY( a == 0x24 );
}
VERIFY( value == 0x24 );
}
void
test03()
{
int i = 0;
std::atomic_ref<int> a0(i);
std::atomic_ref<int> a1(i);
std::atomic_ref<int> a2(a0);
a0 = 42;
VERIFY( a1 == 42 );
VERIFY( a2 == 42 );
}
void
test04()
{
int i = INT_MIN;
std::atomic_ref<int> a(i);
--a;
VERIFY( a == INT_MAX );
++a;
VERIFY( a == INT_MIN );
a |= INT_MAX;
VERIFY( a == -1 );
}
int
main()
{
test01();
test02();
test03();
test04();
}
// Copyright (C) 2019 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.
// You should have received a copy of the GNU General Public License along
// with this library; see the file COPYING3. If not see
// <http://www.gnu.org/licenses/>.
// { dg-options "-std=gnu++2a" }
// { dg-do run { target c++2a } }
// { dg-add-options libatomic }
#include <atomic>
#include <testsuite_hooks.h>
void
test01()
{
long arr[10] = { };
long* value;
{
const auto mo = std::memory_order_relaxed;
std::atomic_ref<long*> a(value);
bool ok = a.is_lock_free();
if constexpr (std::atomic_ref<long*>::is_always_lock_free)
VERIFY( ok );
a = arr;
VERIFY( a.load() == arr );
VERIFY( a.load(mo) == arr );
a.store(arr+1);
VERIFY( a.load() == arr+1 );
auto v = a.exchange(arr+2);
VERIFY( a == arr+2 );
VERIFY( v == arr+1 );
v = a.exchange(arr+3, mo);
VERIFY( a == arr+3 );
VERIFY( v == arr+2 );
auto expected = a.load();
while (!a.compare_exchange_weak(expected, arr+4, mo, mo))
{ /* weak form can fail spuriously */ }
VERIFY( a.load() == arr+4 );
VERIFY( expected == arr+3 );
expected = arr+1;
ok = a.compare_exchange_weak(expected, arr+5, mo, mo);
VERIFY( !ok && a.load() == arr+4 && expected == arr+4 );
ok = a.compare_exchange_strong(expected, arr+5, mo, mo);
VERIFY( ok && a.load() == arr+5 && expected == arr+4 );
expected = nullptr;
ok = a.compare_exchange_strong(expected, arr+3, mo, mo);
VERIFY( !ok && a.load() == arr+5 && expected == arr+5 );
while (!a.compare_exchange_weak(expected, arr+4))
{ /* weak form can fail spuriously */ }
VERIFY( a.load() == arr+4 && expected == arr+5 );
expected = a.load();
while (!a.compare_exchange_weak(expected, arr+6, mo))
{ /* weak form can fail spuriously */ }
VERIFY( a.load() == arr+6 && expected == arr+4 );
expected = a.load() + 1;
ok = a.compare_exchange_weak(expected, arr+8);
VERIFY( !ok && a.load() == arr+6 && expected == arr+6 );
expected = a.load() + 1;
ok = a.compare_exchange_weak(expected, arr+8, mo);
VERIFY( !ok && a.load() == arr+6 && expected == arr+6 );
ok = a.compare_exchange_strong(expected, arr+5);
VERIFY( ok && a.load() == arr+5 && expected == arr+6 );
expected = a.load();
ok = a.compare_exchange_strong(expected, arr+7, mo);
VERIFY( ok && a.load() == arr+7 && expected == arr+5 );
expected = a.load() + 1;
ok = a.compare_exchange_strong(expected, arr+2);
VERIFY( !ok && a.load() == arr+7 && expected == arr+7 );
expected = a.load() + 1;
ok = a.compare_exchange_strong(expected, arr+2, mo);
VERIFY( !ok && a.load() == arr+7 && expected == arr+7 );
v = a.fetch_add(2);
VERIFY( v == arr+7 );
VERIFY( a == arr+9 );
v = a.fetch_add(-3, mo);
VERIFY( v == arr+9 );
VERIFY( a == arr+6 );
v = a.fetch_sub(3);
VERIFY( v == arr+6 );
VERIFY( a == arr+3 );
v = a.fetch_sub(2, mo);
VERIFY( v == arr+3 );
VERIFY( a == arr+1 );
v = a += 5;
VERIFY( v == arr+6 );
VERIFY( a == arr+6 );
v = a -= 5;
VERIFY( v == arr+1 );
VERIFY( a == arr+1 );
}
VERIFY( value == arr+1 );
}
void
test02()
{
char arr[10] = { };
char* value;
{
const auto mo = std::memory_order_relaxed;
std::atomic_ref<char*> a(value);
bool ok = a.is_lock_free();
if constexpr (std::atomic_ref<char*>::is_always_lock_free)
VERIFY( ok );
a = arr;
VERIFY( a.load() == arr );
a.store(arr+3);
VERIFY( a.load(mo) == arr+3 );
a.store(arr+1, mo);
VERIFY( a.load() == arr+1 );
auto v = a.exchange(arr+2);
VERIFY( a == arr+2 );
VERIFY( v == arr+1 );
v = a.exchange(arr+3, mo);
VERIFY( a == arr+3 );
VERIFY( v == arr+2 );
auto expected = a.load();
while (!a.compare_exchange_weak(expected, arr+4, mo, mo))
{ /* weak form can fail spuriously */ }
VERIFY( a.load() == arr+4 );
VERIFY( expected == arr+3 );
expected = arr+1;
ok = a.compare_exchange_weak(expected, arr+5, mo, mo);
VERIFY( !ok && a.load() == arr+4 && expected == arr+4 );
ok = a.compare_exchange_strong(expected, arr+5, mo, mo);
VERIFY( ok && a.load() == arr+5 && expected == arr+4 );
expected = nullptr;
ok = a.compare_exchange_strong(expected, arr+3, mo, mo);
VERIFY( !ok && a.load() == arr+5 && expected == arr+5 );
while (!a.compare_exchange_weak(expected, arr+4))
{ /* weak form can fail spuriously */ }
VERIFY( a.load() == arr+4 && expected == arr+5 );
expected = a.load();
while (!a.compare_exchange_weak(expected, arr+6, mo))
{ /* weak form can fail spuriously */ }
VERIFY( a.load() == arr+6 && expected == arr+4 );
expected = a.load() + 1;
ok = a.compare_exchange_weak(expected, arr+8);
VERIFY( !ok && a.load() == arr+6 && expected == arr+6 );
expected = a.load() + 1;
ok = a.compare_exchange_weak(expected, arr+8, mo);
VERIFY( !ok && a.load() == arr+6 && expected == arr+6 );
ok = a.compare_exchange_strong(expected, arr+5);
VERIFY( ok && a.load() == arr+5 && expected == arr+6 );
expected = a.load();
ok = a.compare_exchange_strong(expected, arr+7, mo);
VERIFY( ok && a.load() == arr+7 && expected == arr+5 );
expected = a.load() + 1;
ok = a.compare_exchange_strong(expected, arr+2);
VERIFY( !ok && a.load() == arr+7 && expected == arr+7 );
expected = a.load() + 1;
ok = a.compare_exchange_strong(expected, arr+2, mo);
VERIFY( !ok && a.load() == arr+7 && expected == arr+7 );
v = a.fetch_add(2);
VERIFY( v == arr+7 );
VERIFY( a == arr+9 );
v = a.fetch_add(-3, mo);
VERIFY( v == arr+9 );
VERIFY( a == arr+6 );
v = a.fetch_sub(3);
VERIFY( v == arr+6 );
VERIFY( a == arr+3 );
v = a.fetch_sub(2, mo);
VERIFY( v == arr+3 );
VERIFY( a == arr+1 );
v = a += 5;
VERIFY( v == arr+6 );
VERIFY( a == arr+6 );
v = a -= 5;
VERIFY( v == arr+1 );
VERIFY( a == arr+1 );
}
VERIFY( value == arr+1 );
}
void
test03()
{
int i = 0;
int* ptr = 0;
std::atomic_ref<int*> a0(ptr);
std::atomic_ref<int*> a1(ptr);
std::atomic_ref<int*> a2(a0);
a0 = &i;
VERIFY( a1 == &i );
VERIFY( a2 == &i );
}
int
main()
{
test01();
test02();
test03();
}
// Copyright (C) 2019 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.
// You should have received a copy of the GNU General Public License along
// with this library; see the file COPYING3. If not see
// <http://www.gnu.org/licenses/>.
// { dg-options "-std=gnu++2a" }
// { dg-do compile { target c++2a } }
#include <atomic>
void
test01()
{
struct X { int c; };
using A = std::atomic_ref<X>;
static_assert( std::is_standard_layout_v<A> );
static_assert( std::is_nothrow_copy_constructible_v<A> );
static_assert( std::is_trivially_destructible_v<A> );
static_assert( std::is_same_v<A::value_type, X> );
static_assert( !std::is_copy_assignable_v<A> );
static_assert( !std::is_move_assignable_v<A> );
}
void
test02()
{
using A = std::atomic_ref<int>;
static_assert( std::is_standard_layout_v<A> );
static_assert( std::is_nothrow_copy_constructible_v<A> );
static_assert( std::is_trivially_destructible_v<A> );
static_assert( std::is_same_v<A::value_type, int> );
static_assert( std::is_same_v<A::difference_type, A::value_type> );
static_assert( !std::is_copy_assignable_v<A> );
static_assert( !std::is_move_assignable_v<A> );
}
void
test03()
{
using A = std::atomic_ref<double>;
static_assert( std::is_standard_layout_v<A> );
static_assert( std::is_nothrow_copy_constructible_v<A> );
static_assert( std::is_trivially_destructible_v<A> );
static_assert( std::is_same_v<A::value_type, double> );
static_assert( std::is_same_v<A::difference_type, A::value_type> );
static_assert( !std::is_copy_assignable_v<A> );
static_assert( !std::is_move_assignable_v<A> );
}
void
test04()
{
using A = std::atomic_ref<int*>;
static_assert( std::is_standard_layout_v<A> );
static_assert( std::is_nothrow_copy_constructible_v<A> );
static_assert( std::is_trivially_destructible_v<A> );
static_assert( std::is_same_v<A::value_type, int*> );
static_assert( std::is_same_v<A::difference_type, std::ptrdiff_t> );
static_assert( std::is_nothrow_copy_constructible_v<A> );
static_assert( !std::is_copy_assignable_v<A> );
static_assert( !std::is_move_assignable_v<A> );
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment