xref: /llvm-project/libcxx/test/std/atomics/atomics.ref/compare_exchange_strong.pass.cpp (revision 266fac8375bdf3f039503c559bb16ffab8895ae5)
1 //
2 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
3 // See https://llvm.org/LICENSE.txt for license information.
4 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
5 //
6 //===----------------------------------------------------------------------===//
7 
8 // UNSUPPORTED: c++03, c++11, c++14, c++17
9 // XFAIL: !has-64-bit-atomics
10 // XFAIL: !has-1024-bit-atomics
11 
12 // MSVC warning C4310: cast truncates constant value
13 // ADDITIONAL_COMPILE_FLAGS(cl-style-warnings): /wd4310
14 
15 // bool compare_exchange_strong(T&, T, memory_order, memory_order) const noexcept;
16 // bool compare_exchange_strong(T&, T, memory_order = memory_order::seq_cst) const noexcept;
17 
18 #include <atomic>
19 #include <cassert>
20 #include <concepts>
21 #include <type_traits>
22 
23 #include "atomic_helpers.h"
24 #include "test_helper.h"
25 #include "test_macros.h"
26 
27 template <typename T>
28 struct TestCompareExchangeStrong {
operator ()TestCompareExchangeStrong29   void operator()() const {
30     {
31       T x(T(1));
32       std::atomic_ref<T> const a(x);
33 
34       T t(T(1));
35       std::same_as<bool> decltype(auto) y = a.compare_exchange_strong(t, T(2));
36       assert(y == true);
37       assert(a == T(2));
38       assert(t == T(1));
39       y = a.compare_exchange_strong(t, T(3));
40       assert(y == false);
41       assert(a == T(2));
42       assert(t == T(2));
43 
44       ASSERT_NOEXCEPT(a.compare_exchange_strong(t, T(2)));
45     }
46     {
47       T x(T(1));
48       std::atomic_ref<T> const a(x);
49 
50       T t(T(1));
51       std::same_as<bool> decltype(auto) y = a.compare_exchange_strong(t, T(2), std::memory_order_seq_cst);
52       assert(y == true);
53       assert(a == T(2));
54       assert(t == T(1));
55       y = a.compare_exchange_strong(t, T(3), std::memory_order_seq_cst);
56       assert(y == false);
57       assert(a == T(2));
58       assert(t == T(2));
59 
60       ASSERT_NOEXCEPT(a.compare_exchange_strong(t, T(2), std::memory_order_seq_cst));
61     }
62     {
63       T x(T(1));
64       std::atomic_ref<T> const a(x);
65 
66       T t(T(1));
67       std::same_as<bool> decltype(auto) y =
68           a.compare_exchange_strong(t, T(2), std::memory_order_release, std::memory_order_relaxed);
69       assert(y == true);
70       assert(a == T(2));
71       assert(t == T(1));
72       y = a.compare_exchange_strong(t, T(3), std::memory_order_release, std::memory_order_relaxed);
73       assert(y == false);
74       assert(a == T(2));
75       assert(t == T(2));
76 
77       ASSERT_NOEXCEPT(a.compare_exchange_strong(t, T(2), std::memory_order_release, std::memory_order_relaxed));
78     }
79 
80     // success memory_order::release
81     {
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);
84         assert(r);
85       };
86 
87       auto load = [](std::atomic_ref<T> const& x) { return x.load(std::memory_order::acquire); };
88       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);
92         assert(r);
93       };
94       test_acquire_release<T>(store_one_arg, load);
95     }
96 
97     // success memory_order::acquire
98     {
99       auto store = [](std::atomic_ref<T> const& x, T, T new_val) { x.store(new_val, std::memory_order::release); };
100 
101       auto load = [](std::atomic_ref<T> const& x) {
102         auto val = x.load(std::memory_order::relaxed);
103         while (!x.compare_exchange_strong(val, val, std::memory_order::acquire, std::memory_order::relaxed)) {
104         }
105         return val;
106       };
107       test_acquire_release<T>(store, load);
108 
109       auto load_one_arg = [](std::atomic_ref<T> const& x) {
110         auto val = x.load(std::memory_order::relaxed);
111         while (!x.compare_exchange_strong(val, val, std::memory_order::acquire)) {
112         }
113         return val;
114       };
115       test_acquire_release<T>(store, load_one_arg);
116     }
117 
118     // success memory_order::acq_rel
119     {
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);
122         assert(r);
123       };
124       auto load = [](std::atomic_ref<T> const& x) {
125         auto val = x.load(std::memory_order::relaxed);
126         while (!x.compare_exchange_strong(val, val, std::memory_order::acq_rel, std::memory_order::relaxed)) {
127         }
128         return val;
129       };
130       test_acquire_release<T>(store, load);
131 
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);
134         assert(r);
135       };
136       auto load_one_arg = [](std::atomic_ref<T> const& x) {
137         auto val = x.load(std::memory_order::relaxed);
138         while (!x.compare_exchange_strong(val, val, std::memory_order::acq_rel)) {
139         }
140         return val;
141       };
142       test_acquire_release<T>(store_one_arg, load_one_arg);
143     }
144 
145     // success memory_order::seq_cst
146     {
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);
149         assert(r);
150       };
151       auto load = [](std::atomic_ref<T> const& x) {
152         auto val = x.load(std::memory_order::relaxed);
153         while (!x.compare_exchange_strong(val, val, std::memory_order::seq_cst, std::memory_order::relaxed)) {
154         }
155         return val;
156       };
157       test_seq_cst<T>(store, load);
158 
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);
161         assert(r);
162       };
163       auto load_one_arg = [](std::atomic_ref<T> const& x) {
164         auto val = x.load(std::memory_order::relaxed);
165         while (!x.compare_exchange_strong(val, val, std::memory_order::seq_cst)) {
166         }
167         return val;
168       };
169       test_seq_cst<T>(store_one_arg, load_one_arg);
170     }
171 
172     // failure memory_order::acquire
173     {
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) {
176         auto result = x.load(std::memory_order::relaxed);
177         T unexpected(T(255));
178         bool r =
179             x.compare_exchange_strong(unexpected, unexpected, std::memory_order::relaxed, std::memory_order::acquire);
180         assert(!r);
181         return result;
182       };
183       test_acquire_release<T>(store, load);
184 
185       auto load_one_arg = [](std::atomic_ref<T> const& x) {
186         auto result = x.load(std::memory_order::relaxed);
187         T unexpected(T(255));
188         bool r = x.compare_exchange_strong(unexpected, unexpected, std::memory_order::acquire);
189         assert(!r);
190         return result;
191       };
192       test_acquire_release<T>(store, load_one_arg);
193 
194       // acq_rel replaced by acquire
195       auto load_one_arg_acq_rel = [](std::atomic_ref<T> const& x) {
196         auto result = x.load(std::memory_order::relaxed);
197         T unexpected(T(255));
198         bool r = x.compare_exchange_strong(unexpected, unexpected, std::memory_order::acq_rel);
199         assert(!r);
200         return result;
201       };
202       test_acquire_release<T>(store, load_one_arg_acq_rel);
203     }
204 
205     // failure memory_order::seq_cst
206     {
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) {
209         auto result = x.load(std::memory_order::relaxed);
210         T unexpected(T(255));
211         bool r =
212             x.compare_exchange_strong(unexpected, unexpected, std::memory_order::relaxed, std::memory_order::seq_cst);
213         assert(!r);
214         return result;
215       };
216       test_seq_cst<T>(store, load);
217     }
218   }
219 };
220 
main(int,char **)221 int main(int, char**) {
222   TestEachAtomicType<TestCompareExchangeStrong>()();
223   return 0;
224 }
225