#pragma once #include "CoreTypes.h" #include "Templates/Invoke.h" #include "Memory/Alignment.h" #include "Templates/Function.h" #include "TypeTraits/TypeTraits.h" #include "Templates/Noncopyable.h" #include NAMESPACE_REDCRAFT_BEGIN NAMESPACE_MODULE_BEGIN(Redcraft) NAMESPACE_MODULE_BEGIN(Utility) enum class EMemoryOrder : uint8 { Relaxed = static_cast::Type>(NAMESPACE_STD::memory_order_relaxed), Consume = static_cast::Type>(NAMESPACE_STD::memory_order_consume), Acquire = static_cast::Type>(NAMESPACE_STD::memory_order_acquire), Release = static_cast::Type>(NAMESPACE_STD::memory_order_release), AcquireRelease = static_cast::Type>(NAMESPACE_STD::memory_order_acq_rel), SequentiallyConsistent = static_cast::Type>(NAMESPACE_STD::memory_order_seq_cst), }; #if BUILD_DEBUG NAMESPACE_PRIVATE_BEGIN FORCEINLINE void MemoryOrderCheck(EMemoryOrder Order, uint8 Require) { switch (Order) { case EMemoryOrder::Relaxed: checkf((Require) & 0x01, TEXT("Invalid memory order.")); break; case EMemoryOrder::Consume: checkf((Require) & 0x02, TEXT("Invalid memory order.")); break; case EMemoryOrder::Acquire: checkf((Require) & 0x04, TEXT("Invalid memory order.")); break; case EMemoryOrder::Release: checkf((Require) & 0x08, TEXT("Invalid memory order.")); break; case EMemoryOrder::AcquireRelease: checkf((Require) & 0x10, TEXT("Invalid memory order.")); break; case EMemoryOrder::SequentiallyConsistent: checkf((Require) & 0x20, TEXT("Invalid memory order.")); break; default: check_no_entry(); } } NAMESPACE_PRIVATE_END #define MEMORY_ORDER_CHECK(Order, Require) NAMESPACE_PRIVATE::MemoryOrderCheck(Order, Require) #else #define MEMORY_ORDER_CHECK(Order, Require) #endif template requires TIsTriviallyCopyable::Value && TIsCopyConstructible::Value && TIsMoveConstructible::Value && TIsCopyAssignable::Value && TIsMoveAssignable::Value struct TAtomic : public FSingleton { protected: using ElementType = typename TConditional, NAMESPACE_STD::atomic>::Type; public: using ValueType = T; static constexpr bool bIsAlwaysLockFree = ElementType::is_always_lock_free; static constexpr size_t RequiredAlignment = NAMESPACE_STD::atomic_ref::required_alignment; constexpr TAtomic() requires (!bIsRef) : Element() { }; constexpr TAtomic(ValueType Desired) requires (!bIsRef) : Element(Desired) { }; FORCEINLINE explicit TAtomic(ValueType& Desired) requires (bIsRef) : Element(Desired) { check(Memory::IsAligned(&Desired, RequiredAlignment)); }; FORCEINLINE TAtomic(TAtomic& InValue) requires (bIsRef) : Element(InValue) { }; FORCEINLINE ValueType operator=(ValueType Desired) { return Element = Desired; } FORCEINLINE ValueType operator=(ValueType Desired) volatile requires bIsAlwaysLockFree { return Element = Desired; } FORCEINLINE void Store(ValueType Desired, EMemoryOrder Order = EMemoryOrder::SequentiallyConsistent) { MEMORY_ORDER_CHECK(Order, 0x01 | 0x08 | 0x20); Element.store(Desired, static_cast(Order)); } FORCEINLINE void Store(ValueType Desired, EMemoryOrder Order = EMemoryOrder::SequentiallyConsistent) volatile requires bIsAlwaysLockFree { MEMORY_ORDER_CHECK(Order, 0x01 | 0x08 | 0x20); Element.store(Desired, static_cast(Order)); } FORCEINLINE ValueType Load(EMemoryOrder Order = EMemoryOrder::SequentiallyConsistent) const { MEMORY_ORDER_CHECK(Order, 0x01 | 0x02 | 0x04 | 0x20); return Element.load(static_cast(Order)); } FORCEINLINE ValueType Load(EMemoryOrder Order = EMemoryOrder::SequentiallyConsistent) const volatile requires bIsAlwaysLockFree { MEMORY_ORDER_CHECK(Order, 0x01 | 0x02 | 0x04 | 0x20); return Element.load(static_cast(Order)); } FORCEINLINE operator ValueType() const { return static_cast(Element); } FORCEINLINE operator ValueType() const volatile requires bIsAlwaysLockFree { return static_cast(Element); } FORCEINLINE ValueType Exchange(ValueType Desired, EMemoryOrder Order = EMemoryOrder::SequentiallyConsistent) { return Element.exchange(Desired, static_cast(Order)); } FORCEINLINE ValueType Exchange(ValueType Desired, EMemoryOrder Order = EMemoryOrder::SequentiallyConsistent) volatile requires bIsAlwaysLockFree { return Element.exchange(Desired, static_cast(Order)); } FORCEINLINE bool CompareExchange(ValueType& Expected, ValueType Desired, EMemoryOrder Success, EMemoryOrder Failure, bool bIsWeak = false) { MEMORY_ORDER_CHECK(Failure, 0x01 | 0x02 | 0x04 | 0x20); if (bIsWeak) return Element.compare_exchange_weak(Expected, Desired, static_cast(Success), static_cast(Failure)); else return Element.compare_exchange_strong(Expected, Desired, static_cast(Success), static_cast(Failure)); } FORCEINLINE bool CompareExchange(ValueType& Expected, ValueType Desired, EMemoryOrder Success, EMemoryOrder Failure, bool bIsWeak = false) volatile requires bIsAlwaysLockFree { MEMORY_ORDER_CHECK(Failure, 0x01 | 0x02 | 0x04 | 0x20); if (bIsWeak) return Element.compare_exchange_weak(Expected, Desired, static_cast(Success), static_cast(Failure)); else return Element.compare_exchange_strong(Expected, Desired, static_cast(Success), static_cast(Failure)); } FORCEINLINE bool CompareExchange(ValueType& Expected, ValueType Desired, EMemoryOrder Order = EMemoryOrder::SequentiallyConsistent, bool bIsWeak = false) { if (bIsWeak) return Element.compare_exchange_weak(Expected, Desired, static_cast(Order)); else return Element.compare_exchange_strong(Expected, Desired, static_cast(Order)); } FORCEINLINE bool CompareExchange(ValueType& Expected, ValueType Desired, EMemoryOrder Order = EMemoryOrder::SequentiallyConsistent, bool bIsWeak = false) volatile requires bIsAlwaysLockFree { if (bIsWeak) return Element.compare_exchange_weak(Expected, Desired, static_cast(Order)); else return Element.compare_exchange_strong(Expected, Desired, static_cast(Order)); } FORCEINLINE void Wait(ValueType Old, EMemoryOrder Order = EMemoryOrder::SequentiallyConsistent) { MEMORY_ORDER_CHECK(Order, 0x01 | 0x02 | 0x04 | 0x20); Element.wait(Old, static_cast(Order)); } FORCEINLINE void Wait(ValueType Old, EMemoryOrder Order = EMemoryOrder::SequentiallyConsistent) volatile { MEMORY_ORDER_CHECK(Order, 0x01 | 0x02 | 0x04 | 0x20); Element.wait(Old, static_cast(Order)); } FORCEINLINE void Notify(bool bIsAll = false) { if (bIsAll) Element.notify_all(); else Element.notify_one(); } FORCEINLINE void Notify(bool bIsAll = false) volatile { if (bIsAll) Element.notify_all(); else Element.notify_one(); } template requires TIsInvocableResult::Value FORCEINLINE ValueType FetchFn(F&& Func, EMemoryOrder Order = EMemoryOrder::SequentiallyConsistent) { ValueType Temp(Load(EMemoryOrder::Relaxed)); while (!CompareExchange(Temp, InvokeResult(Forward(Func), Temp), Order)); return Temp; } template requires TIsInvocableResult::Value && bIsAlwaysLockFree FORCEINLINE ValueType FetchFn(F&& Func, EMemoryOrder Order = EMemoryOrder::SequentiallyConsistent) volatile { ValueType Temp(Load(EMemoryOrder::Relaxed)); while (!CompareExchange(Temp, InvokeResult(Forward(Func), Temp), Order)); return Temp; } FORCEINLINE ValueType FetchAdd(ValueType InValue, EMemoryOrder Order = EMemoryOrder::SequentiallyConsistent) requires (TIsIntegral::Value || TIsFloatingPoint::Value) { return Element.fetch_add(InValue, static_cast(Order)); } FORCEINLINE ValueType FetchAdd(ValueType InValue, EMemoryOrder Order = EMemoryOrder::SequentiallyConsistent) volatile requires (TIsIntegral::Value || TIsFloatingPoint::Value) && bIsAlwaysLockFree { return Element.fetch_add(InValue, static_cast(Order)); } FORCEINLINE ValueType FetchAdd(ptrdiff InValue, EMemoryOrder Order = EMemoryOrder::SequentiallyConsistent) requires TIsPointer::Value { return Element.fetch_add(InValue, static_cast(Order)); } FORCEINLINE ValueType FetchAdd(ptrdiff InValue, EMemoryOrder Order = EMemoryOrder::SequentiallyConsistent) volatile requires TIsPointer::Value && bIsAlwaysLockFree { return Element.fetch_add(InValue, static_cast(Order)); } FORCEINLINE ValueType FetchSub(ValueType InValue, EMemoryOrder Order = EMemoryOrder::SequentiallyConsistent) requires (TIsIntegral::Value || TIsFloatingPoint::Value) { return Element.fetch_sub(InValue, static_cast(Order)); } FORCEINLINE ValueType FetchSub(ValueType InValue, EMemoryOrder Order = EMemoryOrder::SequentiallyConsistent) volatile requires (TIsIntegral::Value || TIsFloatingPoint::Value) && bIsAlwaysLockFree { return Element.fetch_sub(InValue, static_cast(Order)); } FORCEINLINE ValueType FetchSub(ptrdiff InValue, EMemoryOrder Order = EMemoryOrder::SequentiallyConsistent) requires TIsPointer::Value { return Element.fetch_sub(InValue, static_cast(Order)); } FORCEINLINE ValueType FetchSub(ptrdiff InValue, EMemoryOrder Order = EMemoryOrder::SequentiallyConsistent) volatile requires TIsPointer::Value && bIsAlwaysLockFree { return Element.fetch_sub(InValue, static_cast(Order)); } FORCEINLINE ValueType FetchMul(ValueType InValue, EMemoryOrder Order = EMemoryOrder::SequentiallyConsistent) requires (TIsIntegral::Value || TIsFloatingPoint::Value) { return FetchFn([InValue](ValueType Old) -> ValueType { return Old * InValue; }); } FORCEINLINE ValueType FetchMul(ValueType InValue, EMemoryOrder Order = EMemoryOrder::SequentiallyConsistent) volatile requires (TIsIntegral::Value || TIsFloatingPoint::Value) && bIsAlwaysLockFree { return FetchFn([InValue](ValueType Old) -> ValueType { return Old * InValue; }); } FORCEINLINE ValueType FetchDiv(ValueType InValue, EMemoryOrder Order = EMemoryOrder::SequentiallyConsistent) requires (TIsIntegral::Value || TIsFloatingPoint::Value) { return FetchFn([InValue](ValueType Old) -> ValueType { return Old / InValue; }); } FORCEINLINE ValueType FetchDiv(ValueType InValue, EMemoryOrder Order = EMemoryOrder::SequentiallyConsistent) volatile requires (TIsIntegral::Value || TIsFloatingPoint::Value) && bIsAlwaysLockFree { return FetchFn([InValue](ValueType Old) -> ValueType { return Old / InValue; }); } FORCEINLINE ValueType FetchMod(ValueType InValue, EMemoryOrder Order = EMemoryOrder::SequentiallyConsistent) requires TIsIntegral::Value { return FetchFn([InValue](ValueType Old) -> ValueType { return Old % InValue; }); } FORCEINLINE ValueType FetchMod(ValueType InValue, EMemoryOrder Order = EMemoryOrder::SequentiallyConsistent) volatile requires TIsIntegral::Value && bIsAlwaysLockFree { return FetchFn([InValue](ValueType Old) -> ValueType { return Old % InValue; }); } FORCEINLINE ValueType FetchAnd(ValueType InValue, EMemoryOrder Order = EMemoryOrder::SequentiallyConsistent) requires TIsIntegral::Value { return Element.fetch_and(InValue, static_cast(Order)); } FORCEINLINE ValueType FetchAnd(ValueType InValue, EMemoryOrder Order = EMemoryOrder::SequentiallyConsistent) volatile requires TIsIntegral::Value && bIsAlwaysLockFree { return Element.fetch_and(InValue, static_cast(Order)); } FORCEINLINE ValueType FetchOr(ValueType InValue, EMemoryOrder Order = EMemoryOrder::SequentiallyConsistent) requires TIsIntegral::Value { return Element.fetch_or(InValue, static_cast(Order)); } FORCEINLINE ValueType FetchOr(ValueType InValue, EMemoryOrder Order = EMemoryOrder::SequentiallyConsistent) volatile requires TIsIntegral::Value && bIsAlwaysLockFree { return Element.fetch_or(InValue, static_cast(Order)); } FORCEINLINE ValueType FetchXor(ValueType InValue, EMemoryOrder Order = EMemoryOrder::SequentiallyConsistent) requires TIsIntegral::Value { return Element.fetch_xor(InValue, static_cast(Order)); } FORCEINLINE ValueType FetchXor(ValueType InValue, EMemoryOrder Order = EMemoryOrder::SequentiallyConsistent) volatile requires TIsIntegral::Value && bIsAlwaysLockFree { return Element.fetch_xor(InValue, static_cast(Order)); } FORCEINLINE ValueType FetchLsh(size_t InValue, EMemoryOrder Order = EMemoryOrder::SequentiallyConsistent) requires TIsIntegral::Value { return FetchFn([InValue](ValueType Old) -> ValueType { return Old << InValue; }); } FORCEINLINE ValueType FetchLsh(size_t InValue, EMemoryOrder Order = EMemoryOrder::SequentiallyConsistent) volatile requires TIsIntegral::Value && bIsAlwaysLockFree { return FetchFn([InValue](ValueType Old) -> ValueType { return Old << InValue; }); } FORCEINLINE ValueType FetchRsh(size_t InValue, EMemoryOrder Order = EMemoryOrder::SequentiallyConsistent) requires TIsIntegral::Value { return FetchFn([InValue](ValueType Old) -> ValueType { return Old >> InValue; }); } FORCEINLINE ValueType FetchRsh(size_t InValue, EMemoryOrder Order = EMemoryOrder::SequentiallyConsistent) volatile requires TIsIntegral::Value && bIsAlwaysLockFree { return FetchFn([InValue](ValueType Old) -> ValueType { return Old >> InValue; }); } FORCEINLINE ValueType operator++() requires (TIsIntegral::Value || TIsPointer::Value) { return ++Element; } FORCEINLINE ValueType operator++() volatile requires (TIsIntegral::Value || TIsPointer::Value) && bIsAlwaysLockFree { return ++Element; } FORCEINLINE ValueType operator++(int) requires (TIsIntegral::Value || TIsPointer::Value) { return Element++; } FORCEINLINE ValueType operator++(int) volatile requires (TIsIntegral::Value || TIsPointer::Value) && bIsAlwaysLockFree { return Element++; } FORCEINLINE ValueType operator--() requires (TIsIntegral::Value || TIsPointer::Value) { return --Element; } FORCEINLINE ValueType operator--() volatile requires (TIsIntegral::Value || TIsPointer::Value) && bIsAlwaysLockFree { return --Element; } FORCEINLINE ValueType operator--(int) requires (TIsIntegral::Value || TIsPointer::Value) { return Element--; } FORCEINLINE ValueType operator--(int) volatile requires (TIsIntegral::Value || TIsPointer::Value) && bIsAlwaysLockFree { return Element--; } FORCEINLINE ValueType operator+=(ValueType InValue) requires (TIsIntegral::Value || TIsFloatingPoint::Value) { return Element += InValue; } FORCEINLINE ValueType operator+=(ValueType InValue) volatile requires (TIsIntegral::Value || TIsFloatingPoint::Value) && bIsAlwaysLockFree { return Element += InValue; } FORCEINLINE ValueType operator+=(ptrdiff InValue) requires TIsPointer::Value { return Element += InValue; } FORCEINLINE ValueType operator+=(ptrdiff InValue) volatile requires TIsPointer::Value && bIsAlwaysLockFree { return Element += InValue; } FORCEINLINE ValueType operator-=(ValueType InValue) requires (TIsIntegral::Value || TIsFloatingPoint::Value) { return Element -= InValue; } FORCEINLINE ValueType operator-=(ValueType InValue) volatile requires (TIsIntegral::Value || TIsFloatingPoint::Value) && bIsAlwaysLockFree { return Element -= InValue; } FORCEINLINE ValueType operator-=(ptrdiff InValue) requires TIsPointer::Value { return Element -= InValue; } FORCEINLINE ValueType operator-=(ptrdiff InValue) volatile requires TIsPointer::Value && bIsAlwaysLockFree { return Element -= InValue; } FORCEINLINE ValueType operator*=(ValueType InValue) requires (TIsIntegral::Value || TIsFloatingPoint::Value) { return FetchMul(InValue) * InValue; } FORCEINLINE ValueType operator*=(ValueType InValue) volatile requires (TIsIntegral::Value || TIsFloatingPoint::Value) && bIsAlwaysLockFree { return FetchMul(InValue) * InValue; } FORCEINLINE ValueType operator/=(ValueType InValue) requires (TIsIntegral::Value || TIsFloatingPoint::Value) { return FetchDiv(InValue) / InValue; } FORCEINLINE ValueType operator/=(ValueType InValue) volatile requires (TIsIntegral::Value || TIsFloatingPoint::Value) && bIsAlwaysLockFree { return FetchDiv(InValue) / InValue; } FORCEINLINE ValueType operator%=(ValueType InValue) requires TIsIntegral::Value { return FetchMod(InValue) % InValue; } FORCEINLINE ValueType operator%=(ValueType InValue) volatile requires TIsIntegral::Value && bIsAlwaysLockFree { return FetchMod(InValue) % InValue; } FORCEINLINE ValueType operator&=(ValueType InValue) requires TIsIntegral::Value { return Element &= InValue; } FORCEINLINE ValueType operator&=(ValueType InValue) volatile requires TIsIntegral::Value && bIsAlwaysLockFree { return Element &= InValue; } FORCEINLINE ValueType operator|=(ValueType InValue) requires TIsIntegral::Value { return Element |= InValue; } FORCEINLINE ValueType operator|=(ValueType InValue) volatile requires TIsIntegral::Value && bIsAlwaysLockFree { return Element |= InValue; } FORCEINLINE ValueType operator^=(ValueType InValue) requires TIsIntegral::Value { return Element ^= InValue; } FORCEINLINE ValueType operator^=(ValueType InValue) volatile requires TIsIntegral::Value && bIsAlwaysLockFree { return Element ^= InValue; } FORCEINLINE ValueType operator<<=(size_t InValue) requires TIsIntegral::Value { return FetchLsh(InValue) << InValue; } FORCEINLINE ValueType operator<<=(size_t InValue) volatile requires TIsIntegral::Value && bIsAlwaysLockFree { return FetchLsh(InValue) << InValue; } FORCEINLINE ValueType operator>>=(size_t InValue) requires TIsIntegral::Value { return FetchRsh(InValue) >> InValue; } FORCEINLINE ValueType operator>>=(size_t InValue) volatile requires TIsIntegral::Value && bIsAlwaysLockFree { return FetchRsh(InValue) >> InValue; } protected: ElementType Element; }; template using TAtomicRef = TAtomic; template TAtomic(T) -> TAtomic; struct FAtomicFlag : public FSingleton { public: constexpr FAtomicFlag() : Element() { }; FORCEINLINE void Clear(EMemoryOrder Order = EMemoryOrder::SequentiallyConsistent) { MEMORY_ORDER_CHECK(Order, 0x01 | 0x08 | 0x20); Element.clear(static_cast(Order)); } FORCEINLINE void Clear(EMemoryOrder Order = EMemoryOrder::SequentiallyConsistent) volatile { MEMORY_ORDER_CHECK(Order, 0x01 | 0x08 | 0x20); Element.clear(static_cast(Order)); } FORCEINLINE bool TestAndSet(EMemoryOrder Order = EMemoryOrder::SequentiallyConsistent) { return Element.test_and_set(static_cast(Order)); } FORCEINLINE bool TestAndSet(EMemoryOrder Order = EMemoryOrder::SequentiallyConsistent) volatile { return Element.test_and_set(static_cast(Order)); } FORCEINLINE bool Test(EMemoryOrder Order = EMemoryOrder::SequentiallyConsistent) const { MEMORY_ORDER_CHECK(Order, 0x01 | 0x02 | 0x04 | 0x20); return Element.test(static_cast(Order)); } FORCEINLINE bool Test(EMemoryOrder Order = EMemoryOrder::SequentiallyConsistent) const volatile { MEMORY_ORDER_CHECK(Order, 0x01 | 0x02 | 0x04 | 0x20); return Element.test(static_cast(Order)); } FORCEINLINE void Wait(bool Old, EMemoryOrder Order = EMemoryOrder::SequentiallyConsistent) const { MEMORY_ORDER_CHECK(Order, 0x01 | 0x02 | 0x04 | 0x20); const_cast(Element).wait(Old, static_cast(Order)); } FORCEINLINE void Wait(bool Old, EMemoryOrder Order = EMemoryOrder::SequentiallyConsistent) const volatile { MEMORY_ORDER_CHECK(Order, 0x01 | 0x02 | 0x04 | 0x20); const_cast(Element).wait(Old, static_cast(Order)); } FORCEINLINE void Notify(bool bIsAll = false) { if (bIsAll) const_cast(Element).notify_all(); else const_cast(Element).notify_one(); } FORCEINLINE void Notify(bool bIsAll = false) volatile { if (bIsAll) const_cast(Element).notify_all(); else const_cast(Element).notify_one(); } protected: NAMESPACE_STD::atomic_flag Element; }; template inline T KillDependency(T InValue) { T Temp(InValue); return Temp; } extern "C" FORCEINLINE void AtomicThreadFence(EMemoryOrder Order = EMemoryOrder::SequentiallyConsistent) { NAMESPACE_STD::atomic_thread_fence(static_cast(Order)); } extern "C" FORCEINLINE void AtomicSignalFence(EMemoryOrder Order = EMemoryOrder::SequentiallyConsistent) { NAMESPACE_STD::atomic_signal_fence(static_cast(Order)); } #undef MEMORY_ORDER_CHECK NAMESPACE_MODULE_END(Utility) NAMESPACE_MODULE_END(Redcraft) NAMESPACE_REDCRAFT_END