UDocumentation UE5.7 10.02.2026 (Source)
API documentation for Unreal Engine 5.7
Stack.h
Go to the documentation of this file.
1// Copyright Epic Games, Inc. All Rights Reserved.
2
3#pragma once
4
5#if (defined(__AUTORTFM) && __AUTORTFM)
6
8#include "ExternAPI.h"
9#include "Utils.h"
10
11#include <cstddef>
12#include <type_traits>
13
14namespace AutoRTFM
15{
16
17// A stack container with an inline fixed capacity that once exceeded spills to
18// the heap.
19//
20// Notes:
21// * Heap allocated memory is not automatically freed when popping elements.
22// Only calling Reset() or destructing the stack will free heap allocated
23// memory.
24// * This class is not relocatable and so is not safe to use in UE's containers
25// which require elements to be relocatable.
26//
27// Template parameters:
28// T - the element type. Must support copy and move constructors.
29// InlineCapacity - the number of elements that can be held before spilling to
30// the heap.
31// Validation - if Disabled, do not perform validity assertions.
32template<typename T, size_t InlineCapacity, EContainerValidation Validation = EContainerValidation::Enabled>
33class TStack
34{
35public:
36 using ElementType = T;
37
38 // Constructor.
39 TStack() = default;
40
41 // Copy constructor.
42 TStack(const TStack& Other)
43 {
44 CopyFrom(Other);
45 }
46
47 // Move constructor.
49 {
50 MoveFrom(std::move(Other));
51 }
52
53 // Destructor.
54 // Frees all the memory allocated by the allocator.
55 ~TStack()
56 {
57 Reset();
58 }
59
60 // Copy assignment operator
61 TStack& operator=(const TStack& Other)
62 {
63 if (&Other != this)
64 {
65 Clear();
66 CopyFrom(Other);
67 }
68 return *this;
69 }
70
71 // Move assignment operator
72 TStack& operator=(TStack&& Other)
73 {
74 if (&Other != this)
75 {
76 Clear();
77 MoveFrom(std::move(Other));
78 }
79 return *this;
80 }
81
82 // Clears all the items from the stack, preserving the capacity.
83 void Clear()
84 {
85 for (T& Item : *this)
86 {
87 Item.~T();
88 }
89 Count = 0;
90 }
91
92 // Clears all the items from the stack, freeing all heap allocations and
93 // resetting the capacity to InlineCapacity
94 void Reset()
95 {
96 Clear();
97 if (Data != InlineData())
98 {
99 Free(Data);
100 Data = reinterpret_cast<T*>(InlineDataBuffer);
101 }
102 Capacity = InlineCapacity;
103 }
104
105 // Pushes a new item on to the stack.
106 inline void Push(const T& Item)
107 {
108 if (Count >= Capacity)
109 {
110 Reserve(Capacity * 2);
111 }
112
113 new (Data + Count) T(Item);
114 ++Count;
115 }
116
117 // Moves all the items from Other to this stack.
118 // Other will hold no elements after calling.
119 inline void PushAll(TStack&& Other)
120 {
121 size_t NewCount = Count + Other.Count;
122 if (NewCount >= Capacity)
123 {
124 Reserve(std::max<size_t>(NewCount, Capacity * 2));
125 }
126
127 if constexpr (std::is_trivial_v<T>)
128 {
129 memcpy(Data + Count, Other.Data, Other.Count * sizeof(T));
130 }
131 else
132 {
133 for (size_t I = 0, N = Other.Count; I < N; I++)
134 {
135 new (Data + Count + I) T(std::move(Other.Data[I]));
136 Other.Data[I].~T();
137 }
138 }
139 Count = NewCount;
140 Other.SetToInitialState();
141 }
142
143 // Removes the last item on the stack.
144 inline void Pop()
145 {
146 AUTORTFM_ASSERT(Validation == EContainerValidation::Disabled || Count > 0);
147 --Count;
148 Data[Count].~T();
149 }
150
151 // Reserves memory for at NewCapacity items.
152 inline void Reserve(size_t NewCapacity)
153 {
154 if (NewCapacity <= Capacity)
155 {
156 return; // Already has space for the new capacity
157 }
158
159 if constexpr (std::is_trivial_v<T>)
160 {
161 if (Data == InlineData())
162 {
163 T* NewData = reinterpret_cast<T*>(AutoRTFM::Allocate(NewCapacity * sizeof(T), alignof(T)));
164 memcpy(NewData, InlineDataBuffer, Count * sizeof(T));
165 Data = NewData;
166 }
167 else
168 {
169 Data = reinterpret_cast<T*>(AutoRTFM::Reallocate(Data, NewCapacity * sizeof(T), alignof(T)));
170 }
171 }
172 else
173 {
174 T* NewData = reinterpret_cast<T*>(AutoRTFM::Allocate(NewCapacity * sizeof(T), alignof(T)));
175 for (size_t I = 0, N = Count; I < N; I++)
176 {
177 new (NewData + I) T(std::move(Data[I]));
178 Data[I].~T();
179 }
180 if (Data != InlineData())
181 {
182 AutoRTFM::Free(Data);
183 }
184 Data = NewData;
185 }
186
187 Capacity = NewCapacity;
188 }
189
190 inline size_t Num() const { return Count; }
191
192 inline bool IsEmpty() const { return Count == 0; }
193
194 T& operator[](size_t Index)
195 {
196 AUTORTFM_ASSERT(Validation == EContainerValidation::Disabled || Index < Count);
197 return Data[Index];
198 }
199
200 const T& operator[](size_t Index) const
201 {
202 AUTORTFM_ASSERT(Validation == EContainerValidation::Disabled || Index < Count);
203 return Data[Index];
204 }
205
206 T& Front()
207 {
208 AUTORTFM_ASSERT(Validation == EContainerValidation::Disabled || Count > 0);
209 return Data[0];
210 }
211
212 const T& Front() const
213 {
214 AUTORTFM_ASSERT(Validation == EContainerValidation::Disabled || Count > 0);
215 return Data[0];
216 }
217
218 T& Back()
219 {
220 AUTORTFM_ASSERT(Validation == EContainerValidation::Disabled || Count > 0);
221 return Data[Count - 1];
222 }
223
224 const T& Back() const
225 {
226 AUTORTFM_ASSERT(Validation == EContainerValidation::Disabled || Count > 0);
227 return Data[Count - 1];
228 }
229
230 T* begin() { return Data; }
231 const T* begin() const { return Data; }
232 T* end() { return Data + Count; }
233 const T* end() const { return Data + Count; }
234
235private:
236 // Copies the data from Other to this stack.
237 // This stack must be empty before calling.
238 void CopyFrom(const TStack& Other)
239 {
241 Reserve(Other.Count);
242 if constexpr (std::is_trivial_v<T>)
243 {
244 memcpy(Data, Other.Data, Other.Count * sizeof(T));
245 }
246 else
247 {
248 for (size_t I = 0, N = Other.Count; I < N; I++)
249 {
250 new (Data + I) T(Other.Data[I]);
251 }
252 }
253 Count = Other.Count;
254 }
255
256 // Moves the data from Other to this stack.
257 // This stack must be empty before calling.
258 void MoveFrom(TStack&& Other)
259 {
261 if (Other.Data == Other.InlineData())
262 {
263 if constexpr (std::is_trivial_v<T>)
264 {
265 memcpy(Data, Other.Data, Other.Count * sizeof(T));
266 }
267 else
268 {
269 for (size_t I = 0, N = Other.Count; I < N; I++)
270 {
271 new (Data + I) T(std::move(Other.Data[I]));
272 Other.Data[I].~T();
273 }
274 }
275 }
276 else
277 {
278 // Steal the heap allocation from Other.
279 Data = Other.Data;
280 Capacity = Other.Capacity;
281 }
282 Count = Other.Count;
283 Other.SetToInitialState();
284 }
285
286 // Sets Data, Capacity and Count to the initially default-constructed values.
287 // Warning: This does not free or destruct any elements held by this stack.
288 void SetToInitialState()
289 {
290 Data = InlineData();
291 Capacity = InlineCapacity;
292 Count = 0;
293 }
294
295 T* InlineData() { return reinterpret_cast<T*>(InlineDataBuffer); }
296 const T* InlineData() const { return reinterpret_cast<const T*>(InlineDataBuffer); }
297
298 alignas(T) std::byte InlineDataBuffer[sizeof(T) * InlineCapacity];
299 T* Data = reinterpret_cast<T*>(InlineDataBuffer);
300 size_t Capacity = InlineCapacity;
301 size_t Count = 0;
302};
303
304}
305
306#endif // (defined(__AUTORTFM) && __AUTORTFM)
UE_FORCEINLINE_HINT TSharedRef< CastToType, Mode > StaticCastSharedRef(TSharedRef< CastFromType, Mode > const &InSharedRef)
Definition SharedPointer.h:127
@ Num
Definition MetalRHIPrivate.h:234
memcpy(InputBufferBase, BinkBlocksData, BinkBlocksSize)
Definition API.cpp:57
GeometryCollection::Facades::FMuscleActivationData Data
Definition MuscleActivationConstraints.h:15
FORCEINLINE FStridedReferenceIterator begin(FStridedReferenceView View)
Definition FastReferenceCollector.h:490
FORCEINLINE FStridedReferenceIterator end(FStridedReferenceView View)
Definition FastReferenceCollector.h:491
U16 Index
Definition radfft.cpp:71