Ark Server API (ASA) - Wiki
Loading...
Searching...
No Matches
InlineValue.h
Go to the documentation of this file.
1// Copyright Epic Games, Inc. All Rights Reserved.
2
3#pragma once
4
5#include "CoreTypes.h"
6#include "Misc/AssertionMacros.h"
7#include "HAL/UnrealMemory.h"
8#include "Templates/MemoryOps.h"
9#include "Templates/PointerIsConvertibleFromTo.h"
10#include "Templates/Decay.h"
11#include "Templates/TypeCompatibleBytes.h"
12#include "Templates/UnrealTemplate.h"
13
14/**
15 * A container type that houses an instance of BaseType in inline memory where it is <= MaxInlineSize,
16 * or in a separate heap allocation where it's > MaxInlineSize.
17 *
18 * Can be viewed as a TUniquePtr with a small allocation optimization.
19 */
20template<typename BaseType, uint8 DesiredMaxInlineSize=64, uint8 DefaultAlignment=8>
22{
23public:
24 /**
25 * Default construction to an empty container
26 */
28 : bIsValid(false), bInline(true)
29 {
30 }
31
32 /**
33 * Construction from any type relating to BaseType.
34 */
35 template<
36 typename T,
37 typename = typename TEnableIf<TPointerIsConvertibleFromTo<typename TDecay<T>::Type, BaseType>::Value>::Type
38 >
40 : bIsValid(false)
41 {
42 InitializeFrom<typename TDecay<T>::Type>(Forward<T>(In));
43 }
44
45 /**
46 * In-place construction of BaseType from a set of arguments.
47 */
48 template<typename... ArgTypes>
49 TInlineValue(EInPlace, ArgTypes&&... Args)
50 : bIsValid(false)
51 {
53 }
54
55 /**
56 * Destructor
57 */
59 {
60 Reset();
61 }
62
63 /**
64 * Move construction/assignment
65 */
67 : bIsValid(false), bInline(true)
68 {
69 *this = MoveTemp(In);
70 }
72 {
74 return *this;
75 }
76
77 /**
78 * Copy construction/assignment is disabled
79 */
80 TInlineValue(const TInlineValue& In) = delete;
81 TInlineValue& operator=(const TInlineValue& In) = delete;
82
83 /**
84 * Move assignment from any type relating to BaseType.
85 */
86 template<typename T>
87 typename TEnableIf<TPointerIsConvertibleFromTo<typename TDecay<T>::Type, BaseType>::Value, TInlineValue&>::Type operator=(T&& In)
88 {
89 *this = TInlineValue(Forward<T>(In));
90 return *this;
91 }
92
93 /**
94 * Reset this container to wrap a new type
95 */
97 {
98 Reset();
99
100 if (In.bIsValid)
101 {
102 // Steal the object contained within 'In'
103 bIsValid = true;
104 In.bIsValid = false;
105
107 Data = In.Data;
108 }
109 }
110
111 /**
112 * Reset this container back to its empty state
113 */
114 void Reset()
115 {
116 if (bIsValid)
117 {
119 // Set bIsValid immediately to avoid double-deletion on potential re-entry
120 bIsValid = false;
121 Value.~BaseType();
123 }
124 }
125
126 /**
127 * Emplace a new type (deriving from BaseType) into this inline value
128 */
129 template <typename T, typename... ArgsType>
130 FORCEINLINE void Emplace(ArgsType&&... Args)
131 {
132 static_assert(TPointerIsConvertibleFromTo<T, BaseType>::Value, "T must derive from BaseType.");
133 Reset();
135 }
136
137 /**
138 * Check if this container is wrapping a valid object
139 */
140 FORCEINLINE bool IsValid() const
141 {
142 return bIsValid;
143 }
144
145 /**
146 * Access the wrapped object's base type
147 * @return A reference to the object. Will assert where IsValid() is false.
148 */
149 FORCEINLINE BaseType& GetValue() const
150 {
151 checkf(bIsValid, TEXT("It is an error to call GetValue() on an invalid TInlineValue. Please either check IsValid() or use Get(DefaultValue) instead."));
152 return bInline ? (BaseType&)Data : **((BaseType**)&Data);
153 }
154
155 /**
156 * Get the wrapped object, or a user-specified default
157 * @return The object, or the user-specified default
158 */
159 FORCEINLINE const BaseType& Get(const BaseType& Default) const
160 {
161 return bIsValid ? GetValue() : Default;
162 }
163
164 /**
165 * Get a pointer the wrapped object, or a user-specified default
166 * @return A pointer to the object, or the user-specified default
167 */
168 FORCEINLINE BaseType* GetPtr(BaseType* Default = nullptr) const
169 {
170 return bIsValid ? &GetValue() : Default;
171 }
172
173 FORCEINLINE BaseType& operator*() const { return GetValue(); }
174 FORCEINLINE BaseType* operator->() const { return &GetValue(); }
175
176 /**
177 * Reserve space for a structure derived from BaseType, of the size and alignment specified .
178 * @note Does not initialize the memory in anyway
179 */
180 void* Reserve(uint32 InSize, uint32 InAlignment)
181 {
182 Reset();
183
185
187 bIsValid = true;
188
189 return &GetValue();
190 }
191
192private:
193
194 template<typename T, typename... ArgsType>
195 void InitializeFrom(ArgsType&&... Args)
196 {
197 bInline = sizeof(T) <= MaxInlineSize && alignof(T) <= DefaultAlignment;
198
199 // Allocate the object
200 ConditionallyAllocateObject(sizeof(T), alignof(T));
201 bIsValid = true;
202
203 // Placement new our value into the structure
204 new(&GetValue()) T(Forward<ArgsType>(Args)...);
205
206 checkf((void*)&GetValue() == (BaseType*)((T*)&GetValue()), TEXT("TInlineValue cannot operate with multiple inheritance objects."));
207 }
208
209 void ConditionallyAllocateObject(uint32 Size, uint32 Alignment)
210 {
211 if (!bInline)
212 {
213 // We store a *ptr* to the data in the aligned bytes, when we allocate on the heap
215 *((BaseType**)&Data) = Allocation;
216 }
217 }
218
220 {
221 if (!bInline)
222 {
223 FMemory::Free(*((void**)&Data));
224 }
225 }
226
227private:
228 /** ~We cannot allow an allocation of less than the size of a pointer */
229 enum { MaxInlineSize = DesiredMaxInlineSize < sizeof(void*) ? sizeof(void*) : DesiredMaxInlineSize };
230
231 /** Type-erased bytes containing either a BaseType& or heap allocated BaseType* */
232 TAlignedBytes<MaxInlineSize, DefaultAlignment> Data;
233
234 /** true where this container is wrapping a valid object */
235 bool bIsValid : 1;
236
237 /** true where InlineBytes points to a valid BaseType&, false if it's a heap allocated BaseType* */
238 bool bInline : 1;
239};
240
241/**
242 * Construct a new TInlineValue<BaseType> from the specified user type, and arguments
243 */
244template<typename BaseType, typename UserType, uint8 MaxInlineSize = 64, uint8 DefaultAlignment = 8, typename... ArgsType>
245TInlineValue<BaseType, MaxInlineSize, DefaultAlignment> MakeInlineValue(ArgsType... Args)
246{
247 return TInlineValue<BaseType, MaxInlineSize, DefaultAlignment>(UserType(Forward<ArgsType>(Args)...));
248}
#define checkf(expr, format,...)
TInlineValue< BaseType, MaxInlineSize, DefaultAlignment > MakeInlineValue(ArgsType... Args)
#define FORCEINLINE
Definition Platform.h:644
void ConditionallyAllocateObject(uint32 Size, uint32 Alignment)
TInlineValue(T &&In)
Definition InlineValue.h:39
FORCEINLINE BaseType * operator->() const
FORCEINLINE void Emplace(ArgsType &&... Args)
FORCEINLINE BaseType & GetValue() const
FORCEINLINE const BaseType & Get(const BaseType &Default) const
TAlignedBytes< MaxInlineSize, DefaultAlignment > Data
TInlineValue & operator=(const TInlineValue &In)=delete
FORCEINLINE BaseType & operator*() const
TInlineValue(const TInlineValue &In)=delete
void * Reserve(uint32 InSize, uint32 InAlignment)
void Reset(TInlineValue &&In)
Definition InlineValue.h:96
TInlineValue(TInlineValue &&In)
Definition InlineValue.h:66
TEnableIf< TPointerIsConvertibleFromTo< typenameTDecay< T >::Type, BaseType >::Value, TInlineValue & >::Type operator=(T &&In)
Definition InlineValue.h:87
FORCEINLINE bool IsValid() const
void ConditionallyDestroyAllocation()
void InitializeFrom(ArgsType &&... Args)
FORCEINLINE BaseType * GetPtr(BaseType *Default=nullptr) const
TInlineValue(EInPlace, ArgTypes &&... Args)
Definition InlineValue.h:49
TInlineValue & operator=(TInlineValue &&In)
Definition InlineValue.h:71
Definition Decay.h:44