refactor(templates): refactor TVariant::Visit to Visit
This commit is contained in:
parent
797386f3d6
commit
9cc7ac9480
@ -242,9 +242,64 @@ void TestVariant()
|
||||
}
|
||||
|
||||
{
|
||||
// TVariant<bool> TempA = false;
|
||||
// TempA.Visit([](auto& A) { A = true; });
|
||||
// always_check(TempA.GetValue<bool>());
|
||||
using VariantType = TVariant<int32, int64, float64>;
|
||||
VariantType TempArray[] = { 10, 15ll, 1.5 };
|
||||
|
||||
for(auto&& TempA : TempArray)
|
||||
{
|
||||
Visit(
|
||||
[](auto&& A)
|
||||
{
|
||||
using T = TRemoveCVRef<decltype(A)>;
|
||||
if constexpr (CSameAs<T, int32>) always_check(A == 10);
|
||||
else if constexpr (CSameAs<T, int64>) always_check(A == 15ll);
|
||||
else if constexpr (CSameAs<T, float64>) always_check(A == 1.5);
|
||||
else always_check_no_entry();
|
||||
},
|
||||
TempA
|
||||
);
|
||||
|
||||
VariantType TempB = Visit([](auto&& A) -> VariantType { return A + A; }, TempA);
|
||||
|
||||
Visit(
|
||||
[](auto&& A, auto&& B)
|
||||
{
|
||||
using T = TRemoveCVRef<decltype(A)>;
|
||||
if constexpr (CSameAs<T, int32>) always_check(A == 10 && B == 20);
|
||||
else if constexpr (CSameAs<T, int64>) always_check(A == 15ll && B == 30ll);
|
||||
else if constexpr (CSameAs<T, float64>) always_check(A == 1.5 && B == 3.0);
|
||||
else always_check_no_entry();
|
||||
},
|
||||
TempA, TempB
|
||||
);
|
||||
|
||||
Visit([](auto&& A) { A *= 2; }, TempA);
|
||||
|
||||
Visit(
|
||||
[](auto&& A)
|
||||
{
|
||||
using T = TRemoveCVRef<decltype(A)>;
|
||||
if constexpr (CSameAs<T, int32>) always_check(A == 20);
|
||||
else if constexpr (CSameAs<T, int64>) always_check(A == 30ll);
|
||||
else if constexpr (CSameAs<T, float64>) always_check(A == 3.0);
|
||||
else always_check_no_entry();
|
||||
},
|
||||
TempA
|
||||
);
|
||||
}
|
||||
|
||||
for (auto&& TempA : TempArray) {
|
||||
Visit(
|
||||
TOverloaded
|
||||
{
|
||||
[](int32 A) { always_check(A == 20); },
|
||||
[](int64 A) { always_check(A == 30ll); },
|
||||
[](float64 A) { always_check(A == 3.0); },
|
||||
[](auto A) { always_check_no_entry(); },
|
||||
},
|
||||
TempA
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
@ -272,10 +327,10 @@ void TestVariant()
|
||||
bool bIsLValue;
|
||||
bool bIsRValue;
|
||||
|
||||
auto TestQualifiers = [&bIsConst, &bIsLValue, &bIsRValue](auto&& Arg) -> int32
|
||||
auto TestQualifiers = [&bIsConst, &bIsLValue, &bIsRValue](auto&& A) -> int32
|
||||
{
|
||||
using T = decltype(Arg);
|
||||
always_check(Arg == 10);
|
||||
using T = decltype(A);
|
||||
always_check(A == 10);
|
||||
always_check(CConst<TRemoveReference<T>> == bIsConst);
|
||||
always_check(CLValueReference<T> == bIsLValue);
|
||||
always_check(CRValueReference<T> == bIsRValue);
|
||||
@ -287,7 +342,7 @@ void TestVariant()
|
||||
bIsRValue = false;
|
||||
|
||||
TVariant<int32> TempLA = 10;
|
||||
auto ReturnLA = TempLA.Visit(TestQualifiers);
|
||||
auto ReturnLA = Visit(TestQualifiers, TempLA);
|
||||
always_check((CSameAs<int32, decltype(ReturnLA)>));
|
||||
|
||||
bIsConst = true;
|
||||
@ -295,7 +350,7 @@ void TestVariant()
|
||||
bIsRValue = false;
|
||||
|
||||
const TVariant<int32> TempLB = TempLA;
|
||||
auto ReturnLB = TempLB.Visit(TestQualifiers);
|
||||
auto ReturnLB = Visit(TestQualifiers, TempLB);
|
||||
always_check((CSameAs<int32, decltype(ReturnLB)>));
|
||||
|
||||
bIsConst = false;
|
||||
@ -303,7 +358,7 @@ void TestVariant()
|
||||
bIsRValue = true;
|
||||
|
||||
TVariant<int32> TempRA = 10;
|
||||
auto ReturnRA = MoveTemp(TempRA).Visit(TestQualifiers);
|
||||
auto ReturnRA = Visit(TestQualifiers, MoveTemp(TempRA));
|
||||
always_check((CSameAs<int32, decltype(ReturnRA)>));
|
||||
|
||||
bIsConst = true;
|
||||
@ -311,7 +366,7 @@ void TestVariant()
|
||||
bIsRValue = true;
|
||||
|
||||
const TVariant<int32> TempRB = TempLA;
|
||||
auto ReturnRB = MoveTemp(TempRB).Visit(TestQualifiers);
|
||||
auto ReturnRB = Visit(TestQualifiers, MoveTemp(TempRB));
|
||||
always_check((CSameAs<int32, decltype(ReturnRB)>));
|
||||
|
||||
bIsConst = false;
|
||||
@ -319,7 +374,7 @@ void TestVariant()
|
||||
bIsRValue = false;
|
||||
|
||||
TVariant<int32> TempLC = 10;
|
||||
auto ReturnLC = TempLC.Visit<int32>(TestQualifiers);
|
||||
auto ReturnLC = Visit<int32>(TestQualifiers, TempLC);
|
||||
always_check((CSameAs<int32, decltype(ReturnLC)>));
|
||||
|
||||
bIsConst = true;
|
||||
@ -327,7 +382,7 @@ void TestVariant()
|
||||
bIsRValue = false;
|
||||
|
||||
const TVariant<int32> TempLD = TempLC;
|
||||
auto ReturnLD = TempLD.Visit<int32>(TestQualifiers);
|
||||
auto ReturnLD = Visit<int32>(TestQualifiers, TempLD);
|
||||
always_check((CSameAs<int32, decltype(ReturnLD)>));
|
||||
|
||||
bIsConst = false;
|
||||
@ -335,7 +390,7 @@ void TestVariant()
|
||||
bIsRValue = true;
|
||||
|
||||
TVariant<int32> TempRC = 10;
|
||||
auto ReturnRC = MoveTemp(TempRC).Visit<int32>(TestQualifiers);
|
||||
auto ReturnRC = Visit<int32>(TestQualifiers, MoveTemp(TempRC));
|
||||
always_check((CSameAs<int32, decltype(ReturnRC)>));
|
||||
|
||||
bIsConst = true;
|
||||
@ -343,7 +398,7 @@ void TestVariant()
|
||||
bIsRValue = true;
|
||||
|
||||
const TVariant<int32> TempRD = TempLC;
|
||||
auto ReturnRD = MoveTemp(TempRD).Visit<int32>(TestQualifiers);
|
||||
auto ReturnRD = Visit<int32>(TestQualifiers, MoveTemp(TempRD));
|
||||
always_check((CSameAs<int32, decltype(ReturnRD)>));
|
||||
}
|
||||
|
||||
|
@ -239,70 +239,6 @@ public:
|
||||
template <typename T> constexpr decltype(auto) Get( T& DefaultValue) & { return HoldsAlternative<T>() ? GetValue<T>() : DefaultValue; }
|
||||
template <typename T> constexpr decltype(auto) Get(const T& DefaultValue) const& { return HoldsAlternative<T>() ? GetValue<T>() : DefaultValue; }
|
||||
|
||||
template <typename F> requires (true && ... && CInvocable<F, Ts>)
|
||||
FORCEINLINE decltype(auto) Visit(F&& Func) &
|
||||
{
|
||||
checkf(IsValid(), TEXT("It is an error to call Visit() on an wrong TVariant. Please either check IsValid()."));
|
||||
|
||||
using ReturnType = TCommonType<TInvokeResult<F, Ts>...>;
|
||||
|
||||
using FInvokeImpl = ReturnType(*)(F&&, void*);
|
||||
static constexpr FInvokeImpl InvokeImpl[] = { [](F&& Func, void* This) -> ReturnType { return InvokeResult<ReturnType>(Forward<F>(Func), *reinterpret_cast<Ts*>(This)); }... };
|
||||
|
||||
return InvokeImpl[GetIndex()](Forward<F>(Func), &Value);
|
||||
}
|
||||
|
||||
template <typename F> requires (true && ... && CInvocable<F, Ts>)
|
||||
FORCEINLINE decltype(auto) Visit(F&& Func) &&
|
||||
{
|
||||
checkf(IsValid(), TEXT("It is an error to call Visit() on an wrong TVariant. Please either check IsValid()."));
|
||||
|
||||
using ReturnType = TCommonType<TInvokeResult<F, Ts>...>;
|
||||
|
||||
using FInvokeImpl = ReturnType(*)(F&&, void*);
|
||||
static constexpr FInvokeImpl InvokeImpl[] = { [](F&& Func, void* This) -> ReturnType { return InvokeResult<ReturnType>(Forward<F>(Func), MoveTemp(*reinterpret_cast<Ts*>(This))); }... };
|
||||
|
||||
return InvokeImpl[GetIndex()](Forward<F>(Func), &Value);
|
||||
}
|
||||
|
||||
template <typename F> requires (true && ... && CInvocable<F, Ts>)
|
||||
FORCEINLINE decltype(auto) Visit(F&& Func) const&
|
||||
{
|
||||
checkf(IsValid(), TEXT("It is an error to call Visit() on an wrong TVariant. Please either check IsValid()."));
|
||||
|
||||
using ReturnType = TCommonType<TInvokeResult<F, Ts>...>;
|
||||
|
||||
using FInvokeImpl = ReturnType(*)(F&&, const void*);
|
||||
static constexpr FInvokeImpl InvokeImpl[] = { [](F&& Func, const void* This) -> ReturnType { return InvokeResult<ReturnType>(Forward<F>(Func), *reinterpret_cast<const Ts*>(This)); }... };
|
||||
|
||||
return InvokeImpl[GetIndex()](Forward<F>(Func), &Value);
|
||||
}
|
||||
|
||||
template <typename F> requires (true && ... && CInvocable<F, Ts>)
|
||||
FORCEINLINE decltype(auto) Visit(F&& Func) const&&
|
||||
{
|
||||
checkf(IsValid(), TEXT("It is an error to call Visit() on an wrong TVariant. Please either check IsValid()."));
|
||||
|
||||
using ReturnType = TCommonType<TInvokeResult<F, Ts>...>;
|
||||
|
||||
using FInvokeImpl = ReturnType(*)(F&&, const void*);
|
||||
static constexpr FInvokeImpl InvokeImpl[] = { [](F&& Func, const void* This) -> ReturnType { return InvokeResult<ReturnType>(Forward<F>(Func), MoveTemp(*reinterpret_cast<const Ts*>(This))); }... };
|
||||
|
||||
return InvokeImpl[GetIndex()](Forward<F>(Func), &Value);
|
||||
}
|
||||
|
||||
template <typename R, typename F> requires (true && ... && CInvocableResult<R, F, Ts>)
|
||||
FORCEINLINE R Visit(F&& Func) & { return Visit(Forward<F>(Func)); }
|
||||
|
||||
template <typename R, typename F> requires (true && ... && CInvocableResult<R, F, Ts>)
|
||||
FORCEINLINE R Visit(F&& Func) && { return MoveTemp(*this).Visit(Forward<F>(Func)); }
|
||||
|
||||
template <typename R, typename F> requires (true && ... && CInvocableResult<R, F, Ts>)
|
||||
FORCEINLINE R Visit(F&& Func) const& { return Visit(Forward<F>(Func)); }
|
||||
|
||||
template <typename R, typename F> requires (true && ... && CInvocableResult<R, F, Ts>)
|
||||
FORCEINLINE R Visit(F&& Func) const&& { return MoveTemp(*this).Visit(Forward<F>(Func)); }
|
||||
|
||||
constexpr void Reset()
|
||||
{
|
||||
if (GetIndex() == INDEX_NONE) return;
|
||||
@ -417,6 +353,152 @@ constexpr bool operator==(const TVariant<Ts...>& LHS, FInvalid)
|
||||
return !LHS.IsValid();
|
||||
}
|
||||
|
||||
NAMESPACE_PRIVATE_BEGIN
|
||||
|
||||
template <typename F, typename... VariantTypes>
|
||||
struct TVariantVisitImpl
|
||||
{
|
||||
struct GetTotalNum
|
||||
{
|
||||
static constexpr size_t Do()
|
||||
{
|
||||
if (sizeof...(VariantTypes) == 0) return 0;
|
||||
|
||||
constexpr size_t VariantNums[] = { TVariantNum<TRemoveReference<VariantTypes>>... };
|
||||
|
||||
size_t Result = 1;
|
||||
|
||||
for (size_t Index = 0; Index < sizeof...(VariantTypes); ++Index)
|
||||
{
|
||||
Result *= VariantNums[Index];
|
||||
}
|
||||
|
||||
return Result;
|
||||
};
|
||||
};
|
||||
|
||||
struct EncodeIndices
|
||||
{
|
||||
static constexpr size_t Do(initializer_list<size_t> Indices)
|
||||
{
|
||||
constexpr size_t VariantNums[] = { TVariantNum<TRemoveReference<VariantTypes>>... };
|
||||
|
||||
size_t Result = 0;
|
||||
|
||||
for (size_t Index = 0; Index < sizeof...(VariantTypes); ++Index)
|
||||
{
|
||||
Result *= VariantNums[Index];
|
||||
Result += GetData(Indices)[Index];
|
||||
}
|
||||
|
||||
return Result;
|
||||
};
|
||||
};
|
||||
|
||||
struct DecodeExtent
|
||||
{
|
||||
static constexpr size_t Do(size_t EncodedIndex, size_t Extent)
|
||||
{
|
||||
constexpr size_t VariantNums[] = { TVariantNum<TRemoveReference<VariantTypes>>... };
|
||||
|
||||
for (size_t Index = Extent + 1; Index < sizeof...(VariantTypes); ++Index)
|
||||
{
|
||||
EncodedIndex /= VariantNums[Index];
|
||||
}
|
||||
|
||||
return EncodedIndex % VariantNums[Extent];
|
||||
};
|
||||
};
|
||||
|
||||
template <size_t EncodedIndex, typename>
|
||||
struct InvokeEncoded;
|
||||
|
||||
template <size_t EncodedIndex, size_t... ExtentIndices>
|
||||
struct InvokeEncoded<EncodedIndex, TIndexSequence<ExtentIndices...>>
|
||||
{
|
||||
static constexpr decltype(auto) Do(F&& Func, VariantTypes&&... Variants)
|
||||
{
|
||||
return Invoke(Forward<F>(Func), Forward<VariantTypes>(Variants).template GetValue<DecodeExtent::Do(EncodedIndex, ExtentIndices)>()...);
|
||||
}
|
||||
|
||||
template <typename Ret>
|
||||
struct Result
|
||||
{
|
||||
static constexpr Ret Do(F&& Func, VariantTypes&&... Variants)
|
||||
{
|
||||
return InvokeResult<Ret>(Forward<F>(Func), Forward<VariantTypes>(Variants).template GetValue<DecodeExtent::Do(EncodedIndex, ExtentIndices)>()...);
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
template <typename>
|
||||
struct InvokeVariant;
|
||||
|
||||
template <size_t... EncodedIndices>
|
||||
struct InvokeVariant<TIndexSequence<EncodedIndices...>>
|
||||
{
|
||||
static constexpr decltype(auto) Do(F&& Func, VariantTypes&&... Variants)
|
||||
{
|
||||
using ExtentIndices = TIndexSequenceFor<VariantTypes...>;
|
||||
|
||||
using ResultType = TCommonType<decltype(InvokeEncoded<EncodedIndices, ExtentIndices>::Do(Forward<F>(Func), Forward<VariantTypes>(Variants)...))...>;
|
||||
|
||||
using InvokeImplType = ResultType(*)(F&&, VariantTypes&&...);
|
||||
|
||||
constexpr InvokeImplType InvokeImpl[] = { InvokeEncoded<EncodedIndices, ExtentIndices>::template Result<ResultType>::Do... };
|
||||
|
||||
return InvokeImpl[EncodeIndices::Do({ Variants.GetIndex()... })](Forward<F>(Func), Forward<VariantTypes>(Variants)...);
|
||||
}
|
||||
|
||||
template <typename Ret>
|
||||
struct Result
|
||||
{
|
||||
static constexpr Ret Do(F&& Func, VariantTypes&&... Variants)
|
||||
{
|
||||
using ExtentIndices = TIndexSequenceFor<VariantTypes...>;
|
||||
|
||||
using InvokeImplType = Ret(*)(F&&, VariantTypes&&...);
|
||||
|
||||
constexpr InvokeImplType InvokeImpl[] = { InvokeEncoded<EncodedIndices, ExtentIndices>::template Result<Ret>::Do... };
|
||||
|
||||
return InvokeImpl[EncodeIndices::Do({ Variants.GetIndex()... })](Forward<F>(Func), Forward<VariantTypes>(Variants)...);
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
static constexpr decltype(auto) Do(F&& Func, VariantTypes&&... Variants)
|
||||
{
|
||||
return InvokeVariant<TMakeIndexSequence<GetTotalNum::Do()>>::Do(Forward<F>(Func), Forward<VariantTypes>(Variants)...);
|
||||
}
|
||||
|
||||
template <typename Ret>
|
||||
struct Result
|
||||
{
|
||||
static constexpr Ret Do(F&& Func, VariantTypes&&... Variants)
|
||||
{
|
||||
return InvokeVariant<TMakeIndexSequence<GetTotalNum::Do()>>::template Result<Ret>::Do(Forward<F>(Func), Forward<VariantTypes>(Variants)...);
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
NAMESPACE_PRIVATE_END
|
||||
|
||||
template <typename F, typename FirstVariantType, typename... VariantTypes>
|
||||
requires (CTVariant<TRemoveReference<FirstVariantType>> && (true && ... && CTVariant<TRemoveReference<VariantTypes>>))
|
||||
constexpr decltype(auto) Visit(F&& Func, FirstVariantType&& FirstVariant, VariantTypes&&... Variants)
|
||||
{
|
||||
checkf((true && ... && Variants.IsValid()), TEXT("It is an error to call Visit() on an wrong TVariant. Please either check IsValid()."));
|
||||
return NAMESPACE_PRIVATE::TVariantVisitImpl<F, FirstVariantType, VariantTypes...>::Do(Forward<F>(Func), Forward<FirstVariantType>(FirstVariant), Forward<VariantTypes>(Variants)...);
|
||||
}
|
||||
|
||||
template <typename Ret, typename F, typename FirstVariantType, typename... VariantTypes>
|
||||
requires (CTVariant<TRemoveReference<FirstVariantType>> && (true && ... && CTVariant<TRemoveReference<VariantTypes>>))
|
||||
constexpr Ret Visit(F&& Func, FirstVariantType&& FirstVariant, VariantTypes&&... Variants)
|
||||
{
|
||||
checkf((true && ... && Variants.IsValid()), TEXT("It is an error to call Visit() on an wrong TVariant. Please either check IsValid()."));
|
||||
return NAMESPACE_PRIVATE::TVariantVisitImpl<F, FirstVariantType, VariantTypes...>::template Result<Ret>::Do(Forward<F>(Func), Forward<FirstVariantType>(FirstVariant), Forward<VariantTypes>(Variants)...);
|
||||
}
|
||||
|
||||
NAMESPACE_MODULE_END(Utility)
|
||||
NAMESPACE_MODULE_END(Redcraft)
|
||||
NAMESPACE_REDCRAFT_END
|
||||
|
Loading…
Reference in New Issue
Block a user