xref: /llvm-project/libcxx/test/std/atomics/atomics.ref/compare_exchange_strong.pass.cpp (revision 42ba740afffa16f991be6aa36626bd872d41ebc0)
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 // bool compare_exchange_strong(T&, T, memory_order, memory_order) const noexcept;
13 // bool compare_exchange_strong(T&, T, memory_order = memory_order::seq_cst) const noexcept;
14 
15 #include <atomic>
16 #include <cassert>
17 #include <concepts>
18 #include <type_traits>
19 
20 #include "atomic_helpers.h"
21 #include "test_helper.h"
22 #include "test_macros.h"
23 
24 template <typename T>
25 struct TestCompareExchangeStrong {
26   void operator()() const {
27     {
28       T x(T(1));
29       std::atomic_ref<T> const a(x);
30 
31       T t(T(1));
32       std::same_as<bool> decltype(auto) y = a.compare_exchange_strong(t, T(2));
33       assert(y == true);
34       assert(a == T(2));
35       assert(t == T(1));
36       y = a.compare_exchange_strong(t, T(3));
37       assert(y == false);
38       assert(a == T(2));
39       assert(t == T(2));
40 
41       ASSERT_NOEXCEPT(a.compare_exchange_strong(t, T(2)));
42     }
43     {
44       T x(T(1));
45       std::atomic_ref<T> const a(x);
46 
47       T t(T(1));
48       std::same_as<bool> decltype(auto) y = a.compare_exchange_strong(t, T(2), std::memory_order_seq_cst);
49       assert(y == true);
50       assert(a == T(2));
51       assert(t == T(1));
52       y = a.compare_exchange_strong(t, T(3), std::memory_order_seq_cst);
53       assert(y == false);
54       assert(a == T(2));
55       assert(t == T(2));
56 
57       ASSERT_NOEXCEPT(a.compare_exchange_strong(t, T(2), std::memory_order_seq_cst));
58     }
59     {
60       T x(T(1));
61       std::atomic_ref<T> const a(x);
62 
63       T t(T(1));
64       std::same_as<bool> decltype(auto) y =
65           a.compare_exchange_strong(t, T(2), std::memory_order_release, std::memory_order_relaxed);
66       assert(y == true);
67       assert(a == T(2));
68       assert(t == T(1));
69       y = a.compare_exchange_strong(t, T(3), std::memory_order_release, std::memory_order_relaxed);
70       assert(y == false);
71       assert(a == T(2));
72       assert(t == T(2));
73 
74       ASSERT_NOEXCEPT(a.compare_exchange_strong(t, T(2), std::memory_order_release, std::memory_order_relaxed));
75     }
76 
77     // success memory_order::release
78     {
79       auto store = [](std::atomic_ref<T> const& x, T old_val, T new_val) {
80         auto r = x.compare_exchange_strong(old_val, new_val, std::memory_order::release, std::memory_order::relaxed);
81         assert(r);
82       };
83 
84       auto load = [](std::atomic_ref<T> const& x) { return x.load(std::memory_order::acquire); };
85       test_acquire_release<T>(store, load);
86 
87       auto store_one_arg = [](std::atomic_ref<T> const& x, T old_val, T new_val) {
88         auto r = x.compare_exchange_strong(old_val, new_val, std::memory_order::release);
89         assert(r);
90       };
91       test_acquire_release<T>(store_one_arg, load);
92     }
93 
94     // success memory_order::acquire
95     {
96       auto store = [](std::atomic_ref<T> const& x, T, T new_val) { x.store(new_val, std::memory_order::release); };
97 
98       auto load = [](std::atomic_ref<T> const& x) {
99         auto val = x.load(std::memory_order::relaxed);
100         while (!x.compare_exchange_strong(val, val, std::memory_order::acquire, std::memory_order::relaxed)) {
101         }
102         return val;
103       };
104       test_acquire_release<T>(store, load);
105 
106       auto load_one_arg = [](std::atomic_ref<T> const& x) {
107         auto val = x.load(std::memory_order::relaxed);
108         while (!x.compare_exchange_strong(val, val, std::memory_order::acquire)) {
109         }
110         return val;
111       };
112       test_acquire_release<T>(store, load_one_arg);
113     }
114 
115     // success memory_order::acq_rel
116     {
117       auto store = [](std::atomic_ref<T> const& x, T old_val, T new_val) {
118         auto r = x.compare_exchange_strong(old_val, new_val, std::memory_order::acq_rel, std::memory_order::relaxed);
119         assert(r);
120       };
121       auto load = [](std::atomic_ref<T> const& x) {
122         auto val = x.load(std::memory_order::relaxed);
123         while (!x.compare_exchange_strong(val, val, std::memory_order::acq_rel, std::memory_order::relaxed)) {
124         }
125         return val;
126       };
127       test_acquire_release<T>(store, load);
128 
129       auto store_one_arg = [](std::atomic_ref<T> const& x, T old_val, T new_val) {
130         auto r = x.compare_exchange_strong(old_val, new_val, std::memory_order::acq_rel);
131         assert(r);
132       };
133       auto load_one_arg = [](std::atomic_ref<T> const& x) {
134         auto val = x.load(std::memory_order::relaxed);
135         while (!x.compare_exchange_strong(val, val, std::memory_order::acq_rel)) {
136         }
137         return val;
138       };
139       test_acquire_release<T>(store_one_arg, load_one_arg);
140     }
141 
142     // success memory_order::seq_cst
143     {
144       auto store = [](std::atomic_ref<T> const& x, T old_val, T new_val) {
145         auto r = x.compare_exchange_strong(old_val, new_val, std::memory_order::seq_cst, std::memory_order::relaxed);
146         assert(r);
147       };
148       auto load = [](std::atomic_ref<T> const& x) {
149         auto val = x.load(std::memory_order::relaxed);
150         while (!x.compare_exchange_strong(val, val, std::memory_order::seq_cst, std::memory_order::relaxed)) {
151         }
152         return val;
153       };
154       test_seq_cst<T>(store, load);
155 
156       auto store_one_arg = [](std::atomic_ref<T> const& x, T old_val, T new_val) {
157         auto r = x.compare_exchange_strong(old_val, new_val, std::memory_order::seq_cst);
158         assert(r);
159       };
160       auto load_one_arg = [](std::atomic_ref<T> const& x) {
161         auto val = x.load(std::memory_order::relaxed);
162         while (!x.compare_exchange_strong(val, val, std::memory_order::seq_cst)) {
163         }
164         return val;
165       };
166       test_seq_cst<T>(store_one_arg, load_one_arg);
167     }
168 
169     // failure memory_order::acquire
170     {
171       auto store = [](std::atomic_ref<T> const& x, T, T new_val) { x.store(new_val, std::memory_order::release); };
172       auto load  = [](std::atomic_ref<T> const& x) {
173         auto result = x.load(std::memory_order::relaxed);
174         T unexpected(T(255));
175         bool r =
176             x.compare_exchange_strong(unexpected, unexpected, std::memory_order::relaxed, std::memory_order::acquire);
177         assert(!r);
178         return result;
179       };
180       test_acquire_release<T>(store, load);
181 
182       auto load_one_arg = [](std::atomic_ref<T> const& x) {
183         auto result = x.load(std::memory_order::relaxed);
184         T unexpected(T(255));
185         bool r = x.compare_exchange_strong(unexpected, unexpected, std::memory_order::acquire);
186         assert(!r);
187         return result;
188       };
189       test_acquire_release<T>(store, load_one_arg);
190 
191       // acq_rel replaced by acquire
192       auto load_one_arg_acq_rel = [](std::atomic_ref<T> const& x) {
193         auto result = x.load(std::memory_order::relaxed);
194         T unexpected(T(255));
195         bool r = x.compare_exchange_strong(unexpected, unexpected, std::memory_order::acq_rel);
196         assert(!r);
197         return result;
198       };
199       test_acquire_release<T>(store, load_one_arg_acq_rel);
200     }
201 
202     // failure memory_order::seq_cst
203     {
204       auto store = [](std::atomic_ref<T> const& x, T, T new_val) { x.store(new_val, std::memory_order::seq_cst); };
205       auto load  = [](std::atomic_ref<T> const& x) {
206         auto result = x.load(std::memory_order::relaxed);
207         T unexpected(T(255));
208         bool r =
209             x.compare_exchange_strong(unexpected, unexpected, std::memory_order::relaxed, std::memory_order::seq_cst);
210         assert(!r);
211         return result;
212       };
213       test_seq_cst<T>(store, load);
214     }
215   }
216 };
217 
218 int main(int, char**) {
219   TestEachAtomicType<TestCompareExchangeStrong>()();
220   return 0;
221 }
222