xref: /llvm-project/libcxx/test/std/atomics/atomics.ref/compare_exchange_weak.pass.cpp (revision 266fac8375bdf3f039503c559bb16ffab8895ae5)
142ba740aSDamien L-G //
242ba740aSDamien L-G // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
342ba740aSDamien L-G // See https://llvm.org/LICENSE.txt for license information.
442ba740aSDamien L-G // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
542ba740aSDamien L-G //
642ba740aSDamien L-G //===----------------------------------------------------------------------===//
742ba740aSDamien L-G 
842ba740aSDamien L-G // UNSUPPORTED: c++03, c++11, c++14, c++17
942ba740aSDamien L-G // XFAIL: !has-64-bit-atomics
1042ba740aSDamien L-G // XFAIL: !has-1024-bit-atomics
1142ba740aSDamien L-G 
12*266fac83SStephan T. Lavavej // MSVC warning C4310: cast truncates constant value
13*266fac83SStephan T. Lavavej // ADDITIONAL_COMPILE_FLAGS(cl-style-warnings): /wd4310
14*266fac83SStephan T. Lavavej 
1542ba740aSDamien L-G // bool compare_exchange_weak(T&, T, memory_order, memory_order) const noexcept;
1642ba740aSDamien L-G // bool compare_exchange_weak(T&, T, memory_order = memory_order::seq_cst) const noexcept;
1742ba740aSDamien L-G 
1842ba740aSDamien L-G #include <atomic>
1942ba740aSDamien L-G #include <concepts>
2042ba740aSDamien L-G #include <cassert>
2142ba740aSDamien L-G #include <type_traits>
2242ba740aSDamien L-G 
2342ba740aSDamien L-G #include "atomic_helpers.h"
2442ba740aSDamien L-G #include "test_helper.h"
2542ba740aSDamien L-G #include "test_macros.h"
2642ba740aSDamien L-G 
2742ba740aSDamien L-G template <typename T>
2842ba740aSDamien L-G struct TestCompareExchangeWeak {
operator ()TestCompareExchangeWeak2942ba740aSDamien L-G   void operator()() const {
3042ba740aSDamien L-G     {
3142ba740aSDamien L-G       T x(T(1));
3242ba740aSDamien L-G       std::atomic_ref<T> const a(x);
3342ba740aSDamien L-G 
3442ba740aSDamien L-G       T t(T(1));
3542ba740aSDamien L-G       std::same_as<bool> decltype(auto) y = a.compare_exchange_weak(t, T(2));
3642ba740aSDamien L-G       assert(y == true);
3742ba740aSDamien L-G       assert(a == T(2));
3842ba740aSDamien L-G       assert(t == T(1));
3942ba740aSDamien L-G       y = a.compare_exchange_weak(t, T(3));
4042ba740aSDamien L-G       assert(y == false);
4142ba740aSDamien L-G       assert(a == T(2));
4242ba740aSDamien L-G       assert(t == T(2));
4342ba740aSDamien L-G 
4442ba740aSDamien L-G       ASSERT_NOEXCEPT(a.compare_exchange_weak(t, T(2)));
4542ba740aSDamien L-G     }
4642ba740aSDamien L-G     {
4742ba740aSDamien L-G       T x(T(1));
4842ba740aSDamien L-G       std::atomic_ref<T> const a(x);
4942ba740aSDamien L-G 
5042ba740aSDamien L-G       T t(T(1));
5142ba740aSDamien L-G       std::same_as<bool> decltype(auto) y = a.compare_exchange_weak(t, T(2), std::memory_order_seq_cst);
5242ba740aSDamien L-G       assert(y == true);
5342ba740aSDamien L-G       assert(a == T(2));
5442ba740aSDamien L-G       assert(t == T(1));
5542ba740aSDamien L-G       y = a.compare_exchange_weak(t, T(3), std::memory_order_seq_cst);
5642ba740aSDamien L-G       assert(y == false);
5742ba740aSDamien L-G       assert(a == T(2));
5842ba740aSDamien L-G       assert(t == T(2));
5942ba740aSDamien L-G 
6042ba740aSDamien L-G       ASSERT_NOEXCEPT(a.compare_exchange_weak(t, T(2), std::memory_order_seq_cst));
6142ba740aSDamien L-G     }
6242ba740aSDamien L-G     {
6342ba740aSDamien L-G       T x(T(1));
6442ba740aSDamien L-G       std::atomic_ref<T> const a(x);
6542ba740aSDamien L-G 
6642ba740aSDamien L-G       T t(T(1));
6742ba740aSDamien L-G       std::same_as<bool> decltype(auto) y =
6842ba740aSDamien L-G           a.compare_exchange_weak(t, T(2), std::memory_order_release, std::memory_order_relaxed);
6942ba740aSDamien L-G       assert(y == true);
7042ba740aSDamien L-G       assert(a == T(2));
7142ba740aSDamien L-G       assert(t == T(1));
7242ba740aSDamien L-G       y = a.compare_exchange_weak(t, T(3), std::memory_order_release, std::memory_order_relaxed);
7342ba740aSDamien L-G       assert(y == false);
7442ba740aSDamien L-G       assert(a == T(2));
7542ba740aSDamien L-G       assert(t == T(2));
7642ba740aSDamien L-G 
7742ba740aSDamien L-G       ASSERT_NOEXCEPT(a.compare_exchange_weak(t, T(2), std::memory_order_release, std::memory_order_relaxed));
7842ba740aSDamien L-G     }
7942ba740aSDamien L-G 
8042ba740aSDamien L-G     // success memory_order::release
8142ba740aSDamien L-G     {
8242ba740aSDamien L-G       auto store = [](std::atomic_ref<T> const& x, T old_val, T new_val) {
8342ba740aSDamien L-G         // could fail spuriously, so put it in a loop
8442ba740aSDamien L-G         while (!x.compare_exchange_weak(old_val, new_val, std::memory_order::release, std::memory_order::relaxed)) {
8542ba740aSDamien L-G         }
8642ba740aSDamien L-G       };
8742ba740aSDamien L-G 
8842ba740aSDamien L-G       auto load = [](std::atomic_ref<T> const& x) { return x.load(std::memory_order::acquire); };
8942ba740aSDamien L-G       test_acquire_release<T>(store, load);
9042ba740aSDamien L-G 
9142ba740aSDamien L-G       auto store_one_arg = [](std::atomic_ref<T> const& x, T old_val, T new_val) {
9242ba740aSDamien L-G         // could fail spuriously, so put it in a loop
9342ba740aSDamien L-G         while (!x.compare_exchange_weak(old_val, new_val, std::memory_order::release)) {
9442ba740aSDamien L-G         }
9542ba740aSDamien L-G       };
9642ba740aSDamien L-G       test_acquire_release<T>(store_one_arg, load);
9742ba740aSDamien L-G     }
9842ba740aSDamien L-G 
9942ba740aSDamien L-G     // success memory_order::acquire
10042ba740aSDamien L-G     {
10142ba740aSDamien L-G       auto store = [](std::atomic_ref<T> const& x, T, T new_val) { x.store(new_val, std::memory_order::release); };
10242ba740aSDamien L-G       auto load  = [](std::atomic_ref<T> const& x) {
10342ba740aSDamien L-G         auto val = x.load(std::memory_order::relaxed);
10442ba740aSDamien L-G         while (!x.compare_exchange_weak(val, val, std::memory_order::acquire, std::memory_order::relaxed)) {
10542ba740aSDamien L-G         }
10642ba740aSDamien L-G         return val;
10742ba740aSDamien L-G       };
10842ba740aSDamien L-G       test_acquire_release<T>(store, load);
10942ba740aSDamien L-G 
11042ba740aSDamien L-G       auto load_one_arg = [](std::atomic_ref<T> const& x) {
11142ba740aSDamien L-G         auto val = x.load(std::memory_order::relaxed);
11242ba740aSDamien L-G         while (!x.compare_exchange_weak(val, val, std::memory_order::acquire)) {
11342ba740aSDamien L-G         }
11442ba740aSDamien L-G         return val;
11542ba740aSDamien L-G       };
11642ba740aSDamien L-G       test_acquire_release<T>(store, load_one_arg);
11742ba740aSDamien L-G     }
11842ba740aSDamien L-G 
11942ba740aSDamien L-G     // success memory_order::acq_rel
12042ba740aSDamien L-G     {
12142ba740aSDamien L-G       auto store = [](std::atomic_ref<T> const& x, T old_val, T new_val) {
12242ba740aSDamien L-G         // could fail spuriously, so put it in a loop
12342ba740aSDamien L-G         while (!x.compare_exchange_weak(old_val, new_val, std::memory_order::acq_rel, std::memory_order::relaxed)) {
12442ba740aSDamien L-G         }
12542ba740aSDamien L-G       };
12642ba740aSDamien L-G       auto load = [](std::atomic_ref<T> const& x) {
12742ba740aSDamien L-G         auto val = x.load(std::memory_order::relaxed);
12842ba740aSDamien L-G         while (!x.compare_exchange_weak(val, val, std::memory_order::acq_rel, std::memory_order::relaxed)) {
12942ba740aSDamien L-G         }
13042ba740aSDamien L-G         return val;
13142ba740aSDamien L-G       };
13242ba740aSDamien L-G       test_acquire_release<T>(store, load);
13342ba740aSDamien L-G 
13442ba740aSDamien L-G       auto store_one_arg = [](std::atomic_ref<T> const& x, T old_val, T new_val) {
13542ba740aSDamien L-G         // could fail spuriously, so put it in a loop
13642ba740aSDamien L-G         while (!x.compare_exchange_weak(old_val, new_val, std::memory_order::acq_rel)) {
13742ba740aSDamien L-G         }
13842ba740aSDamien L-G       };
13942ba740aSDamien L-G       auto load_one_arg = [](std::atomic_ref<T> const& x) {
14042ba740aSDamien L-G         auto val = x.load(std::memory_order::relaxed);
14142ba740aSDamien L-G         while (!x.compare_exchange_weak(val, val, std::memory_order::acq_rel)) {
14242ba740aSDamien L-G         }
14342ba740aSDamien L-G         return val;
14442ba740aSDamien L-G       };
14542ba740aSDamien L-G       test_acquire_release<T>(store_one_arg, load_one_arg);
14642ba740aSDamien L-G     }
14742ba740aSDamien L-G 
14842ba740aSDamien L-G     // success memory_order::seq_cst
14942ba740aSDamien L-G     {
15042ba740aSDamien L-G       auto store = [](std::atomic_ref<T> const& x, T old_val, T new_val) {
15142ba740aSDamien L-G         // could fail spuriously, so put it in a loop
15242ba740aSDamien L-G         while (!x.compare_exchange_weak(old_val, new_val, std::memory_order::seq_cst, std::memory_order::relaxed)) {
15342ba740aSDamien L-G         }
15442ba740aSDamien L-G       };
15542ba740aSDamien L-G       auto load = [](std::atomic_ref<T> const& x) {
15642ba740aSDamien L-G         auto val = x.load(std::memory_order::relaxed);
15742ba740aSDamien L-G         while (!x.compare_exchange_weak(val, val, std::memory_order::seq_cst, std::memory_order::relaxed)) {
15842ba740aSDamien L-G         }
15942ba740aSDamien L-G         return val;
16042ba740aSDamien L-G       };
16142ba740aSDamien L-G       test_seq_cst<T>(store, load);
16242ba740aSDamien L-G 
16342ba740aSDamien L-G       auto store_one_arg = [](std::atomic_ref<T> const& x, T old_val, T new_val) {
16442ba740aSDamien L-G         // could fail spuriously, so put it in a loop
16542ba740aSDamien L-G         while (!x.compare_exchange_weak(old_val, new_val, std::memory_order::seq_cst)) {
16642ba740aSDamien L-G         }
16742ba740aSDamien L-G       };
16842ba740aSDamien L-G       auto load_one_arg = [](std::atomic_ref<T> const& x) {
16942ba740aSDamien L-G         auto val = x.load(std::memory_order::relaxed);
17042ba740aSDamien L-G         while (!x.compare_exchange_weak(val, val, std::memory_order::seq_cst)) {
17142ba740aSDamien L-G         }
17242ba740aSDamien L-G         return val;
17342ba740aSDamien L-G       };
17442ba740aSDamien L-G       test_seq_cst<T>(store_one_arg, load_one_arg);
17542ba740aSDamien L-G     }
17642ba740aSDamien L-G 
17742ba740aSDamien L-G     // failure memory_order::acquire
17842ba740aSDamien L-G     {
17942ba740aSDamien L-G       auto store = [](std::atomic_ref<T> const& x, T, T new_val) { x.store(new_val, std::memory_order::release); };
18042ba740aSDamien L-G       auto load  = [](std::atomic_ref<T> const& x) {
18142ba740aSDamien L-G         auto result = x.load(std::memory_order::relaxed);
18242ba740aSDamien L-G         T unexpected(T(255));
18342ba740aSDamien L-G         bool r =
18442ba740aSDamien L-G             x.compare_exchange_weak(unexpected, unexpected, std::memory_order::relaxed, std::memory_order::acquire);
18542ba740aSDamien L-G         assert(!r);
18642ba740aSDamien L-G         return result;
18742ba740aSDamien L-G       };
18842ba740aSDamien L-G       test_acquire_release<T>(store, load);
18942ba740aSDamien L-G 
19042ba740aSDamien L-G       auto load_one_arg = [](std::atomic_ref<T> const& x) {
19142ba740aSDamien L-G         auto result = x.load(std::memory_order::relaxed);
19242ba740aSDamien L-G         T unexpected(T(255));
19342ba740aSDamien L-G         bool r = x.compare_exchange_weak(unexpected, unexpected, std::memory_order::acquire);
19442ba740aSDamien L-G         assert(!r);
19542ba740aSDamien L-G         return result;
19642ba740aSDamien L-G       };
19742ba740aSDamien L-G       test_acquire_release<T>(store, load_one_arg);
19842ba740aSDamien L-G 
19942ba740aSDamien L-G       // acq_rel replaced by acquire
20042ba740aSDamien L-G       auto load_one_arg_acq_rel = [](std::atomic_ref<T> const& x) {
20142ba740aSDamien L-G         auto result = x.load(std::memory_order::relaxed);
20242ba740aSDamien L-G         T unexpected(T(255));
20342ba740aSDamien L-G         bool r = x.compare_exchange_weak(unexpected, unexpected, std::memory_order::acq_rel);
20442ba740aSDamien L-G         assert(!r);
20542ba740aSDamien L-G         return result;
20642ba740aSDamien L-G       };
20742ba740aSDamien L-G       test_acquire_release<T>(store, load_one_arg_acq_rel);
20842ba740aSDamien L-G     }
20942ba740aSDamien L-G 
21042ba740aSDamien L-G     // failure memory_order::seq_cst
21142ba740aSDamien L-G     {
21242ba740aSDamien L-G       auto store = [](std::atomic_ref<T> const& x, T, T new_val) { x.store(new_val, std::memory_order::seq_cst); };
21342ba740aSDamien L-G       auto load  = [](std::atomic_ref<T> const& x) {
21442ba740aSDamien L-G         auto result = x.load(std::memory_order::relaxed);
21542ba740aSDamien L-G         T unexpected(T(255));
21642ba740aSDamien L-G         bool r =
21742ba740aSDamien L-G             x.compare_exchange_weak(unexpected, unexpected, std::memory_order::relaxed, std::memory_order::seq_cst);
21842ba740aSDamien L-G         assert(!r);
21942ba740aSDamien L-G         return result;
22042ba740aSDamien L-G       };
22142ba740aSDamien L-G       test_seq_cst<T>(store, load);
22242ba740aSDamien L-G     }
22342ba740aSDamien L-G   }
22442ba740aSDamien L-G };
22542ba740aSDamien L-G 
main(int,char **)22642ba740aSDamien L-G int main(int, char**) {
22742ba740aSDamien L-G   TestEachAtomicType<TestCompareExchangeWeak>()();
22842ba740aSDamien L-G   return 0;
22942ba740aSDamien L-G }
230