///////////////////////////////////////////////////////////////////////////// // Copyright (c) Electronic Arts Inc. All rights reserved. ///////////////////////////////////////////////////////////////////////////// #include "EASTLTest.h" #include /** * This is a basic test suite that tests all functionality is implemented * and that all operations do as expected. * I.E. fetch_add returns the previous value and add_fetch returns the current value */ static eastl::atomic sAtomicInt{ 4 }; static eastl::atomic sAtomicPtr{ nullptr }; static int TestAtomicConstantInitialization() { int nErrorCount; EATEST_VERIFY(sAtomicInt.load() == 4); EATEST_VERIFY(sAtomicPtr == nullptr); return 0; } class AtomicStandaloneBasicTest { public: int RunTest() { AtomicSignalFence(); AtomicThreadFence(); AtomicCpuPause(); AtomicCompilerBarrier(); return nErrorCount; } private: void AtomicSignalFence(); void AtomicThreadFence(); void AtomicCpuPause(); void AtomicCompilerBarrier(); private: int nErrorCount = 0; }; void AtomicStandaloneBasicTest::AtomicSignalFence() { eastl::atomic_signal_fence(eastl::memory_order_relaxed); eastl::atomic_signal_fence(eastl::memory_order_acquire); eastl::atomic_signal_fence(eastl::memory_order_release); eastl::atomic_signal_fence(eastl::memory_order_acq_rel); eastl::atomic_signal_fence(eastl::memory_order_seq_cst); } void AtomicStandaloneBasicTest::AtomicThreadFence() { eastl::atomic_thread_fence(eastl::memory_order_relaxed); eastl::atomic_thread_fence(eastl::memory_order_acquire); eastl::atomic_thread_fence(eastl::memory_order_release); eastl::atomic_thread_fence(eastl::memory_order_acq_rel); eastl::atomic_thread_fence(eastl::memory_order_seq_cst); } void AtomicStandaloneBasicTest::AtomicCpuPause() { eastl::cpu_pause(); } void AtomicStandaloneBasicTest::AtomicCompilerBarrier() { eastl::compiler_barrier(); { bool ret = false; eastl::compiler_barrier_data_dependency(ret); } } class AtomicFlagBasicTest { public: using AtomicType = eastl::atomic_flag; using BoolType = bool; int RunTest() { TestAtomicFlagCtor(); TestAtomicFlagClear(); TestAtomicFlagTestAndSet(); TestAtomicFlagTest(); TestAllMemoryOrders(); TestAtomicFlagStandalone(); return nErrorCount; } private: void TestAtomicFlagCtor(); void TestAtomicFlagClear(); void TestAtomicFlagTestAndSet(); void TestAtomicFlagTest(); void TestAllMemoryOrders(); void TestAtomicFlagStandalone(); private: int nErrorCount = 0; }; void AtomicFlagBasicTest::TestAtomicFlagCtor() { { AtomicType atomic; VERIFY(atomic.test(eastl::memory_order_relaxed) == false); } { AtomicType atomic{ false }; VERIFY(atomic.test(eastl::memory_order_relaxed) == false); } { AtomicType atomic{ true }; VERIFY(atomic.test(eastl::memory_order_relaxed) == true); } } void AtomicFlagBasicTest::TestAtomicFlagClear() { { AtomicType atomic; atomic.clear(eastl::memory_order_relaxed); VERIFY(atomic.test(eastl::memory_order_relaxed) == false); } { AtomicType atomic{ true }; atomic.clear(eastl::memory_order_relaxed); VERIFY(atomic.test(eastl::memory_order_relaxed) == false); } } void AtomicFlagBasicTest::TestAtomicFlagTestAndSet() { { AtomicType atomic; BoolType ret = atomic.test_and_set(eastl::memory_order_relaxed); VERIFY(ret == false); VERIFY(atomic.test(eastl::memory_order_relaxed) == true); } { AtomicType atomic{ true }; BoolType ret = atomic.test_and_set(eastl::memory_order_relaxed); VERIFY(ret == true); VERIFY(atomic.test(eastl::memory_order_relaxed) == true); } } void AtomicFlagBasicTest::TestAtomicFlagTest() { { AtomicType atomic; VERIFY(atomic.test(eastl::memory_order_relaxed) == false); } { AtomicType atomic{ true }; VERIFY(atomic.test(eastl::memory_order_relaxed) == true); } } void AtomicFlagBasicTest::TestAllMemoryOrders() { { AtomicType atomic; atomic.clear(); atomic.clear(eastl::memory_order_relaxed); atomic.clear(eastl::memory_order_release); atomic.clear(eastl::memory_order_seq_cst); } { AtomicType atomic; atomic.test_and_set(); atomic.test_and_set(eastl::memory_order_relaxed); atomic.test_and_set(eastl::memory_order_acquire); atomic.test_and_set(eastl::memory_order_release); atomic.test_and_set(eastl::memory_order_acq_rel); atomic.test_and_set(eastl::memory_order_seq_cst); } { AtomicType atomic; BoolType ret = atomic.test(); ret = atomic.test(eastl::memory_order_relaxed); ret = atomic.test(eastl::memory_order_acquire); ret = atomic.test(eastl::memory_order_seq_cst); } } void AtomicFlagBasicTest::TestAtomicFlagStandalone() { { AtomicType atomic; BoolType ret = atomic_flag_test_and_set(&atomic); ret = atomic_flag_test_and_set_explicit(&atomic, eastl::memory_order_relaxed); ret = atomic_flag_test_and_set_explicit(&atomic, eastl::memory_order_acquire); ret = atomic_flag_test_and_set_explicit(&atomic, eastl::memory_order_release); ret = atomic_flag_test_and_set_explicit(&atomic, eastl::memory_order_acq_rel); ret = atomic_flag_test_and_set_explicit(&atomic, eastl::memory_order_seq_cst); } { AtomicType atomic; atomic_flag_clear(&atomic); atomic_flag_clear_explicit(&atomic, eastl::memory_order_relaxed); atomic_flag_clear_explicit(&atomic, eastl::memory_order_release); atomic_flag_clear_explicit(&atomic, eastl::memory_order_seq_cst); } { AtomicType atomic; BoolType ret = atomic_flag_test(&atomic); ret = atomic_flag_test_explicit(&atomic, eastl::memory_order_relaxed); ret = atomic_flag_test_explicit(&atomic, eastl::memory_order_acquire); ret = atomic_flag_test_explicit(&atomic, eastl::memory_order_seq_cst); } } class AtomicVoidPointerBasicTest { public: using AtomicType = eastl::atomic; using PtrType = void*; int RunTest() { TestAtomicCtor(); TestAssignmentOperators(); TestIsLockFree(); TestStore(); TestLoad(); TestExchange(); TestCompareExchangeWeak(); TestCompareExchangeStrong(); TestAllMemoryOrders(); return nErrorCount; } private: void TestAtomicCtor(); void TestAssignmentOperators(); void TestIsLockFree(); void TestStore(); void TestLoad(); void TestExchange(); void TestCompareExchangeWeak(); void TestCompareExchangeStrong(); void TestAllMemoryOrders(); private: int nErrorCount = 0; }; void AtomicVoidPointerBasicTest::TestAtomicCtor() { { AtomicType atomic; VERIFY(atomic.load(eastl::memory_order_relaxed) == (PtrType)0x0); } { AtomicType atomic{ (PtrType)0x04 }; VERIFY(atomic.load(eastl::memory_order_relaxed) == (PtrType)0x04); } } void AtomicVoidPointerBasicTest::TestAssignmentOperators() { { AtomicType atomic; PtrType ret = atomic = (PtrType)0x04; VERIFY(ret == (PtrType)0x04); VERIFY(atomic.load(eastl::memory_order_relaxed) == (PtrType)0x04); } { AtomicType atomic; PtrType ret = atomic = (PtrType)0x0; VERIFY(ret == (PtrType)0x0); VERIFY(atomic.load(eastl::memory_order_relaxed) == (PtrType)0x0); } } void AtomicVoidPointerBasicTest::TestIsLockFree() { { AtomicType atomic; VERIFY(atomic.is_lock_free() == true); VERIFY(atomic.is_always_lock_free == true); } } void AtomicVoidPointerBasicTest::TestStore() { { PtrType val = (PtrType)0x0; AtomicType atomic; atomic.store(val, eastl::memory_order_relaxed); VERIFY(atomic.load(eastl::memory_order_relaxed) == val); } { PtrType val = (PtrType)0x4; AtomicType atomic; atomic.store(val, eastl::memory_order_relaxed); VERIFY(atomic.load(eastl::memory_order_relaxed) == val); } } void AtomicVoidPointerBasicTest::TestLoad() { { AtomicType atomic{ (PtrType)0x4 }; PtrType ret = atomic.load(eastl::memory_order_relaxed); VERIFY(ret == (PtrType)0x4); VERIFY(atomic == (PtrType)0x4); } } void AtomicVoidPointerBasicTest::TestExchange() { { AtomicType atomic; PtrType ret = atomic.exchange((PtrType)0x4, eastl::memory_order_release); VERIFY(ret == (PtrType)0x0); VERIFY(atomic.load(eastl::memory_order_relaxed) == (PtrType)0x4); } } void AtomicVoidPointerBasicTest::TestCompareExchangeWeak() { { AtomicType atomic; PtrType observed = (PtrType)0x0; bool ret = atomic.compare_exchange_weak(observed, (PtrType)0x4, eastl::memory_order_relaxed); if (ret) { VERIFY(ret == true); VERIFY(observed == (PtrType)0x0); VERIFY(atomic.load(eastl::memory_order_relaxed) == (PtrType)0x4); } } { AtomicType atomic; PtrType observed = (PtrType)0x4; bool ret = atomic.compare_exchange_weak(observed, (PtrType)0x4, eastl::memory_order_relaxed); VERIFY(ret == false); VERIFY(observed == (PtrType)0x0); VERIFY(atomic.load(eastl::memory_order_relaxed) == (PtrType)0x0); } } void AtomicVoidPointerBasicTest::TestCompareExchangeStrong() { { AtomicType atomic; PtrType observed = (PtrType)0x0; bool ret = atomic.compare_exchange_strong(observed, (PtrType)0x4, eastl::memory_order_relaxed); VERIFY(ret == true); VERIFY(observed == (PtrType)0x0); VERIFY(atomic.load(eastl::memory_order_relaxed) == (PtrType)0x4); } { AtomicType atomic; PtrType observed = (PtrType)0x4; bool ret = atomic.compare_exchange_strong(observed, (PtrType)0x4, eastl::memory_order_relaxed); VERIFY(ret == false); VERIFY(observed == (PtrType)0x0); VERIFY(atomic.load(eastl::memory_order_relaxed) == (PtrType)0x0); } } void AtomicVoidPointerBasicTest::TestAllMemoryOrders() { { AtomicType atomic; PtrType val = (PtrType)0x4; atomic.store(val); atomic.store(val, eastl::memory_order_relaxed); atomic.store(val, eastl::memory_order_release); atomic.store(val, eastl::memory_order_seq_cst); } { AtomicType atomic; PtrType ret = atomic.load(); ret = atomic.load(eastl::memory_order_relaxed); ret = atomic.load(eastl::memory_order_acquire); ret = atomic.load(eastl::memory_order_seq_cst); ret = atomic.load(eastl::memory_order_read_depends); } { AtomicType atomic; PtrType ret = atomic.exchange((PtrType)0x4); ret = atomic.exchange((PtrType)0x4, eastl::memory_order_relaxed); ret = atomic.exchange((PtrType)0x4, eastl::memory_order_acquire); ret = atomic.exchange((PtrType)0x4, eastl::memory_order_release); ret = atomic.exchange((PtrType)0x4, eastl::memory_order_acq_rel); ret = atomic.exchange((PtrType)0x4, eastl::memory_order_seq_cst); } { AtomicType atomic; PtrType observed = (PtrType)0x0; bool ret = atomic.compare_exchange_weak(observed, (PtrType)0x4); ret = atomic.compare_exchange_weak(observed, (PtrType)0x4, eastl::memory_order_relaxed); ret = atomic.compare_exchange_weak(observed, (PtrType)0x4, eastl::memory_order_acquire); ret = atomic.compare_exchange_weak(observed, (PtrType)0x4, eastl::memory_order_release); ret = atomic.compare_exchange_weak(observed, (PtrType)0x4, eastl::memory_order_acq_rel); ret = atomic.compare_exchange_weak(observed, (PtrType)0x4, eastl::memory_order_seq_cst); } { AtomicType atomic; PtrType observed = (PtrType)0x0; bool ret = atomic.compare_exchange_strong(observed, (PtrType)0x4); ret = atomic.compare_exchange_strong(observed, (PtrType)0x4, eastl::memory_order_relaxed); ret = atomic.compare_exchange_strong(observed, (PtrType)0x4, eastl::memory_order_acquire); ret = atomic.compare_exchange_strong(observed, (PtrType)0x4, eastl::memory_order_release); ret = atomic.compare_exchange_strong(observed, (PtrType)0x4, eastl::memory_order_acq_rel); ret = atomic.compare_exchange_strong(observed, (PtrType)0x4, eastl::memory_order_seq_cst); } { AtomicType atomic; PtrType observed = (PtrType)0x0; bool ret; ret = atomic.compare_exchange_weak(observed, (PtrType)0x4, eastl::memory_order_relaxed, eastl::memory_order_relaxed); ret = atomic.compare_exchange_weak(observed, (PtrType)0x4, eastl::memory_order_acquire, eastl::memory_order_relaxed); ret = atomic.compare_exchange_weak(observed, (PtrType)0x4, eastl::memory_order_acquire, eastl::memory_order_acquire); ret = atomic.compare_exchange_weak(observed, (PtrType)0x4, eastl::memory_order_release, eastl::memory_order_relaxed); ret = atomic.compare_exchange_weak(observed, (PtrType)0x4, eastl::memory_order_acq_rel, eastl::memory_order_relaxed); ret = atomic.compare_exchange_weak(observed, (PtrType)0x4, eastl::memory_order_acq_rel, eastl::memory_order_acquire); ret = atomic.compare_exchange_weak(observed, (PtrType)0x4, eastl::memory_order_seq_cst, eastl::memory_order_relaxed); ret = atomic.compare_exchange_weak(observed, (PtrType)0x4, eastl::memory_order_seq_cst, eastl::memory_order_acquire); ret = atomic.compare_exchange_weak(observed, (PtrType)0x4, eastl::memory_order_seq_cst, eastl::memory_order_seq_cst); } { AtomicType atomic; PtrType observed = (PtrType)0x0; bool ret; ret = atomic.compare_exchange_strong(observed, (PtrType)0x4, eastl::memory_order_relaxed, eastl::memory_order_relaxed); ret = atomic.compare_exchange_strong(observed, (PtrType)0x4, eastl::memory_order_acquire, eastl::memory_order_relaxed); ret = atomic.compare_exchange_strong(observed, (PtrType)0x4, eastl::memory_order_acquire, eastl::memory_order_acquire); ret = atomic.compare_exchange_strong(observed, (PtrType)0x4, eastl::memory_order_release, eastl::memory_order_relaxed); ret = atomic.compare_exchange_strong(observed, (PtrType)0x4, eastl::memory_order_acq_rel, eastl::memory_order_relaxed); ret = atomic.compare_exchange_strong(observed, (PtrType)0x4, eastl::memory_order_acq_rel, eastl::memory_order_acquire); ret = atomic.compare_exchange_strong(observed, (PtrType)0x4, eastl::memory_order_seq_cst, eastl::memory_order_relaxed); ret = atomic.compare_exchange_strong(observed, (PtrType)0x4, eastl::memory_order_seq_cst, eastl::memory_order_acquire); ret = atomic.compare_exchange_strong(observed, (PtrType)0x4, eastl::memory_order_seq_cst, eastl::memory_order_seq_cst); } } class AtomicPointerBasicTest { public: using AtomicType = eastl::atomic; using PtrType = uint32_t*; int RunTest() { TestAtomicCtor(); TestAssignmentOperators(); TestIsLockFree(); TestStore(); TestLoad(); TestExchange(); TestCompareExchangeWeak(); TestCompareExchangeStrong(); TestAllMemoryOrders(); TestFetchAdd(); TestAddFetch(); TestFetchSub(); TestSubFetch(); TestAtomicPointerStandalone(); return nErrorCount; } private: void TestAtomicCtor(); void TestAssignmentOperators(); void TestIsLockFree(); void TestStore(); void TestLoad(); void TestExchange(); void TestCompareExchangeWeak(); void TestCompareExchangeStrong(); void TestAllMemoryOrders(); void TestFetchAdd(); void TestAddFetch(); void TestFetchSub(); void TestSubFetch(); void TestAtomicPointerStandalone(); private: int nErrorCount = 0; }; void AtomicPointerBasicTest::TestAtomicCtor() { { AtomicType atomic{}; PtrType ret = atomic.load(eastl::memory_order_relaxed); VERIFY(ret == nullptr); } { AtomicType atomic{ (PtrType)0x4 }; PtrType ret = atomic.load(eastl::memory_order_relaxed); VERIFY(ret == (PtrType)0x4); } } void AtomicPointerBasicTest::TestAssignmentOperators() { { PtrType val = (PtrType)0x4; AtomicType atomic{val}; PtrType expected = (PtrType)0x8; PtrType ret = atomic = expected; VERIFY(ret == expected); VERIFY(atomic.load(eastl::memory_order_relaxed) == expected); } { PtrType val = (PtrType)0x0; AtomicType atomic{val}; PtrType ret = atomic = val; VERIFY(ret == val); VERIFY(atomic.load(eastl::memory_order_relaxed) == val); } { PtrType val = (PtrType)0x4; AtomicType atomic{val}; PtrType expected = (PtrType)0x8; PtrType ret = ++atomic; VERIFY(ret == expected); VERIFY(atomic.load(eastl::memory_order_relaxed) == expected); } { PtrType val = (PtrType)0x4; AtomicType atomic{val}; PtrType expected = (PtrType)0x8; PtrType ret = atomic++; VERIFY(ret == val); VERIFY(atomic.load(eastl::memory_order_relaxed) == expected); } { PtrType val = (PtrType)0x4; AtomicType atomic{val}; PtrType expected = (PtrType)0x10; PtrType ret = atomic += 3; VERIFY(ret == expected); VERIFY(atomic.load(eastl::memory_order_relaxed) == expected); } { PtrType val = (PtrType)0x4; AtomicType atomic{val}; PtrType expected = (PtrType)0x4; PtrType ret = atomic += 0; VERIFY(ret == expected); VERIFY(atomic.load(eastl::memory_order_relaxed) == expected); } { PtrType val = (PtrType)0x4; AtomicType atomic{val}; PtrType expected = (PtrType)0x0; PtrType ret = atomic -= 1; VERIFY(ret == expected); VERIFY(atomic.load(eastl::memory_order_relaxed) == expected); } { PtrType val = (PtrType)0x4; AtomicType atomic{val}; PtrType expected = (PtrType)0x4; PtrType ret = atomic -= 0; VERIFY(ret == expected); VERIFY(atomic.load(eastl::memory_order_relaxed) == expected); } } void AtomicPointerBasicTest::TestIsLockFree() { { AtomicType atomic; VERIFY(atomic.is_lock_free() == true); VERIFY(atomic.is_always_lock_free == true); } } void AtomicPointerBasicTest::TestStore() { { PtrType val = (PtrType)0x0; AtomicType atomic; atomic.store(val, eastl::memory_order_relaxed); VERIFY(atomic.load(eastl::memory_order_relaxed) == val); } { PtrType val = (PtrType)0x4; AtomicType atomic; atomic.store(val, eastl::memory_order_relaxed); VERIFY(atomic.load(eastl::memory_order_relaxed) == val); } } void AtomicPointerBasicTest::TestLoad() { { AtomicType atomic{ (PtrType)0x4 }; PtrType ret = atomic.load(eastl::memory_order_relaxed); VERIFY(ret == (PtrType)0x4); VERIFY(atomic == (PtrType)0x4); } } void AtomicPointerBasicTest::TestCompareExchangeWeak() { { AtomicType atomic; PtrType observed = (PtrType)0x0; bool ret = atomic.compare_exchange_weak(observed, (PtrType)0x4, eastl::memory_order_relaxed); if (ret) { VERIFY(ret == true); VERIFY(observed == (PtrType)0x0); VERIFY(atomic.load(eastl::memory_order_relaxed) == (PtrType)0x4); } } { AtomicType atomic; PtrType observed = (PtrType)0x4; bool ret = atomic.compare_exchange_weak(observed, (PtrType)0x4, eastl::memory_order_relaxed); VERIFY(ret == false); VERIFY(observed == (PtrType)0x0); VERIFY(atomic.load(eastl::memory_order_relaxed) == (PtrType)0x0); } } void AtomicPointerBasicTest::TestCompareExchangeStrong() { { AtomicType atomic; PtrType observed = (PtrType)0x0; bool ret = atomic.compare_exchange_strong(observed, (PtrType)0x4, eastl::memory_order_relaxed); VERIFY(ret == true); VERIFY(observed == (PtrType)0x0); VERIFY(atomic.load(eastl::memory_order_relaxed) == (PtrType)0x4); } { AtomicType atomic; PtrType observed = (PtrType)0x4; bool ret = atomic.compare_exchange_strong(observed, (PtrType)0x4, eastl::memory_order_relaxed); VERIFY(ret == false); VERIFY(observed == (PtrType)0x0); VERIFY(atomic.load(eastl::memory_order_relaxed) == (PtrType)0x0); } } void AtomicPointerBasicTest::TestExchange() { { AtomicType atomic; PtrType ret = atomic.exchange((PtrType)0x4, eastl::memory_order_release); VERIFY(ret == (PtrType)0x0); VERIFY(atomic.load(eastl::memory_order_relaxed) == (PtrType)0x4); } } void AtomicPointerBasicTest::TestAllMemoryOrders() { { AtomicType atomic; PtrType val = (PtrType)0x4; atomic.store(val); atomic.store(val, eastl::memory_order_relaxed); atomic.store(val, eastl::memory_order_release); atomic.store(val, eastl::memory_order_seq_cst); } { AtomicType atomic; PtrType ret = atomic.load(); ret = atomic.load(eastl::memory_order_relaxed); ret = atomic.load(eastl::memory_order_acquire); ret = atomic.load(eastl::memory_order_seq_cst); ret = atomic.load(eastl::memory_order_read_depends); } { AtomicType atomic; PtrType ret = atomic.fetch_add(0); ret = atomic.fetch_add(0, eastl::memory_order_relaxed); ret = atomic.fetch_add(0, eastl::memory_order_acquire); ret = atomic.fetch_add(0, eastl::memory_order_release); ret = atomic.fetch_add(0, eastl::memory_order_acq_rel); ret = atomic.fetch_add(0, eastl::memory_order_seq_cst); } { AtomicType atomic; PtrType ret = atomic.fetch_sub(0); ret = atomic.fetch_sub(0, eastl::memory_order_relaxed); ret = atomic.fetch_sub(0, eastl::memory_order_acquire); ret = atomic.fetch_sub(0, eastl::memory_order_release); ret = atomic.fetch_sub(0, eastl::memory_order_acq_rel); ret = atomic.fetch_sub(0, eastl::memory_order_seq_cst); } { AtomicType atomic; PtrType ret = atomic.add_fetch(0); ret = atomic.add_fetch(0, eastl::memory_order_relaxed); ret = atomic.add_fetch(0, eastl::memory_order_acquire); ret = atomic.add_fetch(0, eastl::memory_order_release); ret = atomic.add_fetch(0, eastl::memory_order_acq_rel); ret = atomic.add_fetch(0, eastl::memory_order_seq_cst); } { AtomicType atomic; PtrType ret = atomic.sub_fetch(0); ret = atomic.sub_fetch(0, eastl::memory_order_relaxed); ret = atomic.sub_fetch(0, eastl::memory_order_acquire); ret = atomic.sub_fetch(0, eastl::memory_order_release); ret = atomic.sub_fetch(0, eastl::memory_order_acq_rel); ret = atomic.sub_fetch(0, eastl::memory_order_seq_cst); } { AtomicType atomic; PtrType ret = atomic.exchange((PtrType)0x4); ret = atomic.exchange((PtrType)0x4, eastl::memory_order_relaxed); ret = atomic.exchange((PtrType)0x4, eastl::memory_order_acquire); ret = atomic.exchange((PtrType)0x4, eastl::memory_order_release); ret = atomic.exchange((PtrType)0x4, eastl::memory_order_acq_rel); ret = atomic.exchange((PtrType)0x4, eastl::memory_order_seq_cst); } { AtomicType atomic; PtrType observed = (PtrType)0x0; bool ret = atomic.compare_exchange_weak(observed, (PtrType)0x4); ret = atomic.compare_exchange_weak(observed, (PtrType)0x4, eastl::memory_order_relaxed); ret = atomic.compare_exchange_weak(observed, (PtrType)0x4, eastl::memory_order_acquire); ret = atomic.compare_exchange_weak(observed, (PtrType)0x4, eastl::memory_order_release); ret = atomic.compare_exchange_weak(observed, (PtrType)0x4, eastl::memory_order_acq_rel); ret = atomic.compare_exchange_weak(observed, (PtrType)0x4, eastl::memory_order_seq_cst); } { AtomicType atomic; PtrType observed = (PtrType)0x0; bool ret = atomic.compare_exchange_strong(observed, (PtrType)0x4); ret = atomic.compare_exchange_strong(observed, (PtrType)0x4, eastl::memory_order_relaxed); ret = atomic.compare_exchange_strong(observed, (PtrType)0x4, eastl::memory_order_acquire); ret = atomic.compare_exchange_strong(observed, (PtrType)0x4, eastl::memory_order_release); ret = atomic.compare_exchange_strong(observed, (PtrType)0x4, eastl::memory_order_acq_rel); ret = atomic.compare_exchange_strong(observed, (PtrType)0x4, eastl::memory_order_seq_cst); } { AtomicType atomic; PtrType observed = (PtrType)0x0; bool ret; ret = atomic.compare_exchange_weak(observed, (PtrType)0x4, eastl::memory_order_relaxed, eastl::memory_order_relaxed); ret = atomic.compare_exchange_weak(observed, (PtrType)0x4, eastl::memory_order_acquire, eastl::memory_order_relaxed); ret = atomic.compare_exchange_weak(observed, (PtrType)0x4, eastl::memory_order_acquire, eastl::memory_order_acquire); ret = atomic.compare_exchange_weak(observed, (PtrType)0x4, eastl::memory_order_release, eastl::memory_order_relaxed); ret = atomic.compare_exchange_weak(observed, (PtrType)0x4, eastl::memory_order_acq_rel, eastl::memory_order_relaxed); ret = atomic.compare_exchange_weak(observed, (PtrType)0x4, eastl::memory_order_acq_rel, eastl::memory_order_acquire); ret = atomic.compare_exchange_weak(observed, (PtrType)0x4, eastl::memory_order_seq_cst, eastl::memory_order_relaxed); ret = atomic.compare_exchange_weak(observed, (PtrType)0x4, eastl::memory_order_seq_cst, eastl::memory_order_acquire); ret = atomic.compare_exchange_weak(observed, (PtrType)0x4, eastl::memory_order_seq_cst, eastl::memory_order_seq_cst); } { AtomicType atomic; PtrType observed = (PtrType)0x0; bool ret; ret = atomic.compare_exchange_strong(observed, (PtrType)0x4, eastl::memory_order_relaxed, eastl::memory_order_relaxed); ret = atomic.compare_exchange_strong(observed, (PtrType)0x4, eastl::memory_order_acquire, eastl::memory_order_relaxed); ret = atomic.compare_exchange_strong(observed, (PtrType)0x4, eastl::memory_order_acquire, eastl::memory_order_acquire); ret = atomic.compare_exchange_strong(observed, (PtrType)0x4, eastl::memory_order_release, eastl::memory_order_relaxed); ret = atomic.compare_exchange_strong(observed, (PtrType)0x4, eastl::memory_order_acq_rel, eastl::memory_order_relaxed); ret = atomic.compare_exchange_strong(observed, (PtrType)0x4, eastl::memory_order_acq_rel, eastl::memory_order_acquire); ret = atomic.compare_exchange_strong(observed, (PtrType)0x4, eastl::memory_order_seq_cst, eastl::memory_order_relaxed); ret = atomic.compare_exchange_strong(observed, (PtrType)0x4, eastl::memory_order_seq_cst, eastl::memory_order_acquire); ret = atomic.compare_exchange_strong(observed, (PtrType)0x4, eastl::memory_order_seq_cst, eastl::memory_order_seq_cst); } } void AtomicPointerBasicTest::TestFetchAdd() { { PtrType val = (PtrType)0x4; AtomicType atomic{ val }; PtrType ret = atomic.fetch_add(1, eastl::memory_order_relaxed); VERIFY(ret == (PtrType)0x4); VERIFY(atomic.load(eastl::memory_order_relaxed) == (PtrType)0x8); } { PtrType val = (PtrType)0x4; AtomicType atomic{ val }; PtrType ret = atomic.fetch_add(0, eastl::memory_order_relaxed); VERIFY(ret == (PtrType)0x4); VERIFY(atomic.load(eastl::memory_order_relaxed) == (PtrType)0x4); } } void AtomicPointerBasicTest::TestAddFetch() { { PtrType val = (PtrType)0x4; AtomicType atomic{ val }; PtrType ret = atomic.add_fetch(1, eastl::memory_order_relaxed); VERIFY(ret == (PtrType)0x8); VERIFY(atomic.load(eastl::memory_order_relaxed) == (PtrType)0x8); } { PtrType val = (PtrType)0x4; AtomicType atomic{ val }; PtrType ret = atomic.add_fetch(0, eastl::memory_order_relaxed); VERIFY(ret == (PtrType)0x4); VERIFY(atomic.load(eastl::memory_order_relaxed) == (PtrType)0x4); } } void AtomicPointerBasicTest::TestFetchSub() { { PtrType val = (PtrType)0x4; AtomicType atomic{ val }; PtrType ret = atomic.fetch_sub(1, eastl::memory_order_relaxed); VERIFY(ret == (PtrType)0x4); VERIFY(atomic.load(eastl::memory_order_relaxed) == (PtrType)0x0); } { PtrType val = (PtrType)0x4; AtomicType atomic{ val }; PtrType ret = atomic.fetch_sub(0, eastl::memory_order_relaxed); VERIFY(ret == (PtrType)0x4); VERIFY(atomic.load(eastl::memory_order_relaxed) == (PtrType)0x4); } } void AtomicPointerBasicTest::TestSubFetch() { { PtrType val = (PtrType)0x4; AtomicType atomic{ val }; PtrType ret = atomic.sub_fetch(1, eastl::memory_order_relaxed); VERIFY(ret == (PtrType)0x0); VERIFY(atomic.load(eastl::memory_order_relaxed) == (PtrType)0x0); } { PtrType val = (PtrType)0x4; AtomicType atomic{ val }; PtrType ret = atomic.sub_fetch(0, eastl::memory_order_relaxed); VERIFY(ret == (PtrType)0x4); VERIFY(atomic.load(eastl::memory_order_relaxed) == (PtrType)0x4); } } void AtomicPointerBasicTest::TestAtomicPointerStandalone() { { AtomicType atomic; VERIFY(atomic_is_lock_free(&atomic) == true); } { AtomicType atomic; PtrType val = (PtrType)0x4; atomic_store(&atomic, val); VERIFY(atomic.load(eastl::memory_order_relaxed) == val); } { AtomicType atomic; PtrType val = (PtrType)0x4; atomic_store_explicit(&atomic, val, eastl::memory_order_relaxed); VERIFY(atomic.load(eastl::memory_order_relaxed) == val); } { AtomicType atomic; PtrType ret = atomic_load(&atomic); VERIFY(ret == (PtrType)0x0); } { AtomicType atomic; PtrType ret = atomic_load_explicit(&atomic, eastl::memory_order_relaxed); VERIFY(ret == (PtrType)0x0); } { AtomicType atomic; PtrType ret = atomic_load_cond(&atomic, [](PtrType val) { return true; }); VERIFY(ret == (PtrType)0x0); } { AtomicType atomic; PtrType ret = atomic_load_cond_explicit(&atomic, [](PtrType val) { return true; }, eastl::memory_order_relaxed); VERIFY(ret == (PtrType)0x0); } { AtomicType atomic; PtrType ret = atomic_exchange(&atomic, (PtrType)0x4); VERIFY(ret == (PtrType)0x0); VERIFY(atomic.load(eastl::memory_order_relaxed) == (PtrType)0x4); } { AtomicType atomic; PtrType ret = atomic_exchange_explicit(&atomic, (PtrType)0x4, eastl::memory_order_relaxed); VERIFY(ret == (PtrType)0x0); VERIFY(atomic.load(eastl::memory_order_relaxed) == (PtrType)0x4); } { AtomicType atomic; PtrType ret = atomic_add_fetch(&atomic, 1); VERIFY(ret == (PtrType)0x4); VERIFY(atomic.load(eastl::memory_order_relaxed) == (PtrType)0x4); } { AtomicType atomic; PtrType ret = atomic_add_fetch_explicit(&atomic, 1, eastl::memory_order_relaxed); VERIFY(ret == (PtrType)0x4); VERIFY(atomic.load(eastl::memory_order_relaxed) == (PtrType)0x4); } { AtomicType atomic; PtrType ret = atomic_fetch_add(&atomic, 1); VERIFY(ret == (PtrType)0x0); VERIFY(atomic.load(eastl::memory_order_relaxed) == (PtrType)0x4); } { AtomicType atomic; PtrType ret = atomic_fetch_add_explicit(&atomic, 1, eastl::memory_order_relaxed); VERIFY(ret == (PtrType)0x0); VERIFY(atomic.load(eastl::memory_order_relaxed) == (PtrType)0x4); } { AtomicType atomic{ (PtrType)0x4 }; PtrType ret = atomic_fetch_sub(&atomic, 1); VERIFY(ret == (PtrType)0x4); VERIFY(atomic.load(eastl::memory_order_relaxed) == (PtrType)0x0); } { AtomicType atomic{ (PtrType)0x4 }; PtrType ret = atomic_fetch_sub_explicit(&atomic, 1, eastl::memory_order_relaxed); VERIFY(ret == (PtrType)0x4); VERIFY(atomic.load(eastl::memory_order_relaxed) == (PtrType)0x0); } { AtomicType atomic{ (PtrType)0x4 }; PtrType ret = atomic_sub_fetch(&atomic, 1); VERIFY(ret == (PtrType)0x0); VERIFY(atomic.load(eastl::memory_order_relaxed) == (PtrType)0x0); } { AtomicType atomic{ (PtrType)0x4 }; PtrType ret = atomic_sub_fetch_explicit(&atomic, 1, eastl::memory_order_relaxed); VERIFY(ret == (PtrType)0x0); VERIFY(atomic.load(eastl::memory_order_relaxed) == (PtrType)0x0); } { AtomicType atomic; PtrType expected = (PtrType)0x0; bool ret = atomic_compare_exchange_strong(&atomic, &expected, (PtrType)0x4); VERIFY(ret == true); VERIFY(expected == (PtrType)0x0); VERIFY(atomic.load(eastl::memory_order_relaxed) == (PtrType)0x4); } { AtomicType atomic; PtrType expected = (PtrType)0x0; bool ret = atomic_compare_exchange_strong_explicit(&atomic, &expected, (PtrType)0x4, eastl::memory_order_relaxed, eastl::memory_order_relaxed); VERIFY(ret == true); VERIFY(expected == (PtrType)0x0); VERIFY(atomic.load(eastl::memory_order_relaxed) == (PtrType)0x4); } { AtomicType atomic; PtrType expected = (PtrType)0x0; bool ret = atomic_compare_exchange_weak(&atomic, &expected, (PtrType)0x4); if (ret) { VERIFY(ret == true); VERIFY(expected == (PtrType)0x0); VERIFY(atomic.load(eastl::memory_order_relaxed) == (PtrType)0x4); } } { AtomicType atomic; PtrType expected = (PtrType)0x0; bool ret = atomic_compare_exchange_weak_explicit(&atomic, &expected, (PtrType)0x4, eastl::memory_order_relaxed, eastl::memory_order_relaxed); if (ret) { VERIFY(ret == true); VERIFY(expected == (PtrType)0x0); VERIFY(atomic.load(eastl::memory_order_relaxed) == (PtrType)0x4); } } } struct AtomicNonTriviallyConstructible { AtomicNonTriviallyConstructible() : a(0) , b(0) { } AtomicNonTriviallyConstructible(uint16_t a, uint16_t b) : a(a) , b(b) { } friend bool operator==(const AtomicNonTriviallyConstructible& a, const AtomicNonTriviallyConstructible& b) { return a.a == b.a && a.b == b.b; } uint16_t a; uint16_t b; }; struct AtomicNonTriviallyConstructibleNoExcept { AtomicNonTriviallyConstructibleNoExcept() noexcept : a(0) , b(0) { } AtomicNonTriviallyConstructibleNoExcept(uint16_t a, uint16_t b) noexcept : a(a) , b(b) { } friend bool operator==(const AtomicNonTriviallyConstructibleNoExcept& a, const AtomicNonTriviallyConstructibleNoExcept& b) { return a.a == b.a && a.b == b.b; } uint16_t a; uint16_t b; }; struct AtomicUserType16 { uint8_t a; uint8_t b; friend bool operator==(const AtomicUserType16& a, const AtomicUserType16& b) { return (a.a == b.a) && (a.b == b.b); } }; struct AtomicUserType128 { uint32_t a; uint32_t b; uint32_t c; uint32_t d; AtomicUserType128() = default; AtomicUserType128(const AtomicUserType128&) = default; AtomicUserType128(uint32_t a, uint32_t b) : a(a) , b(b) , c(0) , d(0) { } AtomicUserType128& operator=(const AtomicUserType128&) = default; friend bool operator==(const AtomicUserType128& a, const AtomicUserType128& b) { return (a.a == b.a) && (a.b == b.b) && (a.c == b.c) && (a.d == b.d); } }; template class AtomicUserTypeBasicTest { public: using AtomicType = eastl::atomic; using UserType = T; int RunTest() { TestAtomicCtor(); TestAssignmentOperators(); TestIsLockFree(); TestStore(); TestLoad(); TestExchange(); TestCompareExchangeWeak(); TestCompareExchangeStrong(); TestAllMemoryOrders(); return nErrorCount; } private: void TestAtomicCtor(); void TestAssignmentOperators(); void TestIsLockFree(); void TestStore(); void TestLoad(); void TestExchange(); void TestCompareExchangeWeak(); void TestCompareExchangeStrong(); void TestAllMemoryOrders(); private: int nErrorCount = 0; }; template void AtomicUserTypeBasicTest::TestAtomicCtor() { { AtomicType atomic; UserType expected{0, 0}; UserType ret = atomic.load(eastl::memory_order_relaxed); VERIFY(ret == expected); } { AtomicType atomic{ {5, 8} }; UserType expected{5, 8}; UserType ret = atomic.load(eastl::memory_order_relaxed); VERIFY(ret == expected); } } template void AtomicUserTypeBasicTest::TestAssignmentOperators() { { AtomicType atomic; UserType expected{5, 6}; atomic = {5, 6}; VERIFY(atomic.load(eastl::memory_order_relaxed) == expected); } { AtomicType atomic; UserType expected{0, 0}; atomic = {0, 0}; VERIFY(atomic.load(eastl::memory_order_relaxed) == expected); } } template void AtomicUserTypeBasicTest::TestIsLockFree() { { AtomicType atomic; VERIFY(atomic.is_lock_free() == true); VERIFY(AtomicType::is_always_lock_free == true); } } template void AtomicUserTypeBasicTest::TestStore() { { AtomicType atomic; UserType expected{5, 6}; atomic.store(expected, eastl::memory_order_relaxed); UserType ret = atomic.load(eastl::memory_order_relaxed); VERIFY(ret == expected); } { AtomicType atomic; UserType expected{5, 6}; atomic.store({5, 6}, eastl::memory_order_relaxed); UserType ret = atomic.load(eastl::memory_order_relaxed); VERIFY(ret == expected); } } template void AtomicUserTypeBasicTest::TestLoad() { { AtomicType atomic; UserType expected{0, 0}; VERIFY(atomic.load(eastl::memory_order_relaxed) == expected); VERIFY(atomic == expected); } { AtomicType atomic{ {5, 6} }; UserType expected{5, 6}; VERIFY(atomic.load(eastl::memory_order_relaxed) == expected); VERIFY(atomic == expected); } } template void AtomicUserTypeBasicTest::TestExchange() { { AtomicType atomic; UserType expected{0, 0}; UserType ret = atomic.exchange({0, 0}, eastl::memory_order_relaxed); VERIFY(ret == expected); } { AtomicType atomic; UserType expected{0, 0}; UserType expected2{0, 1}; UserType ret = atomic.exchange({0, 1}, eastl::memory_order_relaxed); VERIFY(ret == expected); VERIFY(atomic.load(eastl::memory_order_relaxed) == expected2); } } template void AtomicUserTypeBasicTest::TestCompareExchangeWeak() { { AtomicType atomic; UserType observed{0, 0}; bool ret = atomic.compare_exchange_weak(observed, {0, 0}, eastl::memory_order_relaxed); UserType expected{0, 0}; if (ret) { VERIFY(ret == true); VERIFY(observed == expected); VERIFY(atomic.load(eastl::memory_order_relaxed) == expected); } } { AtomicType atomic; UserType observed{0, 0}; bool ret = atomic.compare_exchange_weak(observed, {0, 1}, eastl::memory_order_relaxed); UserType expected{0, 1}; UserType expected2{0, 0}; if (ret) { VERIFY(ret == true); VERIFY(observed == expected2); VERIFY(atomic.load(eastl::memory_order_relaxed) == expected); } } { AtomicType atomic; UserType observed{0, 1}; bool ret = atomic.compare_exchange_weak(observed, {0, 1}, eastl::memory_order_relaxed); UserType expected{0, 0}; VERIFY(ret == false); VERIFY(observed == expected); } } template void AtomicUserTypeBasicTest::TestCompareExchangeStrong() { { AtomicType atomic; UserType observed{0, 0}; bool ret = atomic.compare_exchange_strong(observed, {0, 0}, eastl::memory_order_relaxed); UserType expected{0, 0}; VERIFY(ret == true); VERIFY(observed == expected); VERIFY(atomic.load(eastl::memory_order_relaxed) == expected); } { AtomicType atomic; UserType observed{0, 0}; bool ret = atomic.compare_exchange_strong(observed, {0, 1}, eastl::memory_order_relaxed); UserType expected{0, 1}; UserType expected2{0, 0}; VERIFY(ret == true); VERIFY(observed == expected2); VERIFY(atomic.load(eastl::memory_order_relaxed) == expected); } { AtomicType atomic; UserType observed{0, 1}; bool ret = atomic.compare_exchange_strong(observed, {0, 1}, eastl::memory_order_relaxed); UserType expected{0, 0}; VERIFY(ret == false); VERIFY(observed == expected); } } template void AtomicUserTypeBasicTest::TestAllMemoryOrders() { { AtomicType atomic; UserType val{0, 1}; atomic.store(val); atomic.store(val, eastl::memory_order_relaxed); atomic.store(val, eastl::memory_order_release); atomic.store(val, eastl::memory_order_seq_cst); } { AtomicType atomic; UserType ret = atomic.load(); ret = atomic.load(eastl::memory_order_relaxed); ret = atomic.load(eastl::memory_order_acquire); ret = atomic.load(eastl::memory_order_seq_cst); } { AtomicType atomic; UserType ret = atomic.exchange({0, 1}); ret = atomic.exchange({0, 0}, eastl::memory_order_relaxed); ret = atomic.exchange({0, 0}, eastl::memory_order_acquire); ret = atomic.exchange({0, 0}, eastl::memory_order_release); ret = atomic.exchange({0, 0}, eastl::memory_order_acq_rel); ret = atomic.exchange({0, 0}, eastl::memory_order_seq_cst); } { AtomicType atomic; UserType observed{0, 0}; bool ret = atomic.compare_exchange_weak(observed, {0, 0}); ret = atomic.compare_exchange_weak(observed, {0, 0}, eastl::memory_order_relaxed); ret = atomic.compare_exchange_weak(observed, {0, 0}, eastl::memory_order_acquire); ret = atomic.compare_exchange_weak(observed, {0, 0}, eastl::memory_order_release); ret = atomic.compare_exchange_weak(observed, {0, 0}, eastl::memory_order_acq_rel); ret = atomic.compare_exchange_weak(observed, {0, 0}, eastl::memory_order_seq_cst); } { AtomicType atomic; UserType observed{0, 0}; bool ret = atomic.compare_exchange_strong(observed, {0, 0}); ret = atomic.compare_exchange_strong(observed, {0, 0}, eastl::memory_order_relaxed); ret = atomic.compare_exchange_strong(observed, {0, 0}, eastl::memory_order_acquire); ret = atomic.compare_exchange_strong(observed, {0, 0}, eastl::memory_order_release); ret = atomic.compare_exchange_strong(observed, {0, 0}, eastl::memory_order_acq_rel); ret = atomic.compare_exchange_strong(observed, {0, 0}, eastl::memory_order_seq_cst); } { AtomicType atomic; UserType observed{0, 0}; bool ret; ret = atomic.compare_exchange_weak(observed, {0, 0}, eastl::memory_order_relaxed, eastl::memory_order_relaxed); ret = atomic.compare_exchange_weak(observed, {0, 0}, eastl::memory_order_acquire, eastl::memory_order_relaxed); ret = atomic.compare_exchange_weak(observed, {0, 0}, eastl::memory_order_acquire, eastl::memory_order_acquire); ret = atomic.compare_exchange_weak(observed, {0, 0}, eastl::memory_order_release, eastl::memory_order_relaxed); ret = atomic.compare_exchange_weak(observed, {0, 0}, eastl::memory_order_acq_rel, eastl::memory_order_relaxed); ret = atomic.compare_exchange_weak(observed, {0, 0}, eastl::memory_order_acq_rel, eastl::memory_order_acquire); ret = atomic.compare_exchange_weak(observed, {0, 0}, eastl::memory_order_seq_cst, eastl::memory_order_relaxed); ret = atomic.compare_exchange_weak(observed, {0, 0}, eastl::memory_order_seq_cst, eastl::memory_order_acquire); ret = atomic.compare_exchange_weak(observed, {0, 0}, eastl::memory_order_seq_cst, eastl::memory_order_seq_cst); } { AtomicType atomic; UserType observed{0, 0}; bool ret; ret = atomic.compare_exchange_strong(observed, {0, 0}, eastl::memory_order_relaxed, eastl::memory_order_relaxed); ret = atomic.compare_exchange_strong(observed, {0, 0}, eastl::memory_order_acquire, eastl::memory_order_relaxed); ret = atomic.compare_exchange_strong(observed, {0, 0}, eastl::memory_order_acquire, eastl::memory_order_acquire); ret = atomic.compare_exchange_strong(observed, {0, 0}, eastl::memory_order_release, eastl::memory_order_relaxed); ret = atomic.compare_exchange_strong(observed, {0, 0}, eastl::memory_order_acq_rel, eastl::memory_order_relaxed); ret = atomic.compare_exchange_strong(observed, {0, 0}, eastl::memory_order_acq_rel, eastl::memory_order_acquire); ret = atomic.compare_exchange_strong(observed, {0, 0}, eastl::memory_order_seq_cst, eastl::memory_order_relaxed); ret = atomic.compare_exchange_strong(observed, {0, 0}, eastl::memory_order_seq_cst, eastl::memory_order_acquire); ret = atomic.compare_exchange_strong(observed, {0, 0}, eastl::memory_order_seq_cst, eastl::memory_order_seq_cst); } } class AtomicBoolBasicTest { public: using AtomicType = eastl::atomic; using BoolType = bool; int RunTest() { TestAtomicCtor(); TestAssignmentOperators(); TestIsLockFree(); TestStore(); TestLoad(); TestExchange(); TestCompareExchangeWeak(); TestCompareExchangeStrong(); TestAllMemoryOrders(); return nErrorCount; } private: void TestAtomicCtor(); void TestAssignmentOperators(); void TestIsLockFree(); void TestStore(); void TestLoad(); void TestExchange(); void TestCompareExchangeWeak(); void TestCompareExchangeStrong(); void TestAllMemoryOrders(); private: int nErrorCount = 0; }; void AtomicBoolBasicTest::TestAtomicCtor() { { AtomicType atomic{ false }; BoolType ret = atomic.load(eastl::memory_order_relaxed); VERIFY(ret == false); } { AtomicType atomic{ true }; BoolType ret = atomic.load(eastl::memory_order_relaxed); VERIFY(ret == true); } { AtomicType atomic; BoolType ret = atomic.load(eastl::memory_order_relaxed); VERIFY(ret == false); } { AtomicType atomic{}; BoolType ret = atomic.load(eastl::memory_order_relaxed); VERIFY(ret == false); } } void AtomicBoolBasicTest::TestAssignmentOperators() { { AtomicType atomic; BoolType ret = atomic = true; VERIFY(ret == true); VERIFY(atomic.load(eastl::memory_order_relaxed) == true); } } void AtomicBoolBasicTest::TestIsLockFree() { { AtomicType atomic; bool ret = atomic.is_lock_free(); VERIFY(ret == true); VERIFY(AtomicType::is_always_lock_free == true); } } void AtomicBoolBasicTest::TestStore() { { AtomicType atomic; atomic.store(true, eastl::memory_order_relaxed); VERIFY(atomic.load(eastl::memory_order_relaxed) == true); } } void AtomicBoolBasicTest::TestLoad() { { AtomicType atomic; VERIFY(atomic.load(eastl::memory_order_relaxed) == false); VERIFY(atomic == false); } { AtomicType atomic{ true }; VERIFY(atomic.load(eastl::memory_order_relaxed) == true); VERIFY(atomic == true); } } void AtomicBoolBasicTest::TestExchange() { { AtomicType atomic; BoolType ret = atomic.exchange(false, eastl::memory_order_relaxed); VERIFY(ret == false); VERIFY(atomic.load(eastl::memory_order_relaxed) == false); } { AtomicType atomic; BoolType ret = atomic.exchange(true, eastl::memory_order_relaxed); VERIFY(ret == false); VERIFY(atomic.load(eastl::memory_order_relaxed) == true); } } void AtomicBoolBasicTest::TestCompareExchangeWeak() { { AtomicType atomic{ false }; BoolType observed = false; bool ret = atomic.compare_exchange_weak(observed, false, eastl::memory_order_relaxed); if (ret) { VERIFY(ret == true); VERIFY(observed == false); VERIFY(atomic.load(eastl::memory_order_relaxed) == false); } } { AtomicType atomic{ false }; BoolType observed = false; bool ret = atomic.compare_exchange_weak(observed, true, eastl::memory_order_relaxed); if (ret) { VERIFY(ret == true); VERIFY(observed == false); VERIFY(atomic.load(eastl::memory_order_relaxed) == true); } } { AtomicType atomic{ false }; BoolType observed = true; bool ret = atomic.compare_exchange_weak(observed, true, eastl::memory_order_relaxed); VERIFY(ret == false); VERIFY(observed == false); } } void AtomicBoolBasicTest::TestCompareExchangeStrong() { { AtomicType atomic{ false }; BoolType observed = false; bool ret = atomic.compare_exchange_weak(observed, false, eastl::memory_order_relaxed); VERIFY(ret == true); VERIFY(observed == false); VERIFY(atomic.load(eastl::memory_order_relaxed) == false); } { AtomicType atomic{ false }; BoolType observed = false; bool ret = atomic.compare_exchange_weak(observed, true, eastl::memory_order_relaxed); VERIFY(ret == true); VERIFY(observed == false); VERIFY(atomic.load(eastl::memory_order_relaxed) == true); } { AtomicType atomic{ false }; BoolType observed = true; bool ret = atomic.compare_exchange_weak(observed, true, eastl::memory_order_relaxed); VERIFY(ret == false); VERIFY(observed == false); } } void AtomicBoolBasicTest::TestAllMemoryOrders() { { AtomicType atomic; atomic.store(true); atomic.store(true, eastl::memory_order_relaxed); atomic.store(true, eastl::memory_order_release); atomic.store(true, eastl::memory_order_seq_cst); } { AtomicType atomic; BoolType ret = atomic.load(); ret = atomic.load(eastl::memory_order_relaxed); ret = atomic.load(eastl::memory_order_acquire); ret = atomic.load(eastl::memory_order_seq_cst); } { AtomicType atomic; BoolType ret = atomic.exchange(true); ret = atomic.exchange(true, eastl::memory_order_relaxed); ret = atomic.exchange(true, eastl::memory_order_acquire); ret = atomic.exchange(true, eastl::memory_order_release); ret = atomic.exchange(true, eastl::memory_order_acq_rel); ret = atomic.exchange(true, eastl::memory_order_seq_cst); } { AtomicType atomic; BoolType observed = false; bool ret = atomic.compare_exchange_weak(observed, true); ret = atomic.compare_exchange_weak(observed, true, eastl::memory_order_relaxed); ret = atomic.compare_exchange_weak(observed, true, eastl::memory_order_acquire); ret = atomic.compare_exchange_weak(observed, true, eastl::memory_order_release); ret = atomic.compare_exchange_weak(observed, true, eastl::memory_order_acq_rel); ret = atomic.compare_exchange_weak(observed, true, eastl::memory_order_seq_cst); } { AtomicType atomic; BoolType observed = false; bool ret = atomic.compare_exchange_strong(observed, true); ret = atomic.compare_exchange_strong(observed, true, eastl::memory_order_relaxed); ret = atomic.compare_exchange_strong(observed, true, eastl::memory_order_acquire); ret = atomic.compare_exchange_strong(observed, true, eastl::memory_order_release); ret = atomic.compare_exchange_strong(observed, true, eastl::memory_order_acq_rel); ret = atomic.compare_exchange_strong(observed, true, eastl::memory_order_seq_cst); } { AtomicType atomic; BoolType observed = false; bool ret = atomic.compare_exchange_weak(observed, true, eastl::memory_order_relaxed, eastl::memory_order_relaxed); ret = atomic.compare_exchange_weak(observed, true, eastl::memory_order_acquire, eastl::memory_order_relaxed); ret = atomic.compare_exchange_weak(observed, true, eastl::memory_order_acquire, eastl::memory_order_acquire); ret = atomic.compare_exchange_weak(observed, true, eastl::memory_order_release, eastl::memory_order_relaxed); ret = atomic.compare_exchange_weak(observed, true, eastl::memory_order_acq_rel, eastl::memory_order_relaxed); ret = atomic.compare_exchange_weak(observed, true, eastl::memory_order_acq_rel, eastl::memory_order_acquire); ret = atomic.compare_exchange_weak(observed, true, eastl::memory_order_seq_cst, eastl::memory_order_relaxed); ret = atomic.compare_exchange_weak(observed, true, eastl::memory_order_seq_cst, eastl::memory_order_acquire); ret = atomic.compare_exchange_weak(observed, true, eastl::memory_order_seq_cst, eastl::memory_order_seq_cst); } { AtomicType atomic; BoolType observed = false; bool ret = atomic.compare_exchange_strong(observed, true, eastl::memory_order_relaxed, eastl::memory_order_relaxed); ret = atomic.compare_exchange_strong(observed, true, eastl::memory_order_acquire, eastl::memory_order_relaxed); ret = atomic.compare_exchange_strong(observed, true, eastl::memory_order_acquire, eastl::memory_order_acquire); ret = atomic.compare_exchange_strong(observed, true, eastl::memory_order_release, eastl::memory_order_relaxed); ret = atomic.compare_exchange_strong(observed, true, eastl::memory_order_acq_rel, eastl::memory_order_relaxed); ret = atomic.compare_exchange_strong(observed, true, eastl::memory_order_acq_rel, eastl::memory_order_acquire); ret = atomic.compare_exchange_strong(observed, true, eastl::memory_order_seq_cst, eastl::memory_order_relaxed); ret = atomic.compare_exchange_strong(observed, true, eastl::memory_order_seq_cst, eastl::memory_order_acquire); ret = atomic.compare_exchange_strong(observed, true, eastl::memory_order_seq_cst, eastl::memory_order_seq_cst); } } template class AtomicIntegralBasicTest { public: using AtomicType = eastl::atomic; using IntegralType = T; int RunTest() { TestAtomicCtor(); TestAtomicFetchAdd(); TestAtomicAddFetch(); TestAtomicFetchSub(); TestAtomicSubFetch(); TestAtomicFetchAnd(); TestAtomicAndFetch(); TestAtomicFetchOr(); TestAtomicOrFetch(); TestAtomicFetchXor(); TestAtomicXorFetch(); TestAssignmentOperators(); TestIsLockFree(); TestStore(); TestLoad(); TestExchange(); TestCompareExchangeWeak(); TestCompareExchangeStrong(); TestAllMemoryOrders(); TestAtomicStandalone(); return nErrorCount; } private: void TestAtomicCtor(); void TestAtomicFetchAdd(); void TestAtomicAddFetch(); void TestAtomicFetchSub(); void TestAtomicSubFetch(); void TestAtomicFetchAnd(); void TestAtomicAndFetch(); void TestAtomicFetchOr(); void TestAtomicOrFetch(); void TestAtomicFetchXor(); void TestAtomicXorFetch(); void TestAssignmentOperators(); void TestIsLockFree(); void TestStore(); void TestLoad(); void TestExchange(); void TestCompareExchangeWeak(); void TestCompareExchangeStrong(); void TestAllMemoryOrders(); void TestAtomicStandalone(); private: int nErrorCount = 0; }; template void AtomicIntegralBasicTest::TestAtomicCtor() { { AtomicType atomic{ 0 }; IntegralType ret = atomic.load(eastl::memory_order_relaxed); VERIFY(ret == 0); } { AtomicType atomic{ 1 }; IntegralType ret = atomic.load(eastl::memory_order_relaxed); VERIFY(ret == 1); } { AtomicType atomic{ 20 }; IntegralType ret = atomic.load(eastl::memory_order_relaxed); VERIFY(ret == 20); } { AtomicType atomic; IntegralType ret = atomic.load(eastl::memory_order_relaxed); VERIFY(ret == 0); } { AtomicType atomic{}; IntegralType ret = atomic.load(eastl::memory_order_relaxed); VERIFY(ret == 0); } } template void AtomicIntegralBasicTest::TestAtomicFetchAdd() { { AtomicType atomic; IntegralType ret = atomic.fetch_add(1, eastl::memory_order_relaxed); VERIFY(ret == 0); ret = atomic.load(eastl::memory_order_relaxed); VERIFY(ret == 1); } { AtomicType atomic; IntegralType ret = atomic.fetch_add(0, eastl::memory_order_relaxed); VERIFY(ret == 0); ret = atomic.load(eastl::memory_order_relaxed); VERIFY(ret == 0); } { AtomicType atomic{ 5 }; IntegralType ret = atomic.fetch_add(0, eastl::memory_order_relaxed); VERIFY(ret == 5); ret = atomic.fetch_add(4, eastl::memory_order_relaxed); VERIFY(ret == 5); ret = atomic.fetch_add(1, eastl::memory_order_relaxed); VERIFY(ret == 9); ret = atomic.load(eastl::memory_order_relaxed); VERIFY(ret == 10); } } template void AtomicIntegralBasicTest::TestAtomicAddFetch() { { AtomicType atomic; IntegralType ret = atomic.add_fetch(1, eastl::memory_order_relaxed); VERIFY(ret == 1); ret = atomic.load(eastl::memory_order_relaxed); VERIFY(ret == 1); } { AtomicType atomic; IntegralType ret = atomic.add_fetch(0, eastl::memory_order_relaxed); VERIFY(ret == 0); ret = atomic.load(eastl::memory_order_relaxed); VERIFY(ret == 0); } { AtomicType atomic{ 5 }; IntegralType ret = atomic.add_fetch(0, eastl::memory_order_relaxed); VERIFY(ret == 5); ret = atomic.add_fetch(4, eastl::memory_order_relaxed); VERIFY(ret == 9); ret = atomic.load(eastl::memory_order_relaxed); VERIFY(ret == 9); } } template void AtomicIntegralBasicTest::TestAtomicFetchSub() { { AtomicType atomic{ 1 }; IntegralType ret = atomic.fetch_sub(1, eastl::memory_order_relaxed); VERIFY(ret == 1); ret = atomic.load(eastl::memory_order_relaxed); VERIFY(ret == 0); } { AtomicType atomic{ 1 }; IntegralType ret = atomic.fetch_sub(0, eastl::memory_order_relaxed); VERIFY(ret == 1); ret = atomic.load(eastl::memory_order_relaxed); VERIFY(ret == 1); } { AtomicType atomic{ 5 }; IntegralType ret = atomic.fetch_sub(2, eastl::memory_order_relaxed); VERIFY(ret == 5); ret = atomic.fetch_sub(1, eastl::memory_order_relaxed); VERIFY(ret == 3); ret = atomic.load(eastl::memory_order_relaxed); VERIFY(ret == 2); } } template void AtomicIntegralBasicTest::TestAtomicSubFetch() { { AtomicType atomic{ 1 }; IntegralType ret = atomic.sub_fetch(1, eastl::memory_order_relaxed); VERIFY(ret == 0); ret = atomic.load(eastl::memory_order_relaxed); VERIFY(ret == 0); } { AtomicType atomic{ 1 }; IntegralType ret = atomic.sub_fetch(0, eastl::memory_order_relaxed); VERIFY(ret == 1); ret = atomic.load(eastl::memory_order_relaxed); VERIFY(ret == 1); } { AtomicType atomic{ 5 }; IntegralType ret = atomic.sub_fetch(2, eastl::memory_order_relaxed); VERIFY(ret == 3); ret = atomic.sub_fetch(1, eastl::memory_order_relaxed); VERIFY(ret == 2); ret = atomic.load(eastl::memory_order_relaxed); VERIFY(ret == 2); } } template void AtomicIntegralBasicTest::TestAtomicFetchAnd() { { AtomicType atomic{ 0 }; IntegralType ret = atomic.fetch_and(0x0, eastl::memory_order_relaxed); VERIFY(ret == 0); ret = atomic.load(eastl::memory_order_relaxed); VERIFY(ret == 0); } { AtomicType atomic{ 0 }; IntegralType ret = atomic.fetch_and(0x1, eastl::memory_order_relaxed); VERIFY(ret == 0); ret = atomic.load(eastl::memory_order_relaxed); VERIFY(ret == 0); } { AtomicType atomic{ 0xF }; IntegralType ret = atomic.fetch_and(0x1, eastl::memory_order_relaxed); VERIFY(ret == 0xF); ret = atomic.load(eastl::memory_order_relaxed); VERIFY(ret == 0X1); } { AtomicType atomic{ 0xF }; IntegralType ret = atomic.fetch_and(0xF0, eastl::memory_order_relaxed); VERIFY(ret == 0xF); ret = atomic.load(eastl::memory_order_relaxed); VERIFY(ret == 0x0); } } template void AtomicIntegralBasicTest::TestAtomicAndFetch() { { AtomicType atomic{ 0 }; IntegralType ret = atomic.and_fetch(0x0, eastl::memory_order_relaxed); VERIFY(ret == 0); ret = atomic.load(eastl::memory_order_relaxed); VERIFY(ret == 0); } { AtomicType atomic{ 0 }; IntegralType ret = atomic.and_fetch(0x1, eastl::memory_order_relaxed); VERIFY(ret == 0); ret = atomic.load(eastl::memory_order_relaxed); VERIFY(ret == 0); } { AtomicType atomic{ 0xF }; IntegralType ret = atomic.and_fetch(0x1, eastl::memory_order_relaxed); VERIFY(ret == 0x1); ret = atomic.load(eastl::memory_order_relaxed); VERIFY(ret == 0x1); } { AtomicType atomic{ 0xF }; IntegralType ret = atomic.and_fetch(0xF0, eastl::memory_order_relaxed); VERIFY(ret == 0x0); ret = atomic.load(eastl::memory_order_relaxed); VERIFY(ret == 0x0); } } template void AtomicIntegralBasicTest::TestAtomicFetchOr() { { AtomicType atomic{ 0 }; IntegralType ret = atomic.fetch_or(0x1, eastl::memory_order_relaxed); VERIFY(ret == 0x0); ret = atomic.load(eastl::memory_order_relaxed); VERIFY(ret == 0x1); } { AtomicType atomic{ 0x1 }; IntegralType ret = atomic.fetch_or(0x0, eastl::memory_order_relaxed); VERIFY(ret == 0x1); ret = atomic.load(eastl::memory_order_relaxed); VERIFY(ret == 0x1); } { AtomicType atomic{ 0x1 }; IntegralType ret = atomic.fetch_or(0x2, eastl::memory_order_relaxed); VERIFY(ret == 0x1); ret = atomic.load(eastl::memory_order_relaxed); VERIFY(ret == 0x3); } } template void AtomicIntegralBasicTest::TestAtomicOrFetch() { { AtomicType atomic{ 0 }; IntegralType ret = atomic.or_fetch(0x1, eastl::memory_order_relaxed); VERIFY(ret == 0x1); ret = atomic.load(eastl::memory_order_relaxed); VERIFY(ret == 0x1); } { AtomicType atomic{ 0x1 }; IntegralType ret = atomic.or_fetch(0x0, eastl::memory_order_relaxed); VERIFY(ret == 0x1); ret = atomic.load(eastl::memory_order_relaxed); VERIFY(ret == 0x1); } { AtomicType atomic{ 0x1 }; IntegralType ret = atomic.or_fetch(0x2, eastl::memory_order_relaxed); VERIFY(ret == 0x3); ret = atomic.load(eastl::memory_order_relaxed); VERIFY(ret == 0x3); } } template void AtomicIntegralBasicTest::TestAtomicFetchXor() { { AtomicType atomic{ 0 }; IntegralType ret = atomic.fetch_xor(0x0, eastl::memory_order_relaxed); VERIFY(ret == 0x0); ret = atomic.load(eastl::memory_order_relaxed); VERIFY(ret == 0x0); } { AtomicType atomic{ 0x1 }; IntegralType ret = atomic.fetch_xor(0x1, eastl::memory_order_relaxed); VERIFY(ret == 0x1); ret = atomic.load(eastl::memory_order_relaxed); VERIFY(ret == 0x0); } { AtomicType atomic{ 0x0 }; IntegralType ret = atomic.fetch_xor(0x1, eastl::memory_order_relaxed); VERIFY(ret == 0x0); ret = atomic.load(eastl::memory_order_relaxed); VERIFY(ret == 0x1); } } template void AtomicIntegralBasicTest::TestAtomicXorFetch() { { AtomicType atomic{ 0 }; IntegralType ret = atomic.xor_fetch(0x0, eastl::memory_order_relaxed); VERIFY(ret == 0x0); ret = atomic.load(eastl::memory_order_relaxed); VERIFY(ret == 0x0); } { AtomicType atomic{ 0x1 }; IntegralType ret = atomic.xor_fetch(0x1, eastl::memory_order_relaxed); VERIFY(ret == 0x0); ret = atomic.load(eastl::memory_order_relaxed); VERIFY(ret == 0x0); } { AtomicType atomic{ 0x0 }; IntegralType ret = atomic.xor_fetch(0x1, eastl::memory_order_relaxed); VERIFY(ret == 0x1); ret = atomic.load(eastl::memory_order_relaxed); VERIFY(ret == 0x1); } } template void AtomicIntegralBasicTest::TestAssignmentOperators() { { AtomicType atomic{ 0 }; IntegralType ret = (atomic = 5); VERIFY(ret == 5); ret = atomic.load(eastl::memory_order_relaxed); VERIFY(ret == 5); } { AtomicType atomic{ 0 }; IntegralType ret = ++atomic; VERIFY(ret == 1); ret = atomic.load(eastl::memory_order_relaxed); VERIFY(ret == 1); } { AtomicType atomic{ 0 }; IntegralType ret = atomic++; VERIFY(ret == 0); ret = atomic.load(eastl::memory_order_relaxed); VERIFY(ret == 1); } { AtomicType atomic{ 1 }; IntegralType ret = --atomic; VERIFY(ret == 0); ret = atomic.load(eastl::memory_order_relaxed); VERIFY(ret == 0); } { AtomicType atomic{ 1 }; IntegralType ret = atomic--; VERIFY(ret == 1); ret = atomic.load(eastl::memory_order_relaxed); VERIFY(ret == 0); } { AtomicType atomic{ 0 }; IntegralType ret = atomic += 5; VERIFY(ret == 5); ret = atomic.load(eastl::memory_order_relaxed); VERIFY(ret == 5); } { AtomicType atomic{ 5 }; IntegralType ret = atomic -= 3; VERIFY(ret == 2); ret = atomic.load(eastl::memory_order_relaxed); VERIFY(ret == 2); } { AtomicType atomic{ 0x0 }; IntegralType ret = atomic |= 0x1; VERIFY(ret == 0x1); ret = atomic.load(eastl::memory_order_relaxed); VERIFY(ret == 0x1); } { AtomicType atomic{ 0x1 }; IntegralType ret = atomic &= 0x1; VERIFY(ret == 0x1); ret = atomic.load(eastl::memory_order_relaxed); VERIFY(ret == 0x1); } { AtomicType atomic{ 0x1 }; IntegralType ret = atomic ^= 0x1; VERIFY(ret == 0x0); ret = atomic.load(eastl::memory_order_relaxed); VERIFY(ret == 0x0); } } template void AtomicIntegralBasicTest::TestIsLockFree() { { const AtomicType atomic{ 5 }; VERIFY(atomic.is_lock_free() == true); VERIFY(AtomicType::is_always_lock_free == true); } } template void AtomicIntegralBasicTest::TestStore() { { AtomicType atomic{ 0 }; atomic.store(0, eastl::memory_order_relaxed); VERIFY(atomic.load(eastl::memory_order_relaxed) == 0); } { AtomicType atomic{ 0 }; atomic.store(1, eastl::memory_order_relaxed); VERIFY(atomic.load(eastl::memory_order_relaxed) == 1); } } template void AtomicIntegralBasicTest::TestLoad() { { AtomicType atomic{ 0 }; VERIFY(atomic.load(eastl::memory_order_relaxed) == 0); bool ret = atomic == 0; VERIFY(ret == true); VERIFY(atomic == 0); } { AtomicType atomic{ 5 }; VERIFY(atomic.load(eastl::memory_order_relaxed) == 5); bool ret = atomic == 5; VERIFY(ret == true); VERIFY(atomic == 5); } } template void AtomicIntegralBasicTest::TestExchange() { { AtomicType atomic{ 0 }; IntegralType ret = atomic.exchange(0, eastl::memory_order_relaxed); VERIFY(ret == 0); ret = atomic.load(eastl::memory_order_relaxed); VERIFY(ret == 0); } { AtomicType atomic{ 0 }; IntegralType ret = atomic.exchange(1, eastl::memory_order_relaxed); VERIFY(ret == 0); ret = atomic.load(eastl::memory_order_relaxed); VERIFY(ret == 1); } } template void AtomicIntegralBasicTest::TestCompareExchangeWeak() { { AtomicType atomic{ 0 }; IntegralType observed = 0; bool ret = atomic.compare_exchange_weak(observed, 1, eastl::memory_order_relaxed); if (ret == true) { VERIFY(ret == true); VERIFY(observed == 0); VERIFY(atomic.load(eastl::memory_order_relaxed) == 1); } } { AtomicType atomic{ 0 }; IntegralType observed = 1; bool ret = atomic.compare_exchange_weak(observed, 1, eastl::memory_order_relaxed); VERIFY(ret == false); VERIFY(observed == 0); VERIFY(atomic.load(eastl::memory_order_relaxed) == 0); } } template void AtomicIntegralBasicTest::TestCompareExchangeStrong() { { AtomicType atomic{ 0 }; IntegralType observed = 0; bool ret = atomic.compare_exchange_strong(observed, 1, eastl::memory_order_relaxed); VERIFY(ret == true); VERIFY(observed == 0); VERIFY(atomic.load(eastl::memory_order_relaxed) == 1); } { AtomicType atomic{ 0 }; IntegralType observed = 1; bool ret = atomic.compare_exchange_strong(observed, 1, eastl::memory_order_relaxed); VERIFY(ret == false); VERIFY(observed == 0); VERIFY(atomic.load(eastl::memory_order_relaxed) == 0); } } template void AtomicIntegralBasicTest::TestAllMemoryOrders() { { AtomicType atomic{}; atomic.store(1); atomic.store(1, eastl::memory_order_relaxed); atomic.store(1, eastl::memory_order_release); atomic.store(1, eastl::memory_order_seq_cst); } { AtomicType atomic{}; IntegralType ret = atomic.load(); ret = atomic.load(eastl::memory_order_relaxed); ret = atomic.load(eastl::memory_order_acquire); ret = atomic.load(eastl::memory_order_seq_cst); } { AtomicType atomic{}; IntegralType ret = atomic.exchange(1); ret = atomic.exchange(1, eastl::memory_order_relaxed); ret = atomic.exchange(1, eastl::memory_order_acquire); ret = atomic.exchange(1, eastl::memory_order_release); ret = atomic.exchange(1, eastl::memory_order_acq_rel); ret = atomic.exchange(1, eastl::memory_order_seq_cst); } { AtomicType atomic{}; IntegralType ret = atomic.fetch_add(1); ret = atomic.fetch_add(1, eastl::memory_order_relaxed); ret = atomic.fetch_add(1, eastl::memory_order_acquire); ret = atomic.fetch_add(1, eastl::memory_order_release); ret = atomic.fetch_add(1, eastl::memory_order_acq_rel); ret = atomic.fetch_add(1, eastl::memory_order_seq_cst); } { AtomicType atomic{}; IntegralType ret = atomic.add_fetch(1); ret = atomic.add_fetch(1, eastl::memory_order_relaxed); ret = atomic.add_fetch(1, eastl::memory_order_acquire); ret = atomic.add_fetch(1, eastl::memory_order_release); ret = atomic.add_fetch(1, eastl::memory_order_acq_rel); ret = atomic.add_fetch(1, eastl::memory_order_seq_cst); } { AtomicType atomic{}; IntegralType ret = atomic.fetch_sub(1); ret = atomic.fetch_sub(1, eastl::memory_order_relaxed); ret = atomic.fetch_sub(1, eastl::memory_order_acquire); ret = atomic.fetch_sub(1, eastl::memory_order_release); ret = atomic.fetch_sub(1, eastl::memory_order_acq_rel); ret = atomic.fetch_sub(1, eastl::memory_order_seq_cst); } { AtomicType atomic{}; IntegralType ret = atomic.sub_fetch(1); ret = atomic.sub_fetch(1, eastl::memory_order_relaxed); ret = atomic.sub_fetch(1, eastl::memory_order_acquire); ret = atomic.sub_fetch(1, eastl::memory_order_release); ret = atomic.sub_fetch(1, eastl::memory_order_acq_rel); ret = atomic.sub_fetch(1, eastl::memory_order_seq_cst); } { AtomicType atomic{}; IntegralType ret = atomic.fetch_and(1); ret = atomic.fetch_and(1, eastl::memory_order_relaxed); ret = atomic.fetch_and(1, eastl::memory_order_acquire); ret = atomic.fetch_and(1, eastl::memory_order_release); ret = atomic.fetch_and(1, eastl::memory_order_acq_rel); ret = atomic.fetch_and(1, eastl::memory_order_seq_cst); } { AtomicType atomic{}; IntegralType ret = atomic.and_fetch(1); ret = atomic.and_fetch(1, eastl::memory_order_relaxed); ret = atomic.and_fetch(1, eastl::memory_order_acquire); ret = atomic.and_fetch(1, eastl::memory_order_release); ret = atomic.and_fetch(1, eastl::memory_order_acq_rel); ret = atomic.and_fetch(1, eastl::memory_order_seq_cst); } { AtomicType atomic{}; IntegralType ret = atomic.fetch_or(1); ret = atomic.fetch_or(1, eastl::memory_order_relaxed); ret = atomic.fetch_or(1, eastl::memory_order_acquire); ret = atomic.fetch_or(1, eastl::memory_order_release); ret = atomic.fetch_or(1, eastl::memory_order_acq_rel); ret = atomic.fetch_or(1, eastl::memory_order_seq_cst); } { AtomicType atomic{}; IntegralType ret = atomic.or_fetch(1); ret = atomic.or_fetch(1, eastl::memory_order_relaxed); ret = atomic.or_fetch(1, eastl::memory_order_acquire); ret = atomic.or_fetch(1, eastl::memory_order_release); ret = atomic.or_fetch(1, eastl::memory_order_acq_rel); ret = atomic.or_fetch(1, eastl::memory_order_seq_cst); } { AtomicType atomic{}; IntegralType ret = atomic.fetch_xor(1); ret = atomic.fetch_xor(1, eastl::memory_order_relaxed); ret = atomic.fetch_xor(1, eastl::memory_order_acquire); ret = atomic.fetch_xor(1, eastl::memory_order_release); ret = atomic.fetch_xor(1, eastl::memory_order_acq_rel); ret = atomic.fetch_xor(1, eastl::memory_order_seq_cst); } { AtomicType atomic{}; IntegralType ret = atomic.xor_fetch(1); ret = atomic.xor_fetch(1, eastl::memory_order_relaxed); ret = atomic.xor_fetch(1, eastl::memory_order_acquire); ret = atomic.xor_fetch(1, eastl::memory_order_release); ret = atomic.xor_fetch(1, eastl::memory_order_acq_rel); ret = atomic.xor_fetch(1, eastl::memory_order_seq_cst); } { AtomicType atomic{}; IntegralType observed = 0; bool ret; ret = atomic.compare_exchange_weak(observed, 1); ret = atomic.compare_exchange_weak(observed, 1, eastl::memory_order_relaxed); ret = atomic.compare_exchange_weak(observed, 1, eastl::memory_order_acquire); ret = atomic.compare_exchange_weak(observed, 1, eastl::memory_order_release); ret = atomic.compare_exchange_weak(observed, 1, eastl::memory_order_acq_rel); ret = atomic.compare_exchange_weak(observed, 1, eastl::memory_order_seq_cst); } { AtomicType atomic{}; IntegralType observed = 0; bool ret; ret = atomic.compare_exchange_strong(observed, 1); ret = atomic.compare_exchange_strong(observed, 1, eastl::memory_order_relaxed); ret = atomic.compare_exchange_strong(observed, 1, eastl::memory_order_acquire); ret = atomic.compare_exchange_strong(observed, 1, eastl::memory_order_release); ret = atomic.compare_exchange_strong(observed, 1, eastl::memory_order_acq_rel); ret = atomic.compare_exchange_strong(observed, 1, eastl::memory_order_seq_cst); } { AtomicType atomic{}; IntegralType observed = 0; bool ret; ret = atomic.compare_exchange_weak(observed, 1, eastl::memory_order_relaxed, eastl::memory_order_relaxed); ret = atomic.compare_exchange_weak(observed, 1, eastl::memory_order_acquire, eastl::memory_order_relaxed); ret = atomic.compare_exchange_weak(observed, 1, eastl::memory_order_acquire, eastl::memory_order_acquire); ret = atomic.compare_exchange_weak(observed, 1, eastl::memory_order_release, eastl::memory_order_relaxed); ret = atomic.compare_exchange_weak(observed, 1, eastl::memory_order_acq_rel, eastl::memory_order_relaxed); ret = atomic.compare_exchange_weak(observed, 1, eastl::memory_order_acq_rel, eastl::memory_order_acquire); ret = atomic.compare_exchange_weak(observed, 1, eastl::memory_order_seq_cst, eastl::memory_order_relaxed); ret = atomic.compare_exchange_weak(observed, 1, eastl::memory_order_seq_cst, eastl::memory_order_acquire); ret = atomic.compare_exchange_weak(observed, 1, eastl::memory_order_seq_cst, eastl::memory_order_seq_cst); } { AtomicType atomic{}; IntegralType observed = 0; bool ret; ret = atomic.compare_exchange_strong(observed, 1, eastl::memory_order_relaxed, eastl::memory_order_relaxed); ret = atomic.compare_exchange_strong(observed, 1, eastl::memory_order_acquire, eastl::memory_order_relaxed); ret = atomic.compare_exchange_strong(observed, 1, eastl::memory_order_acquire, eastl::memory_order_acquire); ret = atomic.compare_exchange_strong(observed, 1, eastl::memory_order_release, eastl::memory_order_relaxed); ret = atomic.compare_exchange_strong(observed, 1, eastl::memory_order_acq_rel, eastl::memory_order_relaxed); ret = atomic.compare_exchange_strong(observed, 1, eastl::memory_order_acq_rel, eastl::memory_order_acquire); ret = atomic.compare_exchange_strong(observed, 1, eastl::memory_order_seq_cst, eastl::memory_order_relaxed); ret = atomic.compare_exchange_strong(observed, 1, eastl::memory_order_seq_cst, eastl::memory_order_acquire); ret = atomic.compare_exchange_strong(observed, 1, eastl::memory_order_seq_cst, eastl::memory_order_seq_cst); } } template void AtomicIntegralBasicTest::TestAtomicStandalone() { { AtomicType atomic; IntegralType expected = 0; bool ret = atomic_compare_exchange_weak(&atomic, &expected, 1); if (ret) { VERIFY(ret == true); VERIFY(expected == 0); VERIFY(atomic.load(eastl::memory_order_relaxed) == 1); } } { AtomicType atomic; IntegralType expected = 0; bool ret = atomic_compare_exchange_weak_explicit(&atomic, &expected, 1, eastl::memory_order_relaxed, eastl::memory_order_relaxed); if (ret) { VERIFY(ret == true); VERIFY(expected == 0); VERIFY(atomic.load(eastl::memory_order_relaxed) == 1); } } { AtomicType atomic; IntegralType expected = 0; bool ret = atomic_compare_exchange_strong(&atomic, &expected, 1); VERIFY(ret == true); VERIFY(expected == 0); VERIFY(atomic.load(eastl::memory_order_relaxed) == 1); } { AtomicType atomic; IntegralType expected = 0; bool ret = atomic_compare_exchange_strong_explicit(&atomic, &expected, 1, eastl::memory_order_relaxed, eastl::memory_order_relaxed); VERIFY(ret == true); VERIFY(expected == 0); VERIFY(atomic.load(eastl::memory_order_relaxed) == 1); } { AtomicType atomic; IntegralType ret = atomic_fetch_xor(&atomic, 0x1); VERIFY(ret == 0x0); VERIFY(atomic.load(eastl::memory_order_relaxed) == 0x1); } { AtomicType atomic; IntegralType ret = atomic_fetch_xor_explicit(&atomic, 0x1, eastl::memory_order_relaxed); VERIFY(ret == 0x0); VERIFY(atomic.load(eastl::memory_order_relaxed) == 0x1); } { AtomicType atomic; IntegralType ret = atomic_xor_fetch(&atomic, 0x1); VERIFY(ret == 0x1); VERIFY(atomic.load(eastl::memory_order_relaxed) == 0x1); } { AtomicType atomic; IntegralType ret = atomic_xor_fetch_explicit(&atomic, 0x1, eastl::memory_order_relaxed); VERIFY(ret == 0x1); VERIFY(atomic.load(eastl::memory_order_relaxed) == 0x1); } { AtomicType atomic; IntegralType ret = atomic_fetch_or(&atomic, 0x1); VERIFY(ret == 0x0); VERIFY(atomic.load(eastl::memory_order_relaxed) == 0x1); } { AtomicType atomic; IntegralType ret = atomic_fetch_or_explicit(&atomic, 0x1, eastl::memory_order_relaxed); VERIFY(ret == 0x0); VERIFY(atomic.load(eastl::memory_order_relaxed) == 0x1); } { AtomicType atomic; IntegralType ret = atomic_or_fetch(&atomic, 0x1); VERIFY(ret == 0x1); VERIFY(atomic.load(eastl::memory_order_relaxed) == 0x1); } { AtomicType atomic; IntegralType ret = atomic_or_fetch_explicit(&atomic, 0x1, eastl::memory_order_relaxed); VERIFY(ret == 0x1); VERIFY(atomic.load(eastl::memory_order_relaxed) == 0x1); } { AtomicType atomic{ 0x1 }; IntegralType ret = atomic_fetch_and(&atomic, 0x0); VERIFY(ret == 0x1); VERIFY(atomic.load(eastl::memory_order_relaxed) == 0x0); } { AtomicType atomic{ 0x1 }; IntegralType ret = atomic_fetch_and_explicit(&atomic, 0x0, eastl::memory_order_relaxed); VERIFY(ret == 0x1); VERIFY(atomic.load(eastl::memory_order_relaxed) == 0x0); } { AtomicType atomic{ 0x1 }; IntegralType ret = atomic_and_fetch(&atomic, 0x0); VERIFY(ret == 0x0); VERIFY(atomic.load(eastl::memory_order_relaxed) == 0x0); } { AtomicType atomic{ 0x1 }; IntegralType ret = atomic_and_fetch_explicit(&atomic, 0x0, eastl::memory_order_relaxed); VERIFY(ret == 0x0); VERIFY(atomic.load(eastl::memory_order_relaxed) == 0x0); } { AtomicType atomic{ 1 }; IntegralType ret = atomic_fetch_sub(&atomic, 1); VERIFY(ret == 1); VERIFY(atomic.load(eastl::memory_order_relaxed) == 0); } { AtomicType atomic{ 1 }; IntegralType ret = atomic_fetch_sub_explicit(&atomic, 1, eastl::memory_order_relaxed); VERIFY(ret == 1); VERIFY(atomic.load(eastl::memory_order_relaxed) == 0); } { AtomicType atomic{ 1 }; IntegralType ret = atomic_sub_fetch(&atomic, 1); VERIFY(ret == 0); VERIFY(atomic.load(eastl::memory_order_relaxed) == 0); } { AtomicType atomic{ 1 }; IntegralType ret = atomic_sub_fetch_explicit(&atomic, 1, eastl::memory_order_relaxed); VERIFY(ret == 0); VERIFY(atomic.load(eastl::memory_order_relaxed) == 0); } { AtomicType atomic; IntegralType ret = atomic_fetch_add(&atomic, 1); VERIFY(ret == 0); VERIFY(atomic.load(eastl::memory_order_relaxed) == 1); } { AtomicType atomic; IntegralType ret = atomic_fetch_add_explicit(&atomic, 1, eastl::memory_order_relaxed); VERIFY(ret == 0); VERIFY(atomic.load(eastl::memory_order_relaxed) == 1); } { AtomicType atomic; IntegralType ret = atomic_add_fetch(&atomic, 1); VERIFY(ret == 1); VERIFY(atomic.load(eastl::memory_order_relaxed) == 1); } { AtomicType atomic; IntegralType ret = atomic_add_fetch_explicit(&atomic, 1, eastl::memory_order_relaxed); VERIFY(ret == 1); VERIFY(atomic.load(eastl::memory_order_relaxed) == 1); } { AtomicType atomic; IntegralType ret = atomic_exchange(&atomic, 1); VERIFY(ret == 0); VERIFY(atomic.load(eastl::memory_order_relaxed) == 1); } { AtomicType atomic; IntegralType ret = atomic_exchange_explicit(&atomic, 1, eastl::memory_order_relaxed); VERIFY(ret == 0); VERIFY(atomic.load(eastl::memory_order_relaxed) == 1); } { AtomicType atomic; IntegralType ret = atomic_load(&atomic); VERIFY(ret == 0); } { AtomicType atomic; IntegralType ret = atomic_load_explicit(&atomic, eastl::memory_order_relaxed); VERIFY(ret == 0); } { AtomicType atomic; IntegralType ret = atomic_load_cond(&atomic, [](IntegralType val) { return true; }); VERIFY(ret == 0); } { AtomicType atomic; IntegralType ret = atomic_load_cond_explicit(&atomic, [](IntegralType val) { return true; }, eastl::memory_order_relaxed); VERIFY(ret == 0); } { AtomicType atomic; atomic_store(&atomic, 1); VERIFY(atomic.load(eastl::memory_order_relaxed) == 1); } { AtomicType atomic; atomic_store_explicit(&atomic, 1, eastl::memory_order_relaxed); VERIFY(atomic.load(eastl::memory_order_relaxed) == 1); } { AtomicType atomic; VERIFY(atomic_is_lock_free(&atomic) == true); } } struct AtomicNonDefaultConstructible { AtomicNonDefaultConstructible(uint8_t a) : a(a) { } friend bool operator==(const AtomicNonDefaultConstructible& a, const AtomicNonDefaultConstructible& b) { return a.a == b.a; } uint8_t a; }; #if defined(EASTL_ATOMIC_HAS_8BIT) int TestAtomicNonDefaultConstructible() { int nErrorCount = 0; { eastl::atomic atomic{AtomicNonDefaultConstructible{(uint8_t)3}}; VERIFY(atomic.load() == AtomicNonDefaultConstructible{(uint8_t)3}); } { eastl::atomic atomic{AtomicNonDefaultConstructible{(uint8_t)3}}; atomic.store(AtomicNonDefaultConstructible{(uint8_t)4}); VERIFY(atomic.load() == AtomicNonDefaultConstructible{(uint8_t)4}); } { eastl::atomic atomic{AtomicNonDefaultConstructible{(uint8_t)3}}; VERIFY(atomic_load_cond(&atomic, [] (AtomicNonDefaultConstructible) { return true; }) == AtomicNonDefaultConstructible{(uint8_t)3}); } { eastl::atomic atomic{AtomicNonDefaultConstructible{(uint8_t)3}}; VERIFY(atomic_load_cond_explicit(&atomic, [] (AtomicNonDefaultConstructible) { return true; }, eastl::memory_order_seq_cst) == AtomicNonDefaultConstructible{(uint8_t)3}); } return nErrorCount; } #endif struct Atomic128LoadType { friend bool operator==(const Atomic128LoadType& a, const Atomic128LoadType& b) { return a.a == b.a && a.b == b.b && a.c == b.c && a.d == b.d; } uint32_t a, b, c, d; }; #if defined(EASTL_ATOMIC_HAS_128BIT) int TestAtomic128Loads() { int nErrorCount = 0; { eastl::atomic atomic{Atomic128LoadType{1, 1, 0, 0}}; VERIFY((atomic.load() == Atomic128LoadType{1, 1, 0, 0})); } { eastl::atomic atomic{Atomic128LoadType{0, 0, 1, 1}}; VERIFY((atomic.load() == Atomic128LoadType{0, 0, 1, 1})); } { eastl::atomic atomic{Atomic128LoadType{0, 1, 0, 1}}; VERIFY((atomic.load() == Atomic128LoadType{0, 1, 0, 1})); } { eastl::atomic atomic{Atomic128LoadType{1, 0, 1, 0}}; VERIFY((atomic.load() == Atomic128LoadType{1, 0, 1, 0})); } { eastl::atomic atomic{Atomic128LoadType{1, 1, 0, 0}}; Atomic128LoadType expected{0, 0, 0, 0}; atomic.compare_exchange_strong(expected, Atomic128LoadType{1, 1, 0, 0}); VERIFY((expected == Atomic128LoadType{1, 1, 0, 0})); } { eastl::atomic atomic{Atomic128LoadType{0, 0, 1, 1}}; Atomic128LoadType expected{0, 0, 0, 0}; atomic.compare_exchange_strong(expected, Atomic128LoadType{0, 0, 1, 1}); VERIFY((expected == Atomic128LoadType{0, 0, 1, 1})); } { eastl::atomic atomic{Atomic128LoadType{0, 1, 0, 1}}; Atomic128LoadType expected{0, 0, 0, 0}; atomic.compare_exchange_strong(expected, Atomic128LoadType{0, 1, 0, 1}); VERIFY((expected == Atomic128LoadType{0, 1, 0, 1})); } { eastl::atomic atomic{Atomic128LoadType{1, 0, 1, 0}}; Atomic128LoadType expected{0, 0, 0, 0}; atomic.compare_exchange_strong(expected, Atomic128LoadType{1, 0, 1, 0}); VERIFY((expected == Atomic128LoadType{1, 0, 1, 0})); } { eastl::atomic atomic{Atomic128LoadType{0, 0, 0, 0}}; Atomic128LoadType expected{0, 0, 0, 0}; atomic.compare_exchange_strong(expected, Atomic128LoadType{1, 1, 0, 0}); VERIFY((atomic.load() == Atomic128LoadType{1, 1, 0, 0})); } { eastl::atomic atomic{Atomic128LoadType{0, 0, 0, 0}}; Atomic128LoadType expected{0, 0, 0, 0}; atomic.compare_exchange_strong(expected, Atomic128LoadType{0, 0, 1, 1}); VERIFY((atomic.load() == Atomic128LoadType{0, 0, 1, 1})); } { eastl::atomic atomic{Atomic128LoadType{0, 0, 0, 0}}; Atomic128LoadType expected{0, 0, 0, 0}; atomic.compare_exchange_strong(expected, Atomic128LoadType{0, 1, 0, 1}); VERIFY((atomic.load() == Atomic128LoadType{0, 1, 0, 1})); } { eastl::atomic atomic{Atomic128LoadType{0, 0, 0, 0}}; Atomic128LoadType expected{0, 0, 0, 0}; atomic.compare_exchange_strong(expected, Atomic128LoadType{1, 0, 1, 0}); VERIFY((atomic.load() == Atomic128LoadType{1, 0, 1, 0})); } return nErrorCount; } #endif int TestAtomicBasic() { int nErrorCount = 0; #if defined(EASTL_ATOMIC_HAS_8BIT) { AtomicIntegralBasicTest u8AtomicTest; nErrorCount += u8AtomicTest.RunTest(); } #endif #if defined(EASTL_ATOMIC_HAS_16BIT) { AtomicIntegralBasicTest u16AtomicTest; nErrorCount += u16AtomicTest.RunTest(); } #endif #if defined(EASTL_ATOMIC_HAS_32BIT) { AtomicIntegralBasicTest u32AtomicTest; nErrorCount += u32AtomicTest.RunTest(); } #endif #if defined(EASTL_ATOMIC_HAS_64BIT) { AtomicIntegralBasicTest u64AtomicTest; nErrorCount += u64AtomicTest.RunTest(); } #endif #if defined(EASTL_ATOMIC_HAS_128BIT) && (defined(EA_COMPILER_CLANG) || defined(EA_COMPILER_GNUC)) { AtomicIntegralBasicTest<__uint128_t> u128AtomicTest; nErrorCount += u128AtomicTest.RunTest(); } { AtomicIntegralBasicTest u128AtomicTest; nErrorCount += u128AtomicTest.RunTest(); } #endif { AtomicBoolBasicTest boolAtomicTest; nErrorCount += boolAtomicTest.RunTest(); } #if defined(EASTL_ATOMIC_HAS_16BIT) { AtomicUserTypeBasicTest userTypeAtomicTest; nErrorCount += userTypeAtomicTest.RunTest(); } #endif #if defined(EASTL_ATOMIC_HAS_32BIT) { AtomicUserTypeBasicTest userTypeAtomicTest; nErrorCount += userTypeAtomicTest.RunTest(); } { AtomicUserTypeBasicTest userTypeAtomicTest; nErrorCount += userTypeAtomicTest.RunTest(); } #endif #if defined(EASTL_ATOMIC_HAS_128BIT) { AtomicUserTypeBasicTest userTypeAtomicTest; nErrorCount += userTypeAtomicTest.RunTest(); } #endif { AtomicPointerBasicTest ptrAtomicTest; nErrorCount += ptrAtomicTest.RunTest(); } { AtomicVoidPointerBasicTest voidPtrAtomicTest; nErrorCount += voidPtrAtomicTest.RunTest(); } { AtomicFlagBasicTest atomicFlagBasicTest; nErrorCount += atomicFlagBasicTest.RunTest(); } { AtomicStandaloneBasicTest atomicStandaloneBasicTest; nErrorCount += atomicStandaloneBasicTest.RunTest(); } #if defined(EASTL_ATOMIC_HAS_128BIT) nErrorCount += TestAtomic128Loads(); #endif #if defined(EASTL_ATOMIC_HAS_8BIT) nErrorCount += TestAtomicNonDefaultConstructible(); #endif nErrorCount += TestAtomicConstantInitialization(); return nErrorCount; }