11#include <promeki/config.h>
12#if PROMEKI_ENABLE_CORE
17PROMEKI_NAMESPACE_BEGIN
28enum class MemoryOrder {
43inline constexpr std::memory_order toStdMemoryOrder(MemoryOrder mo) {
45 case MemoryOrder::Relaxed:
return std::memory_order_relaxed;
46 case MemoryOrder::Consume:
return std::memory_order_consume;
47 case MemoryOrder::Acquire:
return std::memory_order_acquire;
48 case MemoryOrder::Release:
return std::memory_order_release;
49 case MemoryOrder::AcqRel:
return std::memory_order_acq_rel;
50 case MemoryOrder::SeqCst:
return std::memory_order_seq_cst;
52 return std::memory_order_seq_cst;
65inline void atomicThreadFence(MemoryOrder mo) {
66 std::atomic_thread_fence(toStdMemoryOrder(mo));
105template <
typename T>
class Atomic {
106 static_assert(std::is_trivially_copyable_v<T>,
107 "Atomic<T> requires T to be trivially copyable (std::atomic requirement)");
122 explicit Atomic() : _value(T{}) {}
125 explicit Atomic(T val) : _value(val) {}
130 Atomic(
const Atomic &) =
delete;
131 Atomic &operator=(
const Atomic &) =
delete;
132 Atomic(Atomic &&) =
delete;
133 Atomic &operator=(Atomic &&) =
delete;
143 T value()
const {
return _value.load(std::memory_order_acquire); }
149 void setValue(T val) { _value.store(val, std::memory_order_release); }
170 bool compareAndSwap(T &expected, T desired) {
171 return _value.compare_exchange_strong(expected, desired, std::memory_order_acq_rel,
172 std::memory_order_acquire);
180 T exchange(T desired) {
return _value.exchange(desired, std::memory_order_acq_rel); }
196 T load(MemoryOrder mo = MemoryOrder::SeqCst)
const {
197 return _value.load(toStdMemoryOrder(mo));
201 void store(T val, MemoryOrder mo = MemoryOrder::SeqCst) {
202 _value.store(val, toStdMemoryOrder(mo));
206 T exchange(T desired, MemoryOrder mo) {
207 return _value.exchange(desired, toStdMemoryOrder(mo));
211 T fetchAndAdd(T val, MemoryOrder mo = MemoryOrder::AcqRel) {
212 return _value.fetch_add(val, toStdMemoryOrder(mo));
216 T fetchAndSub(T val, MemoryOrder mo = MemoryOrder::AcqRel) {
217 return _value.fetch_sub(val, toStdMemoryOrder(mo));
221 T fetchAndAnd(T val, MemoryOrder mo = MemoryOrder::AcqRel) {
222 return _value.fetch_and(val, toStdMemoryOrder(mo));
226 T fetchAndOr(T val, MemoryOrder mo = MemoryOrder::AcqRel) {
227 return _value.fetch_or(val, toStdMemoryOrder(mo));
231 T fetchAndXor(T val, MemoryOrder mo = MemoryOrder::AcqRel) {
232 return _value.fetch_xor(val, toStdMemoryOrder(mo));
240 bool compareExchangeStrong(T &expected, T desired, MemoryOrder success, MemoryOrder failure) {
241 return _value.compare_exchange_strong(expected, desired, toStdMemoryOrder(success),
242 toStdMemoryOrder(failure));
246 bool compareExchangeStrong(T &expected, T desired, MemoryOrder mo = MemoryOrder::SeqCst) {
247 return _value.compare_exchange_strong(expected, desired, toStdMemoryOrder(mo));
257 bool compareExchangeWeak(T &expected, T desired, MemoryOrder success, MemoryOrder failure) {
258 return _value.compare_exchange_weak(expected, desired, toStdMemoryOrder(success),
259 toStdMemoryOrder(failure));
263 bool compareExchangeWeak(T &expected, T desired, MemoryOrder mo = MemoryOrder::SeqCst) {
264 return _value.compare_exchange_weak(expected, desired, toStdMemoryOrder(mo));
276 T operator++() {
return _value.fetch_add(1, std::memory_order_acq_rel) + 1; }
283 T operator++(
int) {
return _value.fetch_add(1, std::memory_order_acq_rel); }
290 T operator--() {
return _value.fetch_sub(1, std::memory_order_acq_rel) - 1; }
297 T operator--(
int) {
return _value.fetch_sub(1, std::memory_order_acq_rel); }
300 std::atomic<T> _value;
339template <
typename T>
class AtomicRef {
340 static_assert(std::is_trivially_copyable_v<T>,
341 "AtomicRef<T> requires T to be trivially copyable (std::atomic_ref requirement)");
354 explicit AtomicRef(T &obj) : _ref(obj) {}
356 AtomicRef(
const AtomicRef &) =
default;
357 AtomicRef &operator=(
const AtomicRef &) =
delete;
358 AtomicRef(AtomicRef &&) =
default;
359 AtomicRef &operator=(AtomicRef &&) =
delete;
362 T load(MemoryOrder mo = MemoryOrder::SeqCst)
const {
363 return _ref.load(toStdMemoryOrder(mo));
367 void store(T val, MemoryOrder mo = MemoryOrder::SeqCst)
const {
368 _ref.store(val, toStdMemoryOrder(mo));
372 T exchange(T desired, MemoryOrder mo = MemoryOrder::SeqCst)
const {
373 return _ref.exchange(desired, toStdMemoryOrder(mo));
377 T fetchAndAdd(T val, MemoryOrder mo = MemoryOrder::AcqRel)
const {
378 return _ref.fetch_add(val, toStdMemoryOrder(mo));
382 T fetchAndSub(T val, MemoryOrder mo = MemoryOrder::AcqRel)
const {
383 return _ref.fetch_sub(val, toStdMemoryOrder(mo));
391 bool compareExchangeStrong(T &expected, T desired, MemoryOrder success, MemoryOrder failure)
const {
392 return _ref.compare_exchange_strong(expected, desired, toStdMemoryOrder(success),
393 toStdMemoryOrder(failure));
397 bool compareExchangeStrong(T &expected, T desired, MemoryOrder mo = MemoryOrder::SeqCst)
const {
398 return _ref.compare_exchange_strong(expected, desired, toStdMemoryOrder(mo));
406 bool compareExchangeWeak(T &expected, T desired, MemoryOrder success, MemoryOrder failure)
const {
407 return _ref.compare_exchange_weak(expected, desired, toStdMemoryOrder(success),
408 toStdMemoryOrder(failure));
412 bool compareExchangeWeak(T &expected, T desired, MemoryOrder mo = MemoryOrder::SeqCst)
const {
413 return _ref.compare_exchange_weak(expected, desired, toStdMemoryOrder(mo));
417 std::atomic_ref<T> _ref;
456 AtomicFlag() noexcept = default;
459 ~AtomicFlag() = default;
461 AtomicFlag(const AtomicFlag &) = delete;
462 AtomicFlag &operator=(const AtomicFlag &) = delete;
463 AtomicFlag(AtomicFlag &&) = delete;
464 AtomicFlag &operator=(AtomicFlag &&) = delete;
477 bool testAndSet(MemoryOrder mo = MemoryOrder::Acquire) noexcept {
478 return _flag.test_and_set(toStdMemoryOrder(mo));
487 void clear(MemoryOrder mo = MemoryOrder::Release)
noexcept {
488 _flag.clear(toStdMemoryOrder(mo));
497 bool test(MemoryOrder mo = MemoryOrder::Acquire)
const noexcept {
498 return _flag.test(toStdMemoryOrder(mo));
502 std::atomic_flag _flag = ATOMIC_FLAG_INIT;