225 lines · cpp
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-exception5//6//===----------------------------------------------------------------------===//7 8// UNSUPPORTED: c++03, c++11, c++14, c++179// XFAIL: !has-64-bit-atomics10// XFAIL: !has-1024-bit-atomics11 12// MSVC warning C4310: cast truncates constant value13// ADDITIONAL_COMPILE_FLAGS(cl-style-warnings): /wd431014 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 27template <typename T>28struct TestCompareExchangeStrong {29 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::release81 {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::acquire98 {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_rel119 {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_cst146 {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::acquire173 {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 acquire195 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_cst206 {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 221int main(int, char**) {222 TestEachAtomicType<TestCompareExchangeStrong>()();223 return 0;224}225