xref: /llvm-project/libcxx/test/std/atomics/atomics.ref/compare_exchange_weak.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_weak(T&, T, memory_order, memory_order) const noexcept;
16 // bool compare_exchange_weak(T&, T, memory_order = memory_order::seq_cst) const noexcept;
17 
18 #include <atomic>
19 #include <concepts>
20 #include <cassert>
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 TestCompareExchangeWeak {
operator ()TestCompareExchangeWeak29   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_weak(t, T(2));
36       assert(y == true);
37       assert(a == T(2));
38       assert(t == T(1));
39       y = a.compare_exchange_weak(t, T(3));
40       assert(y == false);
41       assert(a == T(2));
42       assert(t == T(2));
43 
44       ASSERT_NOEXCEPT(a.compare_exchange_weak(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_weak(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_weak(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_weak(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_weak(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_weak(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_weak(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         // could fail spuriously, so put it in a loop
84         while (!x.compare_exchange_weak(old_val, new_val, std::memory_order::release, std::memory_order::relaxed)) {
85         }
86       };
87 
88       auto load = [](std::atomic_ref<T> const& x) { return x.load(std::memory_order::acquire); };
89       test_acquire_release<T>(store, load);
90 
91       auto store_one_arg = [](std::atomic_ref<T> const& x, T old_val, T new_val) {
92         // could fail spuriously, so put it in a loop
93         while (!x.compare_exchange_weak(old_val, new_val, std::memory_order::release)) {
94         }
95       };
96       test_acquire_release<T>(store_one_arg, load);
97     }
98 
99     // success memory_order::acquire
100     {
101       auto store = [](std::atomic_ref<T> const& x, T, T new_val) { x.store(new_val, std::memory_order::release); };
102       auto load  = [](std::atomic_ref<T> const& x) {
103         auto val = x.load(std::memory_order::relaxed);
104         while (!x.compare_exchange_weak(val, val, std::memory_order::acquire, std::memory_order::relaxed)) {
105         }
106         return val;
107       };
108       test_acquire_release<T>(store, load);
109 
110       auto load_one_arg = [](std::atomic_ref<T> const& x) {
111         auto val = x.load(std::memory_order::relaxed);
112         while (!x.compare_exchange_weak(val, val, std::memory_order::acquire)) {
113         }
114         return val;
115       };
116       test_acquire_release<T>(store, load_one_arg);
117     }
118 
119     // success memory_order::acq_rel
120     {
121       auto store = [](std::atomic_ref<T> const& x, T old_val, T new_val) {
122         // could fail spuriously, so put it in a loop
123         while (!x.compare_exchange_weak(old_val, new_val, std::memory_order::acq_rel, std::memory_order::relaxed)) {
124         }
125       };
126       auto load = [](std::atomic_ref<T> const& x) {
127         auto val = x.load(std::memory_order::relaxed);
128         while (!x.compare_exchange_weak(val, val, std::memory_order::acq_rel, std::memory_order::relaxed)) {
129         }
130         return val;
131       };
132       test_acquire_release<T>(store, load);
133 
134       auto store_one_arg = [](std::atomic_ref<T> const& x, T old_val, T new_val) {
135         // could fail spuriously, so put it in a loop
136         while (!x.compare_exchange_weak(old_val, new_val, std::memory_order::acq_rel)) {
137         }
138       };
139       auto load_one_arg = [](std::atomic_ref<T> const& x) {
140         auto val = x.load(std::memory_order::relaxed);
141         while (!x.compare_exchange_weak(val, val, std::memory_order::acq_rel)) {
142         }
143         return val;
144       };
145       test_acquire_release<T>(store_one_arg, load_one_arg);
146     }
147 
148     // success memory_order::seq_cst
149     {
150       auto store = [](std::atomic_ref<T> const& x, T old_val, T new_val) {
151         // could fail spuriously, so put it in a loop
152         while (!x.compare_exchange_weak(old_val, new_val, std::memory_order::seq_cst, std::memory_order::relaxed)) {
153         }
154       };
155       auto load = [](std::atomic_ref<T> const& x) {
156         auto val = x.load(std::memory_order::relaxed);
157         while (!x.compare_exchange_weak(val, val, std::memory_order::seq_cst, std::memory_order::relaxed)) {
158         }
159         return val;
160       };
161       test_seq_cst<T>(store, load);
162 
163       auto store_one_arg = [](std::atomic_ref<T> const& x, T old_val, T new_val) {
164         // could fail spuriously, so put it in a loop
165         while (!x.compare_exchange_weak(old_val, new_val, std::memory_order::seq_cst)) {
166         }
167       };
168       auto load_one_arg = [](std::atomic_ref<T> const& x) {
169         auto val = x.load(std::memory_order::relaxed);
170         while (!x.compare_exchange_weak(val, val, std::memory_order::seq_cst)) {
171         }
172         return val;
173       };
174       test_seq_cst<T>(store_one_arg, load_one_arg);
175     }
176 
177     // failure memory_order::acquire
178     {
179       auto store = [](std::atomic_ref<T> const& x, T, T new_val) { x.store(new_val, std::memory_order::release); };
180       auto load  = [](std::atomic_ref<T> const& x) {
181         auto result = x.load(std::memory_order::relaxed);
182         T unexpected(T(255));
183         bool r =
184             x.compare_exchange_weak(unexpected, unexpected, std::memory_order::relaxed, std::memory_order::acquire);
185         assert(!r);
186         return result;
187       };
188       test_acquire_release<T>(store, load);
189 
190       auto load_one_arg = [](std::atomic_ref<T> const& x) {
191         auto result = x.load(std::memory_order::relaxed);
192         T unexpected(T(255));
193         bool r = x.compare_exchange_weak(unexpected, unexpected, std::memory_order::acquire);
194         assert(!r);
195         return result;
196       };
197       test_acquire_release<T>(store, load_one_arg);
198 
199       // acq_rel replaced by acquire
200       auto load_one_arg_acq_rel = [](std::atomic_ref<T> const& x) {
201         auto result = x.load(std::memory_order::relaxed);
202         T unexpected(T(255));
203         bool r = x.compare_exchange_weak(unexpected, unexpected, std::memory_order::acq_rel);
204         assert(!r);
205         return result;
206       };
207       test_acquire_release<T>(store, load_one_arg_acq_rel);
208     }
209 
210     // failure memory_order::seq_cst
211     {
212       auto store = [](std::atomic_ref<T> const& x, T, T new_val) { x.store(new_val, std::memory_order::seq_cst); };
213       auto load  = [](std::atomic_ref<T> const& x) {
214         auto result = x.load(std::memory_order::relaxed);
215         T unexpected(T(255));
216         bool r =
217             x.compare_exchange_weak(unexpected, unexpected, std::memory_order::relaxed, std::memory_order::seq_cst);
218         assert(!r);
219         return result;
220       };
221       test_seq_cst<T>(store, load);
222     }
223   }
224 };
225 
main(int,char **)226 int main(int, char**) {
227   TestEachAtomicType<TestCompareExchangeWeak>()();
228   return 0;
229 }
230