#pragma once #undef InterlockedExchange #undef InterlockedCompareExchange #undef InterlockedOr #undef InterlockedAnd #undef InterlockedXor template struct _to_atomic { static_assert(size == 1 || size == 2 || size == 4 || size == 8 || size == 16, "Invalid atomic type"); typedef T type; }; template struct _to_atomic { typedef uint8_t type; }; template struct _to_atomic { typedef uint16_t type; }; template struct _to_atomic { typedef uint32_t type; }; template struct _to_atomic { typedef uint64_t type; }; template struct _to_atomic { typedef u128 type; }; template class _atomic_base { typedef typename _to_atomic::type atomic_type; atomic_type data; public: // atomically compare data with cmp, replace with exch if equal, return previous data value anyway __forceinline const T compare_and_swap(const T& cmp, const T& exch) volatile { const atomic_type res = InterlockedCompareExchange(&data, (atomic_type&)(exch), (atomic_type&)(cmp)); return (T&)res; } // atomically compare data with cmp, replace with exch if equal, return true if data was replaced __forceinline bool compare_and_swap_test(const T& cmp, const T& exch) volatile { return InterlockedCompareExchangeTest(&data, (atomic_type&)(exch), (atomic_type&)(cmp)); } // read data with memory barrier __forceinline const T read_sync() const volatile { const atomic_type res = InterlockedCompareExchange(const_cast(&data), 0, 0); return (T&)res; } // atomically replace data with exch, return previous data value __forceinline const T exchange(const T& exch) volatile { const atomic_type res = InterlockedExchange(&data, (atomic_type&)(exch)); return (T&)res; } // read data without memory barrier __forceinline const T read_relaxed() const volatile { return (T&)data; } // write data without memory barrier __forceinline void write_relaxed(const T& value) { data = (atomic_type&)(value); } // perform atomic operation on data template __forceinline void atomic_op(const FT atomic_proc) volatile { while (true) { const T old = read_relaxed(); T _new = old; atomic_proc(_new); // function should accept reference to T type if (compare_and_swap_test(old, _new)) return; } } // perform atomic operation on data with special exit condition (if intermediate result != proceed_value) template __forceinline RT atomic_op(const RT proceed_value, const FT atomic_proc) volatile { while (true) { const T old = read_relaxed(); T _new = old; RT res = (RT)atomic_proc(_new); // function should accept reference to T type and return some value if (res != proceed_value) return res; if (compare_and_swap_test(old, _new)) return proceed_value; } } // perform atomic operation on data with additional memory barrier template __forceinline void atomic_op_sync(const FT atomic_proc) volatile { T old = read_sync(); while (true) { T _new = old; atomic_proc(_new); // function should accept reference to T type const T val = compare_and_swap(old, _new); if ((atomic_type&)val == (atomic_type&)old) return; old = val; } } // perform atomic operation on data with additional memory barrier and special exit condition (if intermediate result != proceed_value) template __forceinline RT atomic_op_sync(const RT proceed_value, const FT atomic_proc) volatile { T old = read_sync(); while (true) { T _new = old; RT res = (RT)atomic_proc(_new); // function should accept reference to T type and return some value if (res != proceed_value) return res; const T val = compare_and_swap(old, _new); if ((atomic_type&)val == (atomic_type&)old) return proceed_value; old = val; } } // perform non-atomic operation on data directly without memory barriers template __forceinline void direct_op(const FT direct_proc) volatile { direct_proc((T&)data); } // atomic bitwise OR, returns previous data __forceinline const T _or(const T& right) volatile { const atomic_type res = InterlockedOr(&data, (atomic_type&)(right)); return (T&)res; } // atomic bitwise AND, returns previous data __forceinline const T _and(const T& right) volatile { const atomic_type res = InterlockedAnd(&data, (atomic_type&)(right)); return (T&)res; } // atomic bitwise AND NOT (inverts right argument), returns previous data __forceinline const T _and_not(const T& right) volatile { const atomic_type res = InterlockedAnd(&data, ~(atomic_type&)(right)); return (T&)res; } // atomic bitwise XOR, returns previous data __forceinline const T _xor(const T& right) volatile { const atomic_type res = InterlockedXor(&data, (atomic_type&)(right)); return (T&)res; } __forceinline const T operator |= (const T& right) volatile { const atomic_type res = InterlockedOr(&data, (atomic_type&)(right)) | (atomic_type&)(right); return (T&)res; } __forceinline const T operator &= (const T& right) volatile { const atomic_type res = InterlockedAnd(&data, (atomic_type&)(right)) & (atomic_type&)(right); return (T&)res; } __forceinline const T operator ^= (const T& right) volatile { const atomic_type res = InterlockedXor(&data, (atomic_type&)(right)) ^ (atomic_type&)(right); return (T&)res; } }; template inline static typename std::enable_if::value, T>::type operator ++(_atomic_base>& left, int) { T result; left.atomic_op([&result](be_t& value) { result = value++; }); return result; } template inline static typename std::enable_if::value, T>::type operator --(_atomic_base>& left, int) { T result; left.atomic_op([&result](be_t& value) { result = value--; }); return result; } template inline static typename std::enable_if::value, T>::type operator +=(_atomic_base>& left, T2 right) { T result; left.atomic_op([&result, right](be_t& value) { result = (value += right); }); return result; } template inline static typename std::enable_if::value, T>::type operator -=(_atomic_base>& left, T2 right) { T result; left.atomic_op([&result, right](be_t& value) { result = (value -= right); }); return result; } template using atomic_le_t = _atomic_base; template using atomic_be_t = _atomic_base::type>; namespace ps3 { template using atomic_t = atomic_be_t; } namespace psv { template using atomic_t = atomic_le_t; } using namespace ps3;