Skip to content

Commit ffdda72

Browse files
committed
Convert compare_exchange_strong test
1 parent 26013d0 commit ffdda72

File tree

2 files changed

+116
-46
lines changed

2 files changed

+116
-46
lines changed

libcxx/include/__atomic/atomic_ref.h

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -76,34 +76,39 @@ struct __atomic_ref_base {
7676
}
7777

7878
_LIBCPP_HIDE_FROM_ABI static bool __compare_exchange(
79-
_Tp* __ptr, _Tp* __expected, _Tp* __desired, bool __is_weak, int __success, int __failure) noexcept {
79+
_Tp* __ptr,
80+
value_type* __expected,
81+
value_type* __desired,
82+
bool __is_weak,
83+
int __success,
84+
int __failure) noexcept {
8085
if constexpr (
8186
# if __has_builtin(__builtin_clear_padding)
82-
has_unique_object_representations_v<_Tp> || floating_point<_Tp>
87+
has_unique_object_representations_v<value_type> || floating_point<value_type>
8388
# else
8489
true // NOLINT(readability-simplify-boolean-expr)
8590
# endif
8691
) {
8792
return __atomic_compare_exchange(__ptr, __expected, __desired, __is_weak, __success, __failure);
88-
} else { // _Tp has padding bits and __builtin_clear_padding is available
93+
} else { // value_type has padding bits and __builtin_clear_padding is available
8994
__clear_padding(*__desired);
90-
_Tp __copy = *__expected;
95+
value_type __copy = *__expected;
9196
__clear_padding(__copy);
9297
// The algorithm we use here is basically to perform `__atomic_compare_exchange` on the
9398
// values until it has either succeeded, or failed because the value representation of the
9499
// objects involved was different. This is why we loop around __atomic_compare_exchange:
95100
// we basically loop until its failure is caused by the value representation of the objects
96101
// being different, not only their object representation.
97102
while (true) {
98-
_Tp __prev = __copy;
103+
value_type __prev = __copy;
99104
if (__atomic_compare_exchange(__ptr, std::addressof(__copy), __desired, __is_weak, __success, __failure)) {
100105
return true;
101106
}
102-
_Tp __curr = __copy;
103-
if (std::memcmp(__clear_padding(__prev), __clear_padding(__curr), sizeof(_Tp)) != 0) {
107+
value_type __curr = __copy;
108+
if (std::memcmp(__clear_padding(__prev), __clear_padding(__curr), sizeof(value_type)) != 0) {
104109
// Value representation without padding bits do not compare equal ->
105110
// write the current content of *ptr into *expected
106-
std::memcpy(__expected, std::addressof(__copy), sizeof(_Tp));
111+
std::memcpy(__expected, std::addressof(__copy), sizeof(value_type));
107112
return false;
108113
}
109114
}

libcxx/test/std/atomics/atomics.ref/compare_exchange_strong.pass.cpp

Lines changed: 103 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -24,79 +24,126 @@
2424
#include "test_helper.h"
2525
#include "test_macros.h"
2626

27-
template <typename T>
27+
template <typename T, typename U>
28+
concept has_compare_exchange_strong_1 =
29+
requires { std::declval<T>().compare_exchange_strong(std::declval<U&>(), std::declval<U>()); };
30+
template <typename T, typename U>
31+
concept has_compare_exchange_strong_2 = requires {
32+
std::declval<T>().compare_exchange_strong(std::declval<U&>(), std::declval<U>(), std::declval<std::memory_order>());
33+
};
34+
template <typename T, typename U>
35+
concept has_compare_exchange_strong_3 = requires {
36+
std::declval<T>().compare_exchange_strong(
37+
std::declval<U&>(), std::declval<U>(), std::declval<std::memory_order>(), std::declval<std::memory_order>());
38+
};
39+
40+
template <typename T, typename U>
41+
concept has_compare_exchange_strong =
42+
has_compare_exchange_strong_1<T, U> && has_compare_exchange_strong_2<T, U> && has_compare_exchange_strong_3<T, U>;
43+
44+
template <typename T, typename U>
45+
concept does_not_have_compare_exchange_strong =
46+
!has_compare_exchange_strong_1<T, U> && !has_compare_exchange_strong_2<T, U> &&
47+
!has_compare_exchange_strong_3<T, U>;
48+
49+
template <typename U>
2850
struct TestCompareExchangeStrong {
2951
void operator()() const {
52+
static_assert(has_compare_exchange_strong<std::atomic_ref<U>, U>);
53+
do_test<U>();
54+
do_test_atomic<U>();
55+
static_assert(does_not_have_compare_exchange_strong<std::atomic_ref<U const>, U>);
56+
if constexpr (std::atomic_ref<U>::is_always_lock_free) {
57+
static_assert(has_compare_exchange_strong<std::atomic_ref<U volatile>, U>);
58+
do_test<U volatile>();
59+
do_test_atomic<U volatile>();
60+
static_assert(does_not_have_compare_exchange_strong<std::atomic_ref<U const volatile>, U>);
61+
}
62+
}
63+
64+
template <typename T>
65+
void do_test() const {
3066
{
3167
T x(T(1));
3268
std::atomic_ref<T> const a(x);
3369

34-
T t(T(1));
70+
std::remove_cv_t<T> t(T(1));
3571
std::same_as<bool> decltype(auto) y = a.compare_exchange_strong(t, T(2));
3672
assert(y == true);
37-
assert(a == T(2));
38-
assert(t == T(1));
73+
assert(a == std::remove_cv_t<T>(2));
74+
assert(t == std::remove_cv_t<T>(1));
3975
y = a.compare_exchange_strong(t, T(3));
4076
assert(y == false);
41-
assert(a == T(2));
42-
assert(t == T(2));
77+
assert(a == std::remove_cv_t<T>(2));
78+
assert(t == std::remove_cv_t<T>(2));
4379

4480
ASSERT_NOEXCEPT(a.compare_exchange_strong(t, T(2)));
4581
}
4682
{
4783
T x(T(1));
4884
std::atomic_ref<T> const a(x);
4985

50-
T t(T(1));
86+
std::remove_cv_t<T> t(T(1));
5187
std::same_as<bool> decltype(auto) y = a.compare_exchange_strong(t, T(2), std::memory_order_seq_cst);
5288
assert(y == true);
53-
assert(a == T(2));
54-
assert(t == T(1));
89+
assert(a == std::remove_cv_t<T>(2));
90+
assert(t == std::remove_cv_t<T>(1));
5591
y = a.compare_exchange_strong(t, T(3), std::memory_order_seq_cst);
5692
assert(y == false);
57-
assert(a == T(2));
58-
assert(t == T(2));
93+
assert(a == std::remove_cv_t<T>(2));
94+
assert(t == std::remove_cv_t<T>(2));
5995

6096
ASSERT_NOEXCEPT(a.compare_exchange_strong(t, T(2), std::memory_order_seq_cst));
6197
}
6298
{
6399
T x(T(1));
64100
std::atomic_ref<T> const a(x);
65101

66-
T t(T(1));
102+
std::remove_cv_t<T> t(T(1));
67103
std::same_as<bool> decltype(auto) y =
68104
a.compare_exchange_strong(t, T(2), std::memory_order_release, std::memory_order_relaxed);
69105
assert(y == true);
70-
assert(a == T(2));
71-
assert(t == T(1));
106+
assert(a == std::remove_cv_t<T>(2));
107+
assert(t == std::remove_cv_t<T>(1));
72108
y = a.compare_exchange_strong(t, T(3), std::memory_order_release, std::memory_order_relaxed);
73109
assert(y == false);
74-
assert(a == T(2));
75-
assert(t == T(2));
110+
assert(a == std::remove_cv_t<T>(2));
111+
assert(t == std::remove_cv_t<T>(2));
76112

77113
ASSERT_NOEXCEPT(a.compare_exchange_strong(t, T(2), std::memory_order_release, std::memory_order_relaxed));
78114
}
115+
}
79116

117+
template <typename T>
118+
void do_test_atomic() const {
80119
// success memory_order::release
81120
{
82-
auto store = [](std::atomic_ref<T> const& x, T old_val, T new_val) {
83-
auto r = x.compare_exchange_strong(old_val, new_val, std::memory_order::release, std::memory_order::relaxed);
121+
auto store = [](std::atomic_ref<T> const& x, T const& old_val, T const& new_val) {
122+
auto r = x.compare_exchange_strong(
123+
const_cast<std::remove_cv_t<T>&>(old_val),
124+
const_cast<std::remove_cv_t<T> const&>(new_val),
125+
std::memory_order::release,
126+
std::memory_order::relaxed);
84127
assert(r);
85128
};
86129

87130
auto load = [](std::atomic_ref<T> const& x) { return x.load(std::memory_order::acquire); };
88131
test_acquire_release<T>(store, load);
89-
90-
auto store_one_arg = [](std::atomic_ref<T> const& x, T old_val, T new_val) {
91-
auto r = x.compare_exchange_strong(old_val, new_val, std::memory_order::release);
132+
auto store_one_arg = [](std::atomic_ref<T> const& x, T const& old_val, T const& new_val) {
133+
auto r = x.compare_exchange_strong(
134+
const_cast<std::remove_cv_t<T>&>(old_val),
135+
const_cast<std::remove_cv_t<T> const&>(new_val),
136+
std::memory_order::release);
92137
assert(r);
93138
};
94139
test_acquire_release<T>(store_one_arg, load);
95140
}
96141

97142
// success memory_order::acquire
98143
{
99-
auto store = [](std::atomic_ref<T> const& x, T, T new_val) { x.store(new_val, std::memory_order::release); };
144+
auto store = [](std::atomic_ref<T> const& x, T const&, T const& new_val) {
145+
x.store(const_cast<std::remove_cv_t<T> const&>(new_val), std::memory_order::release);
146+
};
100147

101148
auto load = [](std::atomic_ref<T> const& x) {
102149
auto val = x.load(std::memory_order::relaxed);
@@ -117,8 +164,12 @@ struct TestCompareExchangeStrong {
117164

118165
// success memory_order::acq_rel
119166
{
120-
auto store = [](std::atomic_ref<T> const& x, T old_val, T new_val) {
121-
auto r = x.compare_exchange_strong(old_val, new_val, std::memory_order::acq_rel, std::memory_order::relaxed);
167+
auto store = [](std::atomic_ref<T> const& x, T const& old_val, T const& new_val) {
168+
auto r = x.compare_exchange_strong(
169+
const_cast<std::remove_cv_t<T>&>(old_val),
170+
const_cast<std::remove_cv_t<T> const&>(new_val),
171+
std::memory_order::acq_rel,
172+
std::memory_order::relaxed);
122173
assert(r);
123174
};
124175
auto load = [](std::atomic_ref<T> const& x) {
@@ -129,8 +180,11 @@ struct TestCompareExchangeStrong {
129180
};
130181
test_acquire_release<T>(store, load);
131182

132-
auto store_one_arg = [](std::atomic_ref<T> const& x, T old_val, T new_val) {
133-
auto r = x.compare_exchange_strong(old_val, new_val, std::memory_order::acq_rel);
183+
auto store_one_arg = [](std::atomic_ref<T> const& x, T const& old_val, T const& new_val) {
184+
auto r = x.compare_exchange_strong(
185+
const_cast<std::remove_cv_t<T>&>(old_val),
186+
const_cast<std::remove_cv_t<T> const&>(new_val),
187+
std::memory_order::acq_rel);
134188
assert(r);
135189
};
136190
auto load_one_arg = [](std::atomic_ref<T> const& x) {
@@ -144,8 +198,12 @@ struct TestCompareExchangeStrong {
144198

145199
// success memory_order::seq_cst
146200
{
147-
auto store = [](std::atomic_ref<T> const& x, T old_val, T new_val) {
148-
auto r = x.compare_exchange_strong(old_val, new_val, std::memory_order::seq_cst, std::memory_order::relaxed);
201+
auto store = [](std::atomic_ref<T> const& x, T const& old_val, T const& new_val) {
202+
auto r = x.compare_exchange_strong(
203+
const_cast<std::remove_cv_t<T>&>(old_val),
204+
const_cast<std::remove_cv_t<T> const&>(new_val),
205+
std::memory_order::seq_cst,
206+
std::memory_order::relaxed);
149207
assert(r);
150208
};
151209
auto load = [](std::atomic_ref<T> const& x) {
@@ -156,8 +214,11 @@ struct TestCompareExchangeStrong {
156214
};
157215
test_seq_cst<T>(store, load);
158216

159-
auto store_one_arg = [](std::atomic_ref<T> const& x, T old_val, T new_val) {
160-
auto r = x.compare_exchange_strong(old_val, new_val, std::memory_order::seq_cst);
217+
auto store_one_arg = [](std::atomic_ref<T> const& x, T const& old_val, T const& new_val) {
218+
auto r = x.compare_exchange_strong(
219+
const_cast<std::remove_cv_t<T>&>(old_val),
220+
const_cast<std::remove_cv_t<T> const&>(new_val),
221+
std::memory_order::seq_cst);
161222
assert(r);
162223
};
163224
auto load_one_arg = [](std::atomic_ref<T> const& x) {
@@ -171,10 +232,12 @@ struct TestCompareExchangeStrong {
171232

172233
// failure memory_order::acquire
173234
{
174-
auto store = [](std::atomic_ref<T> const& x, T, T new_val) { x.store(new_val, std::memory_order::release); };
175-
auto load = [](std::atomic_ref<T> const& x) {
235+
auto store = [](std::atomic_ref<T> const& x, T const&, T const& new_val) {
236+
x.store(const_cast<std::remove_cv_t<T> const&>(new_val), std::memory_order::release);
237+
};
238+
auto load = [](std::atomic_ref<T> const& x) {
176239
auto result = x.load(std::memory_order::relaxed);
177-
T unexpected(T(255));
240+
std::remove_cv_t<T> unexpected(std::remove_cv_t<T>(255));
178241
bool r =
179242
x.compare_exchange_strong(unexpected, unexpected, std::memory_order::relaxed, std::memory_order::acquire);
180243
assert(!r);
@@ -184,7 +247,7 @@ struct TestCompareExchangeStrong {
184247

185248
auto load_one_arg = [](std::atomic_ref<T> const& x) {
186249
auto result = x.load(std::memory_order::relaxed);
187-
T unexpected(T(255));
250+
std::remove_cv_t<T> unexpected(std::remove_cv_t<T>(255));
188251
bool r = x.compare_exchange_strong(unexpected, unexpected, std::memory_order::acquire);
189252
assert(!r);
190253
return result;
@@ -194,7 +257,7 @@ struct TestCompareExchangeStrong {
194257
// acq_rel replaced by acquire
195258
auto load_one_arg_acq_rel = [](std::atomic_ref<T> const& x) {
196259
auto result = x.load(std::memory_order::relaxed);
197-
T unexpected(T(255));
260+
std::remove_cv_t<T> unexpected(std::remove_cv_t<T>(255));
198261
bool r = x.compare_exchange_strong(unexpected, unexpected, std::memory_order::acq_rel);
199262
assert(!r);
200263
return result;
@@ -204,10 +267,12 @@ struct TestCompareExchangeStrong {
204267

205268
// failure memory_order::seq_cst
206269
{
207-
auto store = [](std::atomic_ref<T> const& x, T, T new_val) { x.store(new_val, std::memory_order::seq_cst); };
208-
auto load = [](std::atomic_ref<T> const& x) {
270+
auto store = [](std::atomic_ref<T> const& x, T const&, T const& new_val) {
271+
x.store(const_cast<std::remove_cv_t<T> const&>(new_val), std::memory_order::seq_cst);
272+
};
273+
auto load = [](std::atomic_ref<T> const& x) {
209274
auto result = x.load(std::memory_order::relaxed);
210-
T unexpected(T(255));
275+
std::remove_cv_t<T> unexpected(std::remove_cv_t<T>(255));
211276
bool r =
212277
x.compare_exchange_strong(unexpected, unexpected, std::memory_order::relaxed, std::memory_order::seq_cst);
213278
assert(!r);

0 commit comments

Comments
 (0)