230 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_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 27template <typename T>28struct TestCompareExchangeWeak {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_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::release81 {82 auto store = [](std::atomic_ref<T> const& x, T old_val, T new_val) {83 // could fail spuriously, so put it in a loop84 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 loop93 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::acquire100 {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_rel120 {121 auto store = [](std::atomic_ref<T> const& x, T old_val, T new_val) {122 // could fail spuriously, so put it in a loop123 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 loop136 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_cst149 {150 auto store = [](std::atomic_ref<T> const& x, T old_val, T new_val) {151 // could fail spuriously, so put it in a loop152 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 loop165 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::acquire178 {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 acquire200 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_cst211 {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 226int main(int, char**) {227 TestEachAtomicType<TestCompareExchangeWeak>()();228 return 0;229}230