refactor(templates): allow some template classes to derive and replace some using with inheritance

This commit is contained in:
_Redstone_c_ 2022-11-21 23:28:19 +08:00
parent e35fa9dd11
commit 058f07fedc
9 changed files with 128 additions and 102 deletions

View File

@ -574,6 +574,7 @@ void TestAny()
FAny TempC = static_cast<int32>(16); FAny TempC = static_cast<int32>(16);
FAny TempD = static_cast<int32>(32); FAny TempD = static_cast<int32>(32);
always_check(TempA == TempA);
always_check(TempA != TempB); always_check(TempA != TempB);
always_check(TempB != TempC); always_check(TempB != TempC);
always_check(TempB != TempC); always_check(TempB != TempC);

View File

@ -18,12 +18,12 @@ inline constexpr size_t MinimumAlignment = 8;
#ifdef __cpp_lib_hardware_interference_size #ifdef __cpp_lib_hardware_interference_size
inline constexpr size_t DestructiveInterference = std::hardware_destructive_interference_size; inline constexpr size_t DestructiveInterference = std::hardware_destructive_interference_size;
inline constexpr size_t ConstructiveInterference = std::hardware_constructive_interference_size; inline constexpr size_t ConstructiveInterference = std::hardware_constructive_interference_size;
#else #else
inline constexpr size_t DestructiveInterference = 64; inline constexpr size_t DestructiveInterference = 64;
inline constexpr size_t ConstructiveInterference = 64; inline constexpr size_t ConstructiveInterference = 64;
#endif #endif

View File

@ -74,7 +74,7 @@ static_assert(CAnyCustomStorage<FAnyDefaultStorage>);
// You can add custom storage area through CustomStorage, such as TFunction // You can add custom storage area through CustomStorage, such as TFunction
// It is not recommended to use this, FAny is recommended // It is not recommended to use this, FAny is recommended
template <CAnyCustomStorage CustomStorage = FAnyDefaultStorage> template <CAnyCustomStorage CustomStorage>
class TAny class TAny
{ {
public: public:
@ -142,8 +142,8 @@ public:
EmplaceImpl<SelectedType>(Forward<Ts>(Args)...); EmplaceImpl<SelectedType>(Forward<Ts>(Args)...);
} }
template <typename T> requires (!CSameAs<TDecay<T>, TAny> && !CTInPlaceType<TDecay<T>>) template <typename T> requires (!CBaseOf<TAny, TDecay<T>> && !CTInPlaceType<TDecay<T>>
&& CDestructible<TDecay<T>> && CConstructibleFrom<TDecay<T>, T&&> && CDestructible<TDecay<T>> && CConstructibleFrom<TDecay<T>, T&&>)
FORCEINLINE TAny(T&& InValue) : TAny(InPlaceType<TDecay<T>>, Forward<T>(InValue)) FORCEINLINE TAny(T&& InValue) : TAny(InPlaceType<TDecay<T>>, Forward<T>(InValue))
{ } { }
@ -254,8 +254,8 @@ public:
return *this; return *this;
} }
template <typename T> requires (!CSameAs<TDecay<T>, TAny> && !CTInPlaceType<TDecay<T>>) template <typename T> requires (!CBaseOf<TAny, TDecay<T>> && !CTInPlaceType<TDecay<T>>
&& CDestructible<TDecay<T>> && CConstructibleFrom<TDecay<T>, T&&> && CDestructible<TDecay<T>> && CConstructibleFrom<TDecay<T>, T&&>)
FORCEINLINE TAny& operator=(T&& InValue) FORCEINLINE TAny& operator=(T&& InValue)
{ {
using SelectedType = TDecay<T>; using SelectedType = TDecay<T>;
@ -484,7 +484,11 @@ private:
}; };
template <typename T, CAnyCustomStorage StorageType> class FAny : STRONG_INHERIT(TAny<FAnyDefaultStorage>);
static_assert(sizeof(FAny) == 64, "The byte size of FAny is unexpected");
template <typename T, CAnyCustomStorage StorageType> requires (!CBaseOf<FAny, TRemoveCVRef<T>>)
constexpr bool operator==(const TAny<StorageType>& LHS, const T& RHS) constexpr bool operator==(const TAny<StorageType>& LHS, const T& RHS)
{ {
return LHS.template HoldsAlternative<T>() ? LHS.template GetValue<T>() == RHS : false; return LHS.template HoldsAlternative<T>() ? LHS.template GetValue<T>() == RHS : false;
@ -506,10 +510,6 @@ NAMESPACE_PRIVATE_END
template <typename T> template <typename T>
concept CTAny = NAMESPACE_PRIVATE::TIsTAny<TRemoveCV<T>>::Value; concept CTAny = NAMESPACE_PRIVATE::TIsTAny<TRemoveCV<T>>::Value;
using FAny = TAny<>;
static_assert(sizeof(FAny) == 64, "The byte size of FAny is unexpected");
NAMESPACE_MODULE_END(Utility) NAMESPACE_MODULE_END(Utility)
NAMESPACE_MODULE_END(Redcraft) NAMESPACE_MODULE_END(Redcraft)
NAMESPACE_REDCRAFT_END NAMESPACE_REDCRAFT_END

View File

@ -51,75 +51,75 @@ NAMESPACE_PRIVATE_END
#endif #endif
template <typename T, bool bIsRef = false> requires (CTriviallyCopyable<T> NAMESPACE_PRIVATE_BEGIN
&& CCopyConstructible<T> && CMoveConstructible<T>
&& CCopyAssignable<T> && CMoveAssignable<T>) template <typename T, bool bIsRef>
struct TAtomic : FSingleton struct TAtomicImpl : FSingleton
{ {
protected: protected:
using ElementType = TConditional<bIsRef, NAMESPACE_STD::atomic_ref<T>, NAMESPACE_STD::atomic<T>>; using NativeAtomicType = TConditional<bIsRef, NAMESPACE_STD::atomic_ref<T>, NAMESPACE_STD::atomic<T>>;
public: public:
using ValueType = T; using ValueType = T;
static constexpr bool bIsAlwaysLockFree = ElementType::is_always_lock_free; static constexpr bool bIsAlwaysLockFree = NativeAtomicType::is_always_lock_free;
static constexpr size_t RequiredAlignment = NAMESPACE_STD::atomic_ref<T>::required_alignment; static constexpr size_t RequiredAlignment = NAMESPACE_STD::atomic_ref<T>::required_alignment;
constexpr TAtomic() requires (!bIsRef) : Element() { }; constexpr TAtomicImpl() requires (!bIsRef) : NativeAtomic() { };
constexpr TAtomic(ValueType Desired) requires (!bIsRef) : Element(Desired) { }; constexpr TAtomicImpl(ValueType Desired) requires (!bIsRef) : NativeAtomic(Desired) { };
FORCEINLINE explicit TAtomic(ValueType& Desired) requires (bIsRef) : Element(Desired) { check(Memory::IsAligned(&Desired, RequiredAlignment)); }; FORCEINLINE explicit TAtomicImpl(ValueType& Desired) requires (bIsRef) : NativeAtomic(Desired) { check(Memory::IsAligned(&Desired, RequiredAlignment)); };
FORCEINLINE TAtomic(TAtomic& InValue) requires (bIsRef) : Element(InValue) { }; FORCEINLINE TAtomicImpl(TAtomicImpl& InValue) requires (bIsRef) : NativeAtomic(InValue) { };
FORCEINLINE ValueType operator=(ValueType Desired) { return Element = Desired; } FORCEINLINE ValueType operator=(ValueType Desired) { return NativeAtomic = Desired; }
FORCEINLINE ValueType operator=(ValueType Desired) volatile requires (bIsAlwaysLockFree) { return Element = Desired; } FORCEINLINE ValueType operator=(ValueType Desired) volatile requires (bIsAlwaysLockFree) { return NativeAtomic = Desired; }
FORCEINLINE void Store(ValueType Desired, EMemoryOrder Order = EMemoryOrder::SequentiallyConsistent) { MEMORY_ORDER_CHECK(Order, 0x01 | 0x08 | 0x20); Element.store(Desired, static_cast<NAMESPACE_STD::memory_order>(Order)); } FORCEINLINE void Store(ValueType Desired, EMemoryOrder Order = EMemoryOrder::SequentiallyConsistent) { MEMORY_ORDER_CHECK(Order, 0x01 | 0x08 | 0x20); NativeAtomic.store(Desired, static_cast<NAMESPACE_STD::memory_order>(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<NAMESPACE_STD::memory_order>(Order)); } FORCEINLINE void Store(ValueType Desired, EMemoryOrder Order = EMemoryOrder::SequentiallyConsistent) volatile requires (bIsAlwaysLockFree) { MEMORY_ORDER_CHECK(Order, 0x01 | 0x08 | 0x20); NativeAtomic.store(Desired, static_cast<NAMESPACE_STD::memory_order>(Order)); }
FORCEINLINE ValueType Load(EMemoryOrder Order = EMemoryOrder::SequentiallyConsistent) const { MEMORY_ORDER_CHECK(Order, 0x01 | 0x02 | 0x04 | 0x20); return Element.load(static_cast<NAMESPACE_STD::memory_order>(Order)); } FORCEINLINE ValueType Load(EMemoryOrder Order = EMemoryOrder::SequentiallyConsistent) const { MEMORY_ORDER_CHECK(Order, 0x01 | 0x02 | 0x04 | 0x20); return NativeAtomic.load(static_cast<NAMESPACE_STD::memory_order>(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<NAMESPACE_STD::memory_order>(Order)); } FORCEINLINE ValueType Load(EMemoryOrder Order = EMemoryOrder::SequentiallyConsistent) const volatile requires (bIsAlwaysLockFree) { MEMORY_ORDER_CHECK(Order, 0x01 | 0x02 | 0x04 | 0x20); return NativeAtomic.load(static_cast<NAMESPACE_STD::memory_order>(Order)); }
FORCEINLINE operator ValueType() const { return static_cast<ValueType>(Element); } FORCEINLINE operator ValueType() const { return static_cast<ValueType>(NativeAtomic); }
FORCEINLINE operator ValueType() const volatile requires (bIsAlwaysLockFree) { return static_cast<ValueType>(Element); } FORCEINLINE operator ValueType() const volatile requires (bIsAlwaysLockFree) { return static_cast<ValueType>(NativeAtomic); }
FORCEINLINE ValueType Exchange(ValueType Desired, EMemoryOrder Order = EMemoryOrder::SequentiallyConsistent) { return Element.exchange(Desired, static_cast<NAMESPACE_STD::memory_order>(Order)); } FORCEINLINE ValueType Exchange(ValueType Desired, EMemoryOrder Order = EMemoryOrder::SequentiallyConsistent) { return NativeAtomic.exchange(Desired, static_cast<NAMESPACE_STD::memory_order>(Order)); }
FORCEINLINE ValueType Exchange(ValueType Desired, EMemoryOrder Order = EMemoryOrder::SequentiallyConsistent) volatile requires (bIsAlwaysLockFree) { return Element.exchange(Desired, static_cast<NAMESPACE_STD::memory_order>(Order)); } FORCEINLINE ValueType Exchange(ValueType Desired, EMemoryOrder Order = EMemoryOrder::SequentiallyConsistent) volatile requires (bIsAlwaysLockFree) { return NativeAtomic.exchange(Desired, static_cast<NAMESPACE_STD::memory_order>(Order)); }
FORCEINLINE bool CompareExchange(ValueType& Expected, ValueType Desired, EMemoryOrder Success, EMemoryOrder Failure, bool bIsWeak = false) FORCEINLINE bool CompareExchange(ValueType& Expected, ValueType Desired, EMemoryOrder Success, EMemoryOrder Failure, bool bIsWeak = false)
{ {
MEMORY_ORDER_CHECK(Failure, 0x01 | 0x02 | 0x04 | 0x20); MEMORY_ORDER_CHECK(Failure, 0x01 | 0x02 | 0x04 | 0x20);
if (bIsWeak) return Element.compare_exchange_weak(Expected, Desired, static_cast<NAMESPACE_STD::memory_order>(Success), static_cast<NAMESPACE_STD::memory_order>(Failure)); if (bIsWeak) return NativeAtomic.compare_exchange_weak(Expected, Desired, static_cast<NAMESPACE_STD::memory_order>(Success), static_cast<NAMESPACE_STD::memory_order>(Failure));
else return Element.compare_exchange_strong(Expected, Desired, static_cast<NAMESPACE_STD::memory_order>(Success), static_cast<NAMESPACE_STD::memory_order>(Failure)); else return NativeAtomic.compare_exchange_strong(Expected, Desired, static_cast<NAMESPACE_STD::memory_order>(Success), static_cast<NAMESPACE_STD::memory_order>(Failure));
} }
FORCEINLINE bool CompareExchange(ValueType& Expected, ValueType Desired, EMemoryOrder Success, EMemoryOrder Failure, bool bIsWeak = false) volatile requires (bIsAlwaysLockFree) 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); MEMORY_ORDER_CHECK(Failure, 0x01 | 0x02 | 0x04 | 0x20);
if (bIsWeak) return Element.compare_exchange_weak(Expected, Desired, static_cast<NAMESPACE_STD::memory_order>(Success), static_cast<NAMESPACE_STD::memory_order>(Failure)); if (bIsWeak) return NativeAtomic.compare_exchange_weak(Expected, Desired, static_cast<NAMESPACE_STD::memory_order>(Success), static_cast<NAMESPACE_STD::memory_order>(Failure));
else return Element.compare_exchange_strong(Expected, Desired, static_cast<NAMESPACE_STD::memory_order>(Success), static_cast<NAMESPACE_STD::memory_order>(Failure)); else return NativeAtomic.compare_exchange_strong(Expected, Desired, static_cast<NAMESPACE_STD::memory_order>(Success), static_cast<NAMESPACE_STD::memory_order>(Failure));
} }
FORCEINLINE bool CompareExchange(ValueType& Expected, ValueType Desired, EMemoryOrder Order = EMemoryOrder::SequentiallyConsistent, bool bIsWeak = false) 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<NAMESPACE_STD::memory_order>(Order)); if (bIsWeak) return NativeAtomic.compare_exchange_weak(Expected, Desired, static_cast<NAMESPACE_STD::memory_order>(Order));
else return Element.compare_exchange_strong(Expected, Desired, static_cast<NAMESPACE_STD::memory_order>(Order)); else return NativeAtomic.compare_exchange_strong(Expected, Desired, static_cast<NAMESPACE_STD::memory_order>(Order));
} }
FORCEINLINE bool CompareExchange(ValueType& Expected, ValueType Desired, EMemoryOrder Order = EMemoryOrder::SequentiallyConsistent, bool bIsWeak = false) volatile requires (bIsAlwaysLockFree) 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<NAMESPACE_STD::memory_order>(Order)); if (bIsWeak) return NativeAtomic.compare_exchange_weak(Expected, Desired, static_cast<NAMESPACE_STD::memory_order>(Order));
else return Element.compare_exchange_strong(Expected, Desired, static_cast<NAMESPACE_STD::memory_order>(Order)); else return NativeAtomic.compare_exchange_strong(Expected, Desired, static_cast<NAMESPACE_STD::memory_order>(Order));
} }
FORCEINLINE void Wait(ValueType Old, EMemoryOrder Order = EMemoryOrder::SequentiallyConsistent) { MEMORY_ORDER_CHECK(Order, 0x01 | 0x02 | 0x04 | 0x20); Element.wait(Old, static_cast<NAMESPACE_STD::memory_order>(Order)); } FORCEINLINE void Wait(ValueType Old, EMemoryOrder Order = EMemoryOrder::SequentiallyConsistent) { MEMORY_ORDER_CHECK(Order, 0x01 | 0x02 | 0x04 | 0x20); NativeAtomic.wait(Old, static_cast<NAMESPACE_STD::memory_order>(Order)); }
FORCEINLINE void Wait(ValueType Old, EMemoryOrder Order = EMemoryOrder::SequentiallyConsistent) volatile { MEMORY_ORDER_CHECK(Order, 0x01 | 0x02 | 0x04 | 0x20); Element.wait(Old, static_cast<NAMESPACE_STD::memory_order>(Order)); } FORCEINLINE void Wait(ValueType Old, EMemoryOrder Order = EMemoryOrder::SequentiallyConsistent) volatile { MEMORY_ORDER_CHECK(Order, 0x01 | 0x02 | 0x04 | 0x20); NativeAtomic.wait(Old, static_cast<NAMESPACE_STD::memory_order>(Order)); }
FORCEINLINE void Notify(bool bIsAll = false) { if (bIsAll) Element.notify_all(); else Element.notify_one(); } FORCEINLINE void Notify(bool bIsAll = false) { if (bIsAll) NativeAtomic.notify_all(); else NativeAtomic.notify_one(); }
FORCEINLINE void Notify(bool bIsAll = false) volatile { if (bIsAll) Element.notify_all(); else Element.notify_one(); } FORCEINLINE void Notify(bool bIsAll = false) volatile { if (bIsAll) NativeAtomic.notify_all(); else NativeAtomic.notify_one(); }
template <typename F> requires (CInvocableResult<ValueType, F, ValueType>) template <typename F> requires (CInvocableResult<ValueType, F, ValueType>)
FORCEINLINE ValueType FetchFn(F&& Func, EMemoryOrder Order = EMemoryOrder::SequentiallyConsistent) FORCEINLINE ValueType FetchFn(F&& Func, EMemoryOrder Order = EMemoryOrder::SequentiallyConsistent)
@ -137,17 +137,17 @@ public:
return Temp; return Temp;
} }
FORCEINLINE ValueType FetchAdd(ValueType InValue, EMemoryOrder Order = EMemoryOrder::SequentiallyConsistent) requires (CIntegral<T> || CFloatingPoint<T>) { return Element.fetch_add(InValue, static_cast<NAMESPACE_STD::memory_order>(Order)); } FORCEINLINE ValueType FetchAdd(ValueType InValue, EMemoryOrder Order = EMemoryOrder::SequentiallyConsistent) requires (CIntegral<T> || CFloatingPoint<T>) { return NativeAtomic.fetch_add(InValue, static_cast<NAMESPACE_STD::memory_order>(Order)); }
FORCEINLINE ValueType FetchAdd(ValueType InValue, EMemoryOrder Order = EMemoryOrder::SequentiallyConsistent) volatile requires (CIntegral<T> || CFloatingPoint<T>) && bIsAlwaysLockFree { return Element.fetch_add(InValue, static_cast<NAMESPACE_STD::memory_order>(Order)); } FORCEINLINE ValueType FetchAdd(ValueType InValue, EMemoryOrder Order = EMemoryOrder::SequentiallyConsistent) volatile requires (CIntegral<T> || CFloatingPoint<T>) && bIsAlwaysLockFree { return NativeAtomic.fetch_add(InValue, static_cast<NAMESPACE_STD::memory_order>(Order)); }
FORCEINLINE ValueType FetchAdd(ptrdiff InValue, EMemoryOrder Order = EMemoryOrder::SequentiallyConsistent) requires (CPointer<T> ) { return Element.fetch_add(InValue, static_cast<NAMESPACE_STD::memory_order>(Order)); } FORCEINLINE ValueType FetchAdd(ptrdiff InValue, EMemoryOrder Order = EMemoryOrder::SequentiallyConsistent) requires (CPointer<T> ) { return NativeAtomic.fetch_add(InValue, static_cast<NAMESPACE_STD::memory_order>(Order)); }
FORCEINLINE ValueType FetchAdd(ptrdiff InValue, EMemoryOrder Order = EMemoryOrder::SequentiallyConsistent) volatile requires (CPointer<T> && bIsAlwaysLockFree) { return Element.fetch_add(InValue, static_cast<NAMESPACE_STD::memory_order>(Order)); } FORCEINLINE ValueType FetchAdd(ptrdiff InValue, EMemoryOrder Order = EMemoryOrder::SequentiallyConsistent) volatile requires (CPointer<T> && bIsAlwaysLockFree) { return NativeAtomic.fetch_add(InValue, static_cast<NAMESPACE_STD::memory_order>(Order)); }
FORCEINLINE ValueType FetchSub(ValueType InValue, EMemoryOrder Order = EMemoryOrder::SequentiallyConsistent) requires (CIntegral<T> || CFloatingPoint<T>) { return Element.fetch_sub(InValue, static_cast<NAMESPACE_STD::memory_order>(Order)); } FORCEINLINE ValueType FetchSub(ValueType InValue, EMemoryOrder Order = EMemoryOrder::SequentiallyConsistent) requires (CIntegral<T> || CFloatingPoint<T>) { return NativeAtomic.fetch_sub(InValue, static_cast<NAMESPACE_STD::memory_order>(Order)); }
FORCEINLINE ValueType FetchSub(ValueType InValue, EMemoryOrder Order = EMemoryOrder::SequentiallyConsistent) volatile requires (CIntegral<T> || CFloatingPoint<T>) && bIsAlwaysLockFree { return Element.fetch_sub(InValue, static_cast<NAMESPACE_STD::memory_order>(Order)); } FORCEINLINE ValueType FetchSub(ValueType InValue, EMemoryOrder Order = EMemoryOrder::SequentiallyConsistent) volatile requires (CIntegral<T> || CFloatingPoint<T>) && bIsAlwaysLockFree { return NativeAtomic.fetch_sub(InValue, static_cast<NAMESPACE_STD::memory_order>(Order)); }
FORCEINLINE ValueType FetchSub(ptrdiff InValue, EMemoryOrder Order = EMemoryOrder::SequentiallyConsistent) requires (CPointer<T> ) { return Element.fetch_sub(InValue, static_cast<NAMESPACE_STD::memory_order>(Order)); } FORCEINLINE ValueType FetchSub(ptrdiff InValue, EMemoryOrder Order = EMemoryOrder::SequentiallyConsistent) requires (CPointer<T> ) { return NativeAtomic.fetch_sub(InValue, static_cast<NAMESPACE_STD::memory_order>(Order)); }
FORCEINLINE ValueType FetchSub(ptrdiff InValue, EMemoryOrder Order = EMemoryOrder::SequentiallyConsistent) volatile requires (CPointer<T> && bIsAlwaysLockFree) { return Element.fetch_sub(InValue, static_cast<NAMESPACE_STD::memory_order>(Order)); } FORCEINLINE ValueType FetchSub(ptrdiff InValue, EMemoryOrder Order = EMemoryOrder::SequentiallyConsistent) volatile requires (CPointer<T> && bIsAlwaysLockFree) { return NativeAtomic.fetch_sub(InValue, static_cast<NAMESPACE_STD::memory_order>(Order)); }
FORCEINLINE ValueType FetchMul(ValueType InValue, EMemoryOrder Order = EMemoryOrder::SequentiallyConsistent) requires (CIntegral<T> || CFloatingPoint<T>) { return FetchFn([InValue](ValueType Old) -> ValueType { return Old * InValue; }); } FORCEINLINE ValueType FetchMul(ValueType InValue, EMemoryOrder Order = EMemoryOrder::SequentiallyConsistent) requires (CIntegral<T> || CFloatingPoint<T>) { return FetchFn([InValue](ValueType Old) -> ValueType { return Old * InValue; }); }
FORCEINLINE ValueType FetchMul(ValueType InValue, EMemoryOrder Order = EMemoryOrder::SequentiallyConsistent) volatile requires (CIntegral<T> || CFloatingPoint<T>) && bIsAlwaysLockFree { return FetchFn([InValue](ValueType Old) -> ValueType { return Old * InValue; }); } FORCEINLINE ValueType FetchMul(ValueType InValue, EMemoryOrder Order = EMemoryOrder::SequentiallyConsistent) volatile requires (CIntegral<T> || CFloatingPoint<T>) && bIsAlwaysLockFree { return FetchFn([InValue](ValueType Old) -> ValueType { return Old * InValue; }); }
@ -158,14 +158,14 @@ public:
FORCEINLINE ValueType FetchMod(ValueType InValue, EMemoryOrder Order = EMemoryOrder::SequentiallyConsistent) requires (CIntegral<T> ) { return FetchFn([InValue](ValueType Old) -> ValueType { return Old % InValue; }); } FORCEINLINE ValueType FetchMod(ValueType InValue, EMemoryOrder Order = EMemoryOrder::SequentiallyConsistent) requires (CIntegral<T> ) { return FetchFn([InValue](ValueType Old) -> ValueType { return Old % InValue; }); }
FORCEINLINE ValueType FetchMod(ValueType InValue, EMemoryOrder Order = EMemoryOrder::SequentiallyConsistent) volatile requires (CIntegral<T> && bIsAlwaysLockFree) { return FetchFn([InValue](ValueType Old) -> ValueType { return Old % InValue; }); } FORCEINLINE ValueType FetchMod(ValueType InValue, EMemoryOrder Order = EMemoryOrder::SequentiallyConsistent) volatile requires (CIntegral<T> && bIsAlwaysLockFree) { return FetchFn([InValue](ValueType Old) -> ValueType { return Old % InValue; }); }
FORCEINLINE ValueType FetchAnd(ValueType InValue, EMemoryOrder Order = EMemoryOrder::SequentiallyConsistent) requires (CIntegral<T> ) { return Element.fetch_and(InValue, static_cast<NAMESPACE_STD::memory_order>(Order)); } FORCEINLINE ValueType FetchAnd(ValueType InValue, EMemoryOrder Order = EMemoryOrder::SequentiallyConsistent) requires (CIntegral<T> ) { return NativeAtomic.fetch_and(InValue, static_cast<NAMESPACE_STD::memory_order>(Order)); }
FORCEINLINE ValueType FetchAnd(ValueType InValue, EMemoryOrder Order = EMemoryOrder::SequentiallyConsistent) volatile requires (CIntegral<T> && bIsAlwaysLockFree) { return Element.fetch_and(InValue, static_cast<NAMESPACE_STD::memory_order>(Order)); } FORCEINLINE ValueType FetchAnd(ValueType InValue, EMemoryOrder Order = EMemoryOrder::SequentiallyConsistent) volatile requires (CIntegral<T> && bIsAlwaysLockFree) { return NativeAtomic.fetch_and(InValue, static_cast<NAMESPACE_STD::memory_order>(Order)); }
FORCEINLINE ValueType FetchOr(ValueType InValue, EMemoryOrder Order = EMemoryOrder::SequentiallyConsistent) requires (CIntegral<T> ) { return Element.fetch_or(InValue, static_cast<NAMESPACE_STD::memory_order>(Order)); } FORCEINLINE ValueType FetchOr(ValueType InValue, EMemoryOrder Order = EMemoryOrder::SequentiallyConsistent) requires (CIntegral<T> ) { return NativeAtomic.fetch_or(InValue, static_cast<NAMESPACE_STD::memory_order>(Order)); }
FORCEINLINE ValueType FetchOr(ValueType InValue, EMemoryOrder Order = EMemoryOrder::SequentiallyConsistent) volatile requires (CIntegral<T> && bIsAlwaysLockFree) { return Element.fetch_or(InValue, static_cast<NAMESPACE_STD::memory_order>(Order)); } FORCEINLINE ValueType FetchOr(ValueType InValue, EMemoryOrder Order = EMemoryOrder::SequentiallyConsistent) volatile requires (CIntegral<T> && bIsAlwaysLockFree) { return NativeAtomic.fetch_or(InValue, static_cast<NAMESPACE_STD::memory_order>(Order)); }
FORCEINLINE ValueType FetchXor(ValueType InValue, EMemoryOrder Order = EMemoryOrder::SequentiallyConsistent) requires (CIntegral<T> ) { return Element.fetch_xor(InValue, static_cast<NAMESPACE_STD::memory_order>(Order)); } FORCEINLINE ValueType FetchXor(ValueType InValue, EMemoryOrder Order = EMemoryOrder::SequentiallyConsistent) requires (CIntegral<T> ) { return NativeAtomic.fetch_xor(InValue, static_cast<NAMESPACE_STD::memory_order>(Order)); }
FORCEINLINE ValueType FetchXor(ValueType InValue, EMemoryOrder Order = EMemoryOrder::SequentiallyConsistent) volatile requires (CIntegral<T> && bIsAlwaysLockFree) { return Element.fetch_xor(InValue, static_cast<NAMESPACE_STD::memory_order>(Order)); } FORCEINLINE ValueType FetchXor(ValueType InValue, EMemoryOrder Order = EMemoryOrder::SequentiallyConsistent) volatile requires (CIntegral<T> && bIsAlwaysLockFree) { return NativeAtomic.fetch_xor(InValue, static_cast<NAMESPACE_STD::memory_order>(Order)); }
FORCEINLINE ValueType FetchLsh(size_t InValue, EMemoryOrder Order = EMemoryOrder::SequentiallyConsistent) requires (CIntegral<T> ) { return FetchFn([InValue](ValueType Old) -> ValueType { return Old << InValue; }); } FORCEINLINE ValueType FetchLsh(size_t InValue, EMemoryOrder Order = EMemoryOrder::SequentiallyConsistent) requires (CIntegral<T> ) { return FetchFn([InValue](ValueType Old) -> ValueType { return Old << InValue; }); }
FORCEINLINE ValueType FetchLsh(size_t InValue, EMemoryOrder Order = EMemoryOrder::SequentiallyConsistent) volatile requires (CIntegral<T> && bIsAlwaysLockFree) { return FetchFn([InValue](ValueType Old) -> ValueType { return Old << InValue; }); } FORCEINLINE ValueType FetchLsh(size_t InValue, EMemoryOrder Order = EMemoryOrder::SequentiallyConsistent) volatile requires (CIntegral<T> && bIsAlwaysLockFree) { return FetchFn([InValue](ValueType Old) -> ValueType { return Old << InValue; }); }
@ -173,29 +173,29 @@ public:
FORCEINLINE ValueType FetchRsh(size_t InValue, EMemoryOrder Order = EMemoryOrder::SequentiallyConsistent) requires (CIntegral<T> ) { return FetchFn([InValue](ValueType Old) -> ValueType { return Old >> InValue; }); } FORCEINLINE ValueType FetchRsh(size_t InValue, EMemoryOrder Order = EMemoryOrder::SequentiallyConsistent) requires (CIntegral<T> ) { return FetchFn([InValue](ValueType Old) -> ValueType { return Old >> InValue; }); }
FORCEINLINE ValueType FetchRsh(size_t InValue, EMemoryOrder Order = EMemoryOrder::SequentiallyConsistent) volatile requires (CIntegral<T> && bIsAlwaysLockFree) { return FetchFn([InValue](ValueType Old) -> ValueType { return Old >> InValue; }); } FORCEINLINE ValueType FetchRsh(size_t InValue, EMemoryOrder Order = EMemoryOrder::SequentiallyConsistent) volatile requires (CIntegral<T> && bIsAlwaysLockFree) { return FetchFn([InValue](ValueType Old) -> ValueType { return Old >> InValue; }); }
FORCEINLINE ValueType operator++() requires ((CIntegral<T> || CPointer<T>) ) { return ++Element; } FORCEINLINE ValueType operator++() requires ((CIntegral<T> || CPointer<T>) ) { return ++NativeAtomic; }
FORCEINLINE ValueType operator++() volatile requires ((CIntegral<T> || CPointer<T>) && bIsAlwaysLockFree) { return ++Element; } FORCEINLINE ValueType operator++() volatile requires ((CIntegral<T> || CPointer<T>) && bIsAlwaysLockFree) { return ++NativeAtomic; }
FORCEINLINE ValueType operator++(int) requires ((CIntegral<T> || CPointer<T>) ) { return Element++; } FORCEINLINE ValueType operator++(int) requires ((CIntegral<T> || CPointer<T>) ) { return NativeAtomic++; }
FORCEINLINE ValueType operator++(int) volatile requires ((CIntegral<T> || CPointer<T>) && bIsAlwaysLockFree) { return Element++; } FORCEINLINE ValueType operator++(int) volatile requires ((CIntegral<T> || CPointer<T>) && bIsAlwaysLockFree) { return NativeAtomic++; }
FORCEINLINE ValueType operator--() requires ((CIntegral<T> || CPointer<T>) ) { return --Element; } FORCEINLINE ValueType operator--() requires ((CIntegral<T> || CPointer<T>) ) { return --NativeAtomic; }
FORCEINLINE ValueType operator--() volatile requires ((CIntegral<T> || CPointer<T>) && bIsAlwaysLockFree) { return --Element; } FORCEINLINE ValueType operator--() volatile requires ((CIntegral<T> || CPointer<T>) && bIsAlwaysLockFree) { return --NativeAtomic; }
FORCEINLINE ValueType operator--(int) requires ((CIntegral<T> || CPointer<T>) ) { return Element--; } FORCEINLINE ValueType operator--(int) requires ((CIntegral<T> || CPointer<T>) ) { return NativeAtomic--; }
FORCEINLINE ValueType operator--(int) volatile requires ((CIntegral<T> || CPointer<T>) && bIsAlwaysLockFree) { return Element--; } FORCEINLINE ValueType operator--(int) volatile requires ((CIntegral<T> || CPointer<T>) && bIsAlwaysLockFree) { return NativeAtomic--; }
FORCEINLINE ValueType operator+=(ValueType InValue) requires ((CIntegral<T> || CFloatingPoint<T>) ) { return Element += InValue; } FORCEINLINE ValueType operator+=(ValueType InValue) requires ((CIntegral<T> || CFloatingPoint<T>) ) { return NativeAtomic += InValue; }
FORCEINLINE ValueType operator+=(ValueType InValue) volatile requires ((CIntegral<T> || CFloatingPoint<T>) && bIsAlwaysLockFree) { return Element += InValue; } FORCEINLINE ValueType operator+=(ValueType InValue) volatile requires ((CIntegral<T> || CFloatingPoint<T>) && bIsAlwaysLockFree) { return NativeAtomic += InValue; }
FORCEINLINE ValueType operator+=(ptrdiff InValue) requires (CPointer<T> ) { return Element += InValue; } FORCEINLINE ValueType operator+=(ptrdiff InValue) requires (CPointer<T> ) { return NativeAtomic += InValue; }
FORCEINLINE ValueType operator+=(ptrdiff InValue) volatile requires (CPointer<T> && bIsAlwaysLockFree) { return Element += InValue; } FORCEINLINE ValueType operator+=(ptrdiff InValue) volatile requires (CPointer<T> && bIsAlwaysLockFree) { return NativeAtomic += InValue; }
FORCEINLINE ValueType operator-=(ValueType InValue) requires ((CIntegral<T> || CFloatingPoint<T>) ) { return Element -= InValue; } FORCEINLINE ValueType operator-=(ValueType InValue) requires ((CIntegral<T> || CFloatingPoint<T>) ) { return NativeAtomic -= InValue; }
FORCEINLINE ValueType operator-=(ValueType InValue) volatile requires ((CIntegral<T> || CFloatingPoint<T>) && bIsAlwaysLockFree) { return Element -= InValue; } FORCEINLINE ValueType operator-=(ValueType InValue) volatile requires ((CIntegral<T> || CFloatingPoint<T>) && bIsAlwaysLockFree) { return NativeAtomic -= InValue; }
FORCEINLINE ValueType operator-=(ptrdiff InValue) requires (CPointer<T> ) { return Element -= InValue; } FORCEINLINE ValueType operator-=(ptrdiff InValue) requires (CPointer<T> ) { return NativeAtomic -= InValue; }
FORCEINLINE ValueType operator-=(ptrdiff InValue) volatile requires (CPointer<T> && bIsAlwaysLockFree) { return Element -= InValue; } FORCEINLINE ValueType operator-=(ptrdiff InValue) volatile requires (CPointer<T> && bIsAlwaysLockFree) { return NativeAtomic -= InValue; }
FORCEINLINE ValueType operator*=(ValueType InValue) requires ((CIntegral<T> || CFloatingPoint<T>) ) { return FetchMul(InValue) * InValue; } FORCEINLINE ValueType operator*=(ValueType InValue) requires ((CIntegral<T> || CFloatingPoint<T>) ) { return FetchMul(InValue) * InValue; }
FORCEINLINE ValueType operator*=(ValueType InValue) volatile requires ((CIntegral<T> || CFloatingPoint<T>) && bIsAlwaysLockFree) { return FetchMul(InValue) * InValue; } FORCEINLINE ValueType operator*=(ValueType InValue) volatile requires ((CIntegral<T> || CFloatingPoint<T>) && bIsAlwaysLockFree) { return FetchMul(InValue) * InValue; }
@ -206,14 +206,14 @@ public:
FORCEINLINE ValueType operator%=(ValueType InValue) requires (CIntegral<T> ) { return FetchMod(InValue) % InValue; } FORCEINLINE ValueType operator%=(ValueType InValue) requires (CIntegral<T> ) { return FetchMod(InValue) % InValue; }
FORCEINLINE ValueType operator%=(ValueType InValue) volatile requires (CIntegral<T> && bIsAlwaysLockFree) { return FetchMod(InValue) % InValue; } FORCEINLINE ValueType operator%=(ValueType InValue) volatile requires (CIntegral<T> && bIsAlwaysLockFree) { return FetchMod(InValue) % InValue; }
FORCEINLINE ValueType operator&=(ValueType InValue) requires (CIntegral<T> ) { return Element &= InValue; } FORCEINLINE ValueType operator&=(ValueType InValue) requires (CIntegral<T> ) { return NativeAtomic &= InValue; }
FORCEINLINE ValueType operator&=(ValueType InValue) volatile requires (CIntegral<T> && bIsAlwaysLockFree) { return Element &= InValue; } FORCEINLINE ValueType operator&=(ValueType InValue) volatile requires (CIntegral<T> && bIsAlwaysLockFree) { return NativeAtomic &= InValue; }
FORCEINLINE ValueType operator|=(ValueType InValue) requires (CIntegral<T> ) { return Element |= InValue; } FORCEINLINE ValueType operator|=(ValueType InValue) requires (CIntegral<T> ) { return NativeAtomic |= InValue; }
FORCEINLINE ValueType operator|=(ValueType InValue) volatile requires (CIntegral<T> && bIsAlwaysLockFree) { return Element |= InValue; } FORCEINLINE ValueType operator|=(ValueType InValue) volatile requires (CIntegral<T> && bIsAlwaysLockFree) { return NativeAtomic |= InValue; }
FORCEINLINE ValueType operator^=(ValueType InValue) requires (CIntegral<T> ) { return Element ^= InValue; } FORCEINLINE ValueType operator^=(ValueType InValue) requires (CIntegral<T> ) { return NativeAtomic ^= InValue; }
FORCEINLINE ValueType operator^=(ValueType InValue) volatile requires (CIntegral<T> && bIsAlwaysLockFree) { return Element ^= InValue; } FORCEINLINE ValueType operator^=(ValueType InValue) volatile requires (CIntegral<T> && bIsAlwaysLockFree) { return NativeAtomic ^= InValue; }
FORCEINLINE ValueType operator<<=(size_t InValue) requires (CIntegral<T> ) { return FetchLsh(InValue) << InValue; } FORCEINLINE ValueType operator<<=(size_t InValue) requires (CIntegral<T> ) { return FetchLsh(InValue) << InValue; }
FORCEINLINE ValueType operator<<=(size_t InValue) volatile requires (CIntegral<T> && bIsAlwaysLockFree) { return FetchLsh(InValue) << InValue; } FORCEINLINE ValueType operator<<=(size_t InValue) volatile requires (CIntegral<T> && bIsAlwaysLockFree) { return FetchLsh(InValue) << InValue; }
@ -223,40 +223,50 @@ public:
protected: protected:
ElementType Element; NativeAtomicType NativeAtomic;
}; };
NAMESPACE_PRIVATE_END
template <typename T> template <typename T>
using TAtomicRef = TAtomic<T, true>; struct TAtomic : STRONG_INHERIT(NAMESPACE_PRIVATE::TAtomicImpl<T, false>);
template <typename T>
struct TAtomicRef : STRONG_INHERIT(NAMESPACE_PRIVATE::TAtomicImpl<T, true>);
template <typename T> template <typename T>
TAtomic(T) -> TAtomic<T>; TAtomic(T) -> TAtomic<T>;
template <typename T>
TAtomicRef(T&) -> TAtomicRef<T>;
static_assert(sizeof(TAtomic<int32>) == sizeof(int32), "The byte size of TAtomic is unexpected");
struct FAtomicFlag : FSingleton struct FAtomicFlag : FSingleton
{ {
public: public:
constexpr FAtomicFlag() : Element() { }; constexpr FAtomicFlag() : NativeAtomic() { };
FORCEINLINE void Clear(EMemoryOrder Order = EMemoryOrder::SequentiallyConsistent) { MEMORY_ORDER_CHECK(Order, 0x01 | 0x08 | 0x20); Element.clear(static_cast<NAMESPACE_STD::memory_order>(Order)); } FORCEINLINE void Clear(EMemoryOrder Order = EMemoryOrder::SequentiallyConsistent) { MEMORY_ORDER_CHECK(Order, 0x01 | 0x08 | 0x20); NativeAtomic.clear(static_cast<NAMESPACE_STD::memory_order>(Order)); }
FORCEINLINE void Clear(EMemoryOrder Order = EMemoryOrder::SequentiallyConsistent) volatile { MEMORY_ORDER_CHECK(Order, 0x01 | 0x08 | 0x20); Element.clear(static_cast<NAMESPACE_STD::memory_order>(Order)); } FORCEINLINE void Clear(EMemoryOrder Order = EMemoryOrder::SequentiallyConsistent) volatile { MEMORY_ORDER_CHECK(Order, 0x01 | 0x08 | 0x20); NativeAtomic.clear(static_cast<NAMESPACE_STD::memory_order>(Order)); }
FORCEINLINE bool TestAndSet(EMemoryOrder Order = EMemoryOrder::SequentiallyConsistent) { return Element.test_and_set(static_cast<NAMESPACE_STD::memory_order>(Order)); } FORCEINLINE bool TestAndSet(EMemoryOrder Order = EMemoryOrder::SequentiallyConsistent) { return NativeAtomic.test_and_set(static_cast<NAMESPACE_STD::memory_order>(Order)); }
FORCEINLINE bool TestAndSet(EMemoryOrder Order = EMemoryOrder::SequentiallyConsistent) volatile { return Element.test_and_set(static_cast<NAMESPACE_STD::memory_order>(Order)); } FORCEINLINE bool TestAndSet(EMemoryOrder Order = EMemoryOrder::SequentiallyConsistent) volatile { return NativeAtomic.test_and_set(static_cast<NAMESPACE_STD::memory_order>(Order)); }
FORCEINLINE bool Test(EMemoryOrder Order = EMemoryOrder::SequentiallyConsistent) const { MEMORY_ORDER_CHECK(Order, 0x01 | 0x02 | 0x04 | 0x20); return Element.test(static_cast<NAMESPACE_STD::memory_order>(Order)); } FORCEINLINE bool Test(EMemoryOrder Order = EMemoryOrder::SequentiallyConsistent) const { MEMORY_ORDER_CHECK(Order, 0x01 | 0x02 | 0x04 | 0x20); return NativeAtomic.test(static_cast<NAMESPACE_STD::memory_order>(Order)); }
FORCEINLINE bool Test(EMemoryOrder Order = EMemoryOrder::SequentiallyConsistent) const volatile { MEMORY_ORDER_CHECK(Order, 0x01 | 0x02 | 0x04 | 0x20); return Element.test(static_cast<NAMESPACE_STD::memory_order>(Order)); } FORCEINLINE bool Test(EMemoryOrder Order = EMemoryOrder::SequentiallyConsistent) const volatile { MEMORY_ORDER_CHECK(Order, 0x01 | 0x02 | 0x04 | 0x20); return NativeAtomic.test(static_cast<NAMESPACE_STD::memory_order>(Order)); }
FORCEINLINE void Wait(bool Old, EMemoryOrder Order = EMemoryOrder::SequentiallyConsistent) const { MEMORY_ORDER_CHECK(Order, 0x01 | 0x02 | 0x04 | 0x20); const_cast<const NAMESPACE_STD::atomic_flag&>(Element).wait(Old, static_cast<NAMESPACE_STD::memory_order>(Order)); } FORCEINLINE void Wait(bool Old, EMemoryOrder Order = EMemoryOrder::SequentiallyConsistent) const { MEMORY_ORDER_CHECK(Order, 0x01 | 0x02 | 0x04 | 0x20); const_cast<const NAMESPACE_STD::atomic_flag&>(NativeAtomic).wait(Old, static_cast<NAMESPACE_STD::memory_order>(Order)); }
FORCEINLINE void Wait(bool Old, EMemoryOrder Order = EMemoryOrder::SequentiallyConsistent) const volatile { MEMORY_ORDER_CHECK(Order, 0x01 | 0x02 | 0x04 | 0x20); const_cast<const NAMESPACE_STD::atomic_flag&>(Element).wait(Old, static_cast<NAMESPACE_STD::memory_order>(Order)); } FORCEINLINE void Wait(bool Old, EMemoryOrder Order = EMemoryOrder::SequentiallyConsistent) const volatile { MEMORY_ORDER_CHECK(Order, 0x01 | 0x02 | 0x04 | 0x20); const_cast<const NAMESPACE_STD::atomic_flag&>(NativeAtomic).wait(Old, static_cast<NAMESPACE_STD::memory_order>(Order)); }
FORCEINLINE void Notify(bool bIsAll = false) { if (bIsAll) const_cast<NAMESPACE_STD::atomic_flag&>(Element).notify_all(); else const_cast<NAMESPACE_STD::atomic_flag&>(Element).notify_one(); } FORCEINLINE void Notify(bool bIsAll = false) { if (bIsAll) const_cast<NAMESPACE_STD::atomic_flag&>(NativeAtomic).notify_all(); else const_cast<NAMESPACE_STD::atomic_flag&>(NativeAtomic).notify_one(); }
FORCEINLINE void Notify(bool bIsAll = false) volatile { if (bIsAll) const_cast<NAMESPACE_STD::atomic_flag&>(Element).notify_all(); else const_cast<NAMESPACE_STD::atomic_flag&>(Element).notify_one(); } FORCEINLINE void Notify(bool bIsAll = false) volatile { if (bIsAll) const_cast<NAMESPACE_STD::atomic_flag&>(NativeAtomic).notify_all(); else const_cast<NAMESPACE_STD::atomic_flag&>(NativeAtomic).notify_one(); }
protected: private:
NAMESPACE_STD::atomic_flag Element; NAMESPACE_STD::atomic_flag NativeAtomic;
}; };

View File

@ -48,7 +48,7 @@ public:
} }
template <typename T = OptionalType> requires (CConstructibleFrom<OptionalType, T&&>) template <typename T = OptionalType> requires (CConstructibleFrom<OptionalType, T&&>)
&& (!CSameAs<TRemoveCVRef<T>, FInPlace>) && (!CSameAs<TRemoveCVRef<T>, TOptional>) && (!CSameAs<TRemoveCVRef<T>, FInPlace>) && (!CBaseOf<TOptional, TRemoveCVRef<T>>)
constexpr explicit (!CConvertibleTo<T&&, OptionalType>) TOptional(T&& InValue) constexpr explicit (!CConvertibleTo<T&&, OptionalType>) TOptional(T&& InValue)
: TOptional(InPlace, Forward<T>(InValue)) : TOptional(InPlace, Forward<T>(InValue))
{ } { }

View File

@ -161,7 +161,7 @@ public:
{ } { }
template <typename T = OptionalType> requires (CConstructibleFrom<OptionalType, T&&> template <typename T = OptionalType> requires (CConstructibleFrom<OptionalType, T&&>
&& !CSameAs<TRemoveCVRef<T>, FInPlace> && !CSameAs<TRemoveCVRef<T>, TOptional>) && !CSameAs<TRemoveCVRef<T>, FInPlace> && !CBaseOf<TOptional, TRemoveCVRef<T>>)
constexpr explicit (!CConvertibleTo<T&&, OptionalType>) TOptional(T&& InValue) constexpr explicit (!CConvertibleTo<T&&, OptionalType>) TOptional(T&& InValue)
: TOptional(InPlace, Forward<T>(InValue)) : TOptional(InPlace, Forward<T>(InValue))
{ } { }

View File

@ -597,7 +597,7 @@ template <typename... LHSTypes, typename... RHSTypes> requires (sizeof...(LHSTyp
constexpr bool operator==(const TTuple<LHSTypes...>& LHS, const TTuple<RHSTypes...>& RHS) constexpr bool operator==(const TTuple<LHSTypes...>& LHS, const TTuple<RHSTypes...>& RHS)
{ {
if constexpr (sizeof...(LHSTypes) != sizeof...(RHSTypes)) return false; if constexpr (sizeof...(LHSTypes) != sizeof...(RHSTypes)) return false;
return[&LHS, &RHS]<size_t... Indices>(TIndexSequence<Indices...>) -> bool { return (true && ... && (LHS.template GetValue<Indices>() == RHS.template GetValue<Indices>())); } (TMakeIndexSequence<sizeof...(LHSTypes)>()); return [&LHS, &RHS]<size_t... Indices>(TIndexSequence<Indices...>) -> bool { return (true && ... && (LHS.template GetValue<Indices>() == RHS.template GetValue<Indices>())); } (TMakeIndexSequence<sizeof...(LHSTypes)>());
} }
template <typename... LHSTypes, typename... RHSTypes> requires (sizeof...(LHSTypes) == sizeof...(RHSTypes) && (true && ... && (CSynthThreeWayComparable<LHSTypes, RHSTypes>))) template <typename... LHSTypes, typename... RHSTypes> requires (sizeof...(LHSTypes) == sizeof...(RHSTypes) && (true && ... && (CSynthThreeWayComparable<LHSTypes, RHSTypes>)))

View File

@ -102,6 +102,21 @@ struct FIgnore
inline constexpr FIgnore Ignore; inline constexpr FIgnore Ignore;
// This macro is used in place of using type aliases, see Atomic.h, etc
#define STRONG_INHERIT(...) /* BaseClass */ \
/* struct DerivedClass : */ public __VA_ARGS__ \
{ \
private: \
\
using BaseClassTypedef = __VA_ARGS__; \
\
public: \
\
using BaseClassTypedef::BaseClassTypedef; \
using BaseClassTypedef::operator=; \
\
}
NAMESPACE_MODULE_END(Utility) NAMESPACE_MODULE_END(Utility)
NAMESPACE_MODULE_END(Redcraft) NAMESPACE_MODULE_END(Redcraft)
NAMESPACE_REDCRAFT_END NAMESPACE_REDCRAFT_END

View File

@ -189,7 +189,7 @@ public:
template <typename T> requires (NAMESPACE_PRIVATE::TVariantSelectedType<TRemoveReference<T>, Ts...>::Value template <typename T> requires (NAMESPACE_PRIVATE::TVariantSelectedType<TRemoveReference<T>, Ts...>::Value
&& !CTInPlaceType<TRemoveCVRef<T>> && !CTInPlaceIndex<TRemoveCVRef<T>> && !CTInPlaceType<TRemoveCVRef<T>> && !CTInPlaceIndex<TRemoveCVRef<T>>
&& !CSameAs<TRemoveCVRef<T>, TVariant>) && !CBaseOf<TVariant, TRemoveCVRef<T>>)
constexpr TVariant(T&& InValue) : TVariant(InPlaceType<typename NAMESPACE_PRIVATE::TVariantSelectedType<TRemoveReference<T>, Ts...>::Type>, Forward<T>(InValue)) constexpr TVariant(T&& InValue) : TVariant(InPlaceType<typename NAMESPACE_PRIVATE::TVariantSelectedType<TRemoveReference<T>, Ts...>::Type>, Forward<T>(InValue))
{ } { }
@ -289,7 +289,7 @@ public:
constexpr bool IsValid() const { return TypeIndex != 0xFF; } constexpr bool IsValid() const { return TypeIndex != 0xFF; }
constexpr explicit operator bool() const { return TypeIndex != 0xFF; } constexpr explicit operator bool() const { return TypeIndex != 0xFF; }
template <size_t I> constexpr bool HoldsAlternative() const { return IsValid() ? GetIndex() == I : false; } template <size_t I> constexpr bool HoldsAlternative() const { return IsValid() ? GetIndex() == I : false; }
template <typename T> constexpr bool HoldsAlternative() const { return IsValid() ? GetIndex() == TVariantIndex<T, TVariant<Ts...>> : false; } template <typename T> constexpr bool HoldsAlternative() const { return IsValid() ? GetIndex() == TVariantIndex<T, TVariant<Ts...>> : false; }
template <size_t I> requires (I < sizeof...(Ts)) constexpr decltype(auto) GetValue() & { checkf(HoldsAlternative<I>(), TEXT("It is an error to call GetValue() on an wrong TVariant. Please either check HoldsAlternative() or use Get(DefaultValue) instead.")); return *reinterpret_cast< TVariantAlternative<I, TVariant<Ts...>>*>(&Value); } template <size_t I> requires (I < sizeof...(Ts)) constexpr decltype(auto) GetValue() & { checkf(HoldsAlternative<I>(), TEXT("It is an error to call GetValue() on an wrong TVariant. Please either check HoldsAlternative() or use Get(DefaultValue) instead.")); return *reinterpret_cast< TVariantAlternative<I, TVariant<Ts...>>*>(&Value); }
@ -474,7 +474,7 @@ private:
}; };
template <typename T, typename... Ts> requires (!CSameAs<T, TVariant<Ts...>> && CEqualityComparable<T>) template <typename T, typename... Ts> requires (!CBaseOf<TVariant<Ts...>, T> && CEqualityComparable<T>)
constexpr bool operator==(const TVariant<Ts...>& LHS, const T& RHS) constexpr bool operator==(const TVariant<Ts...>& LHS, const T& RHS)
{ {
return LHS.template HoldsAlternative<T>() ? LHS.template GetValue<T>() == RHS : false; return LHS.template HoldsAlternative<T>() ? LHS.template GetValue<T>() == RHS : false;