Ark Server API (ASA) - Wiki
Loading...
Searching...
No Matches
TVariantMeta.h
Go to the documentation of this file.
1// Copyright Epic Games, Inc. All Rights Reserved.
2
3#pragma once
4
5#include "Templates/MemoryOps.h"
6#include "Templates/TypeCompatibleBytes.h"
7#include "Templates/UnrealTemplate.h"
8#include "Templates/UnrealTypeTraits.h"
9#include "Delegates/IntegerSequence.h"
10#include "Templates/AndOrNot.h"
11#include "Concepts/Insertable.h"
12
13#include "Misc/AssertionMacros.h"
14
15template <typename T, typename... Ts>
16class TVariant;
17
18template <typename T>
19struct TIsVariant;
20
21template <typename T>
22struct TVariantSize;
23
24namespace UE
25{
26namespace Core
27{
28namespace Private
29{
30 /** A shim to get at FArchive through a dependent name, allowing TVariant.h to not include Archive.h. Only calling code that needs serialization has to include it. */
31 template <typename T>
33 {
34 using Type = FArchive;
35 };
36
37 /** Determine if all the types in a template parameter pack has duplicate types */
38 template <typename...>
39 struct TTypePackContainsDuplicates;
40
41 /** A template parameter pack containing a single type has no duplicates */
42 template <typename T>
43 struct TTypePackContainsDuplicates<T>
44 {
45 static constexpr bool Value = false;
46 };
47
48 /**
49 * A template parameter pack containing the same type adjacently contains duplicate types.
50 * The next structure ensures that we check all pairs of types in a template parameter pack.
51 */
52 template <typename T, typename... Ts>
53 struct TTypePackContainsDuplicates<T, T, Ts...>
54 {
55 static constexpr bool Value = true;
56 };
57
58 /** Check all pairs of types in a template parameter pack to determine if any type is duplicated */
59 template <typename T, typename U, typename... Rest>
60 struct TTypePackContainsDuplicates<T, U, Rest...>
61 {
62 static constexpr bool Value = TTypePackContainsDuplicates<T, Rest...>::Value || TTypePackContainsDuplicates<U, Rest...>::Value;
63 };
64
65 /** Determine if any of the types in a template parameter pack are references */
66 template <typename... Ts>
68 {
69 static constexpr bool Value = TOr<TIsReferenceType<Ts>...>::Value;
70 };
71
72 /** Determine the max alignof and sizeof of all types in a template parameter pack and provide a type that is compatible with those sizes */
73 template <typename... Ts>
75 {
76 static constexpr SIZE_T MaxOf(const SIZE_T Sizes[])
77 {
78 SIZE_T MaxSize = 0;
79 for (SIZE_T Itr = 0; Itr < sizeof...(Ts); ++Itr)
80 {
81 if (Sizes[Itr] > MaxSize)
82 {
83 MaxSize = Sizes[Itr];
84 }
85 }
86 return MaxSize;
87 }
88 static constexpr SIZE_T MaxSizeof()
89 {
90 constexpr SIZE_T Sizes[] = { sizeof(Ts)... };
91 return MaxOf(Sizes);
92 }
93 static constexpr SIZE_T MaxAlignof()
94 {
95 constexpr SIZE_T Sizes[] = { alignof(Ts)... };
96 return MaxOf(Sizes);
97 }
98
99 static constexpr SIZE_T SizeofValue = MaxSizeof();
100 static constexpr SIZE_T AlignofValue = MaxAlignof();
101 static_assert(SizeofValue > 0, "MaxSizeof must be greater than 0");
102 static_assert(AlignofValue > 0, "MaxAlignof must be greater than 0");
103
104 /** Interpret the underlying data as the type in the variant parameter pack at the compile-time index. This function is used to implement Visit and should not be used directly */
105 template <SIZE_T N>
107 {
108 using ReturnType = typename TNthTypeFromParameterPack<N, Ts...>::Type;
109 return *reinterpret_cast<ReturnType*>(&Storage);
110 }
111
112 /** Interpret the underlying data as the type in the variant parameter pack at the compile-time index. This function is used to implement Visit and should not be used directly */
113 template <SIZE_T N>
115 {
116 using ReturnType = typename TNthTypeFromParameterPack<N, Ts...>::Type;
117 return (ReturnType&&)GetValueAsIndexedType<N>();
118 }
119
120 /** Interpret the underlying data as the type in the variant parameter pack at the compile-time index. This function is used to implement Visit and should not be used directly */
121 template <SIZE_T N>
122 const auto& GetValueAsIndexedType() const&
123 {
124 // Temporarily remove the const qualifier so we can implement GetValueAsIndexedType in one location.
125 return const_cast<TVariantStorage*>(this)->template GetValueAsIndexedType<N>();
126 }
127
129 };
130
131 /** Helper to lookup indices of each type in a template parameter pack */
132 template <SIZE_T N, typename LookupType, typename... Ts>
134 {
135 static constexpr SIZE_T Value = (SIZE_T)-1;
136 };
137
138 /** When the type we're looking up bubbles up to the top, we return the current index */
139 template <SIZE_T N, typename T, typename... Ts>
140 struct TParameterPackTypeIndexHelper<N, T, T, Ts...>
141 {
142 static constexpr SIZE_T Value = N;
143 };
144
145 /** When different type than the lookup is at the front of the parameter pack, we increase the index and move to the next type */
146 template <SIZE_T N, typename LookupType, typename T, typename... Ts>
147 struct TParameterPackTypeIndexHelper<N, LookupType, T, Ts...>
148 {
149 static constexpr SIZE_T Value = TParameterPackTypeIndexHelper<N + 1, LookupType, Ts...>::Value;
150 };
151
152 /** Entry-point for looking up the index of a type in a template parameter pack */
153 template <typename LookupType, typename... Ts>
155 {
156 static constexpr SIZE_T Value = TParameterPackTypeIndexHelper<0, LookupType, Ts...>::Value;
157 };
158
159 /** An adapter for calling DestructItem */
160 template <typename T>
162 {
163 static constexpr void Destruct(void* Storage)
164 {
165 DestructItem(static_cast<T*>(Storage));
166 }
167 };
168
169 /** Lookup a type in a template parameter pack by its index and call the destructor */
170 template <typename... Ts>
172 {
173 /** If the index matches, call the destructor, otherwise call with the next index and type in the parameter pack*/
174 static void Destruct(SIZE_T TypeIndex, void* Value)
175 {
176 static constexpr void(*Destructors[])(void*) = { &TDestructorCaller<Ts>::Destruct... };
179 }
180 };
181
182 /** An adapter for calling a copy constructor of a type */
183 template <typename T>
185 {
186 /** Call the copy constructor of a type with the provided memory location and value */
187 static void Construct(void* Storage, const void* Value)
188 {
189 new(Storage) T(*static_cast<const T*>(Value));
190 }
191 };
192
193 /** A utility for calling a type's copy constructor based on an index into a template parameter pack */
194 template <typename... Ts>
196 {
197 /** Construct the type at the index in the template parameter pack with the provided memory location and value */
198 static void Construct(SIZE_T TypeIndex, void* Storage, const void* Value)
199 {
200 static constexpr void(*CopyConstructors[])(void*, const void*) = { &TCopyConstructorCaller<Ts>::Construct... };
203 }
204 };
205
206
207 /** A utility for calling a type's move constructor based on an index into a template parameter pack */
208 template <typename T>
210 {
211 /** Call the move constructor of a type with the provided memory location and value */
212 static void Construct(void* Storage, void* Value)
213 {
214 new(Storage) T(MoveTemp(*static_cast<T*>(Value)));
215 }
216 };
217
218 /** A utility for calling a type's move constructor based on an index into a template parameter pack */
219 template <typename... Ts>
221 {
222 /** Construct the type at the index in the template parameter pack with the provided memory location and value */
223 static void Construct(SIZE_T TypeIndex, void* Target, void* Source)
224 {
225 static constexpr void(*MoveConstructors[])(void*, void*) = { &TMoveConstructorCaller<Ts>::Construct... };
228 }
229 };
230
231 /** A utility for loading a specific type from FArchive into a TVariant */
232 template <typename T, typename VariantType>
234 {
235 /** Default construct the type and load it from the FArchive */
236 static void Load(FArchive& Ar, VariantType& OutVariant)
237 {
238 OutVariant.template Emplace<T>();
239 Ar << OutVariant.template Get<T>();
240 }
241 };
242
243 /** A utility for loading a type from FArchive based on an index into a template parameter pack. */
244 template <typename... Ts>
246 {
247 using VariantType = TVariant<Ts...>;
248 static_assert((std::is_default_constructible<Ts>::value && ...), "Each type in TVariant template parameter pack must be default constructible in order to use FArchive serialization");
249 static_assert((TModels<CInsertable<FArchive&>, Ts>::Value && ...), "Each type in TVariant template parameter pack must be able to use operator<< with an FArchive");
250
251 /** Load the type at the specified index from the FArchive and emplace it into the TVariant */
252 static void Load(SIZE_T TypeIndex, FArchive& Ar, VariantType& OutVariant)
253 {
254 static constexpr void(*Loaders[])(FArchive&, VariantType&) = { &TVariantLoadFromArchiveCaller<Ts, VariantType>::Load... };
257 }
258 };
259
260 /** Determine if the type with the provided index in the template parameter pack is the same */
261 template <typename LookupType, typename... Ts>
262 struct TIsType
263 {
264 /** Check if the type at the provided index is the lookup type */
265 static bool IsSame(SIZE_T TypeIndex)
266 {
267 static constexpr bool bIsSameType[] = { std::is_same_v<Ts, LookupType>... };
269 return bIsSameType[TypeIndex];
270 }
271 };
272
273 /** Determine if all the types are TVariant<...> */
274 template <typename... Ts>
275 using TIsAllVariant = TAnd<TIsVariant<Ts>...>;
276
277 /** Encode the stored index of a bunch of variants into a single value used to lookup a Visit invocation function */
278 template <typename T>
279 inline SIZE_T EncodeIndices(const T& Variant)
280 {
281 return Variant.GetIndex();
282 }
283
284 template <typename Variant0, typename... Variants>
285 inline SIZE_T EncodeIndices(const Variant0& First, const Variants&... Rest)
286 {
288 }
289
290 /** Inverse operation of EncodeIndices. Decodes an encoded index into the individual index for the specified variant index. */
291 constexpr SIZE_T DecodeIndex(SIZE_T EncodedIndex, SIZE_T VariantIndex, const SIZE_T* VariantSizes)
292 {
293 while (VariantIndex)
294 {
295 EncodedIndex /= *VariantSizes;
296 --VariantIndex;
297 ++VariantSizes;
298 }
299 return EncodedIndex % *VariantSizes;
300 }
301
303 /** Used to determine the total number of possible Visit invocations when fold expressions are not available. */
304 constexpr SIZE_T Multiply(const SIZE_T* Args, SIZE_T Num)
305 {
306 SIZE_T Result = 1;
307 while (Num)
308 {
309 Result *= *Args++;
310 --Num;
311 }
312 return Result;
313 }
314#endif
315
316 /** Cast a TVariant to its private base */
317 template <typename... Ts>
318 FORCEINLINE TVariantStorage<Ts...>& CastToStorage(TVariant<Ts...>& Variant)
319 {
320 return *(TVariantStorage<Ts...>*)(&Variant);
321 }
322
323 template <typename... Ts>
324 FORCEINLINE TVariantStorage<Ts...>&& CastToStorage(TVariant<Ts...>&& Variant)
325 {
326 return (TVariantStorage<Ts...>&&)(*(TVariantStorage<Ts...>*)(&Variant));
327 }
328
329 template <typename... Ts>
330 FORCEINLINE const TVariantStorage<Ts...>& CastToStorage(const TVariant<Ts...>& Variant)
331 {
332 return *(const TVariantStorage<Ts...>*)(&Variant);
333 }
334
335 /** Invocation detail for a single combination of stored variant indices */
336 template <SIZE_T EncodedIndex, SIZE_T... VariantIndices, typename Func, typename... Variants>
337 inline decltype(auto) VisitApplyEncoded(Func&& Callable, Variants&&... Args)
338 {
339 constexpr SIZE_T VariantSizes[] = { TVariantSize<Variants>::Value... };
340 return Callable(CastToStorage(Forward<Variants>(Args)).template GetValueAsIndexedType<DecodeIndex(EncodedIndex, VariantIndices, VariantSizes)>()...);
341 }
342
343 /**
344 * Work around used to separate pack expansion of EncodedIndices and VariantIndices in VisitImpl below when defining the Invokers array.
345 *
346 * Ideally the line below would only need to be written as:
347 * constexpr InvokeFn Invokers[] = { &VisitApplyEncoded<EncodedIndices, VariantIndices...>... };
348 *
349 * Due to what appears to be a lexing bug, MSVC 2017 tries to expand EncodedIndices and VariantIndices together
350 */
351 template <typename InvokeFn, SIZE_T... VariantIndices>
352 struct TWrapper
353 {
354 template <SIZE_T EncodedIndex>
356 };
357
358 /** Implementation detail for Visit(Callable, Variants...). Builds an array of invokers, and forwards the variants to the callable for the specific EncodedIndex */
359 template <typename Func, SIZE_T... EncodedIndices, SIZE_T... VariantIndices, typename... Variants>
360 decltype(auto) VisitImpl(SIZE_T EncodedIndex, Func&& Callable, TIntegerSequence<SIZE_T, EncodedIndices...>&&, TIntegerSequence<SIZE_T, VariantIndices...>&& VariantIndicesSeq, Variants&&... Args)
361 {
362 using ReturnType = decltype(VisitApplyEncoded<0, VariantIndices...>(Forward<Func>(Callable), Forward<Variants>(Args)...));
363 using InvokeFn = ReturnType(*)(Func&&, Variants&&...);
364 using WrapperType = TWrapper<InvokeFn, VariantIndices...>;
365 static constexpr InvokeFn Invokers[] = { WrapperType::template FuncPtr<EncodedIndices>... };
366 return Invokers[EncodedIndex](Forward<Func>(Callable), Forward<Variants>(Args)...);
367 }
368} // namespace Private
369} // namespace Core
370} // namespace UE
#define check(expr)
#define PLATFORM_COMPILER_HAS_FOLD_EXPRESSIONS
Definition Platform.h:247
#define FORCEINLINE
Definition Platform.h:644
#define UE_ARRAY_COUNT(array)
SIZE_T EncodeIndices(const Variant0 &First, const Variants &... Rest)
SIZE_T EncodeIndices(const T &Variant)
constexpr SIZE_T Multiply(const SIZE_T *Args, SIZE_T Num)
decltype(auto) VisitApplyEncoded(Func &&Callable, Variants &&... Args)
FORCEINLINE TVariantStorage< Ts... > & CastToStorage(TVariant< Ts... > &Variant)
decltype(auto) VisitImpl(SIZE_T EncodedIndex, Func &&Callable, TIntegerSequence< SIZE_T, EncodedIndices... > &&, TIntegerSequence< SIZE_T, VariantIndices... > &&VariantIndicesSeq, Variants &&... Args)
constexpr SIZE_T DecodeIndex(SIZE_T EncodedIndex, SIZE_T VariantIndex, const SIZE_T *VariantSizes)
FORCEINLINE TVariantStorage< Ts... > && CastToStorage(TVariant< Ts... > &&Variant)
FORCEINLINE const TVariantStorage< Ts... > & CastToStorage(const TVariant< Ts... > &Variant)
Definition Vector.h:40
static void Construct(void *Storage, const void *Value)
static void Construct(SIZE_T TypeIndex, void *Storage, const void *Value)
static constexpr void Destruct(void *Storage)
static void Destruct(SIZE_T TypeIndex, void *Value)
static bool IsSame(SIZE_T TypeIndex)
static void Construct(void *Storage, void *Value)
static void Construct(SIZE_T TypeIndex, void *Target, void *Source)
static void Load(FArchive &Ar, VariantType &OutVariant)
static void Load(SIZE_T TypeIndex, FArchive &Ar, VariantType &OutVariant)
static constexpr SIZE_T AlignofValue
static constexpr SIZE_T MaxAlignof()
static constexpr SIZE_T MaxOf(const SIZE_T Sizes[])
static constexpr SIZE_T SizeofValue
const auto & GetValueAsIndexedType() const &
static constexpr SIZE_T MaxSizeof()
TAlignedBytes< SizeofValue, AlignofValue > Storage
static constexpr InvokeFn FuncPtr