UDocumentation UE5.7 10.02.2026 (Source)
API documentation for Unreal Engine 5.7
ResizableCircularQueue.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"
7#include "Containers/Array.h"
10#include <type_traits>
11
19template<typename T, typename AllocatorT = FDefaultAllocator>
21{
22public:
23 typedef T ElementT;
24
26 explicit TResizableCircularQueue(SIZE_T InitialCapacity);
29
31 bool IsEmpty() const { return Head == Tail; }
32
34 SIZE_T Count() const { return Head - Tail; }
35
37 SIZE_T AllocatedCapacity() const { return Storage.Num(); }
38
40 void Enqueue(const ElementT& SrcData);
41
48
55
62
64 void Pop();
65
68
70 void PopNoCheck();
71
74
77
80
82 const ElementT& Peek() const { return PeekAtOffset(0); }
83
85 ElementT& Poke() { return PokeAtOffset(0); }
86
88 const ElementT& PeekAtOffsetNoCheck(SIZE_T Offset = 0) const { return Storage.GetData()[(Tail + Offset) & IndexMask]; }
89
91 ElementT& PokeAtOffsetNoCheck(SIZE_T Offset = 0) { return Storage.GetData()[(Tail + Offset) & IndexMask]; }
92
94 const ElementT& PeekNoCheck() const { return PeekAtOffsetNoCheck(0); }
95
97 void Trim();
98
100 void Reset();
101
103 void Empty();
104
105private:
106 enum : uint32
107 {
108 bConstructElements = (TIsPODType<T>::Value ? 0U : 1U),
109 bDestructElements = (std::is_trivially_destructible_v<T> ? 0U : 1U),
110 };
111
112#if WITH_DEV_AUTOMATION_TESTS
114#endif
115
116 // Resize buffer maintaining validity of stored data.
117 void SetCapacity(SIZE_T NewCapacity);
118
119 typedef uint32 IndexT;
121
122 IndexT Head;
123 IndexT Tail;
124
125 IndexT IndexMask;
126 StorageT Storage;
127};
128
129
130template<typename T, typename AllocatorT>
132: Head(0u)
133, Tail(0u)
134, IndexMask(0u)
135{
136 // Capacity should be power of two, it will be rounded up but lets warn the user anyway in debug builds.
137 checkSlow((InitialCapacity & (InitialCapacity - 1)) == 0);
138 if (InitialCapacity > 0)
139 {
140 SetCapacity(InitialCapacity);
141 }
142}
143
144template<typename T, typename AllocatorT>
146{
147 PopNoCheck(Count());
148 Storage.SetNumUnsafeInternal(0);
149}
150
151template<typename T, typename AllocatorT>
153{
154 const SIZE_T RequiredCapacity = Count() + 1;
155 if (RequiredCapacity > AllocatedCapacity())
156 {
157 // Capacity must be power of two
158 SetCapacity(RequiredCapacity);
159 }
160
161 const IndexT MaskedIndex = Head++ & IndexMask;
162 T* DstData = Storage.GetData() + MaskedIndex;
163 new (DstData) T(SrcData);
164}
165
166template<typename T, typename AllocatorT>
168{
169 const SIZE_T RequiredCapacity = Count() + 1;
170 if (RequiredCapacity > AllocatedCapacity())
171 {
172 // Capacity must be power of two
173 SetCapacity(RequiredCapacity);
174 }
175
176 const IndexT MaskedIndex = Head++ & IndexMask;
177 T* DstData = Storage.GetData() + MaskedIndex;
178 new (DstData) T();
179
180 return *DstData;
181}
182
183template<typename T, typename AllocatorT>
185{
186 const SIZE_T RequiredCapacity = Count() + 1;
187 if (RequiredCapacity > AllocatedCapacity())
188 {
189 // Capacity must be power of two
190 SetCapacity(RequiredCapacity);
191 }
192
193 const IndexT MaskedIndex = Head++ & IndexMask;
194 T* DstData = Storage.GetData() + MaskedIndex;
195 if (bConstructElements)
196 {
197 new (DstData) T();
198 }
199
200 return *DstData;
201}
202
203template<typename T, typename AllocatorT>
208
209template<typename T, typename AllocatorT>
210void
212{
213 if (ensure(Count() >= PopCount))
214 {
215 PopNoCheck(PopCount);
216 }
217}
218
219template<typename T, typename AllocatorT>
221{
222 if (ensure(Count() > 0))
223 {
224 PopNoCheck();
225 }
226}
227
228template<typename T, typename AllocatorT>
230{
231 if (bDestructElements)
232 {
233 const IndexT MaskedIndex = Tail & IndexMask;
234 T* Data = Storage.GetData() + MaskedIndex;
235 DestructItem(Data);
236 }
237
238 ++Tail;
239}
240
241template<typename T, typename AllocatorT>
243{
244 if (bDestructElements)
245 {
246 const IndexT MaskedTailStart = Tail & IndexMask;
247 const IndexT MaskedTailEnd = (Tail + Count) & IndexMask;
248
249 if ((Count > 0) & (MaskedTailStart >= MaskedTailEnd))
250 {
251 T* Data = Storage.GetData();
252 const SIZE_T FirstDestructCount = (Storage.Num() - MaskedTailStart);
255 }
256 else
257 {
258 T* Data = Storage.GetData() + MaskedTailStart;
259 DestructItems(Data, Count);
260 }
261 }
262
264 Tail += (IndexT)Count;
265}
266
267template<typename T, typename AllocatorT>
269{
270 using SizeType = typename StorageT::SizeType;
271
272 SIZE_T NewCapacity = FMath::RoundUpToPowerOfTwo64(RequiredCapacity);
273
274 if ((NewCapacity == Storage.Num()) || (NewCapacity < Count()))
275 {
276 return;
277 }
278
279 if (Storage.Num() > 0)
280 {
281 StorageT NewStorage;
282 NewStorage.Empty(static_cast<SizeType>(NewCapacity));
283
284 // copy data to new storage
285 const IndexT MaskedTail = Tail & IndexMask;
286 const IndexT MaskedHead = Head & IndexMask;
287
288 const ElementT* SrcData = Storage.GetData();
289 const SIZE_T SrcCapacity = Storage.Num();
290 const SIZE_T SrcSize = Count();
291 ElementT* DstData = NewStorage.GetData();
292
293 // MaskedTail will be equal to MaskedHead both when the queue is full and when it is empty.
294 if ((SrcSize > 0) & (MaskedTail >= MaskedHead))
295 {
297 NewStorage.Append(SrcData + MaskedTail, static_cast<SizeType>(CopyCount));
298 NewStorage.Append(SrcData, MaskedHead);
299 }
300 else
301 {
302 NewStorage.Append(SrcData + MaskedTail, static_cast<SizeType>(SrcSize));
303 }
304
305 NewStorage.AddUninitialized(static_cast<SizeType>(NewCapacity - SrcSize));
306
307 this->Storage = MoveTemp(NewStorage);
308 IndexMask = static_cast<IndexT>(NewCapacity - 1);
309 Tail = 0u;
310 Head = static_cast<IndexT>(SrcSize);
311 }
312 else
313 {
314 IndexMask = static_cast<IndexT>(NewCapacity - 1);
315 Storage.AddUninitialized(static_cast<SizeType>(NewCapacity));
316 }
317}
318
319template<typename T, typename AllocatorT>
321{
322 if (IsEmpty())
323 {
324 Empty();
325 }
326 else
327 {
328 SetCapacity(Count());
329 }
330}
331
332template<typename T, typename AllocatorT>
334{
335 PopNoCheck(Count());
336 Head = 0;
337 Tail = 0;
338}
339
340template<typename T, typename AllocatorT>
342{
343 PopNoCheck(Count());
344 Head = 0;
345 Tail = 0;
346 IndexMask = IndexT(-1);
347
348 // We've already destructed items. We just want to free the memory.
349 Storage.SetNumUnsafeInternal(0);
350 Storage.Empty();
351}
352
353#if UE_ENABLE_INCLUDE_ORDER_DEPRECATED_IN_5_5
355#endif
#define checkSlow(expr)
Definition AssertionMacros.h:332
#define check(expr)
Definition AssertionMacros.h:314
#define ensure( InExpression)
Definition AssertionMacros.h:464
FPlatformTypes::SIZE_T SIZE_T
An unsigned integer the same size as a pointer, the same as UPTRINT.
Definition Platform.h:1150
FORCEINLINE constexpr void DestructItem(ElementType *Element)
Definition MemoryOps.h:56
FORCEINLINE constexpr void DestructItems(ElementType *Element, SizeType Count)
Definition MemoryOps.h:81
UE_FORCEINLINE_HINT TSharedRef< CastToType, Mode > StaticCastSharedRef(TSharedRef< CastFromType, Mode > const &InSharedRef)
Definition SharedPointer.h:127
UE_INTRINSIC_CAST UE_REWRITE constexpr std::remove_reference_t< T > && MoveTemp(T &&Obj) noexcept
Definition UnrealTemplate.h:520
uint32 Offset
Definition VulkanMemory.cpp:4033
uint32_t uint32
Definition binka_ue_file_header.h:6
Definition Array.h:670
UE_REWRITE SizeType Num() const
Definition Array.h:1144
UE_NODEBUG UE_FORCEINLINE_HINT ElementType * GetData() UE_LIFETIMEBOUND
Definition Array.h:1027
Definition ResizableCircularQueue.h:21
const ElementT & PeekAtOffset(SIZE_T Offset=0) const
Definition ResizableCircularQueue.h:76
const ElementT & Peek() const
Definition ResizableCircularQueue.h:82
~TResizableCircularQueue()
Definition ResizableCircularQueue.h:145
void Reset()
Definition ResizableCircularQueue.h:333
T ElementT
Definition ResizableCircularQueue.h:23
bool IsEmpty() const
Definition ResizableCircularQueue.h:31
ElementT & Poke()
Definition ResizableCircularQueue.h:85
ElementT & PokeAtOffset(SIZE_T Offset=0)
Definition ResizableCircularQueue.h:79
TResizableCircularQueue()
Definition ResizableCircularQueue.h:27
void PopNoCheck(SIZE_T Count)
Definition ResizableCircularQueue.h:242
SIZE_T AllocatedCapacity() const
Definition ResizableCircularQueue.h:37
const ElementT & PeekNoCheck() const
Definition ResizableCircularQueue.h:94
void Pop(SIZE_T Count)
Definition ResizableCircularQueue.h:211
ElementT & PokeAtOffsetNoCheck(SIZE_T Offset=0)
Definition ResizableCircularQueue.h:91
void Empty()
Definition ResizableCircularQueue.h:341
SIZE_T Count() const
Definition ResizableCircularQueue.h:34
ElementT & Enqueue_GetRef()
Definition ResizableCircularQueue.h:184
ElementT & EnqueueDefaulted_GetRef()
Definition ResizableCircularQueue.h:167
const ElementT & PeekAtOffsetNoCheck(SIZE_T Offset=0) const
Definition ResizableCircularQueue.h:88
TResizableCircularQueue(SIZE_T InitialCapacity)
Definition ResizableCircularQueue.h:131
void Enqueue(const ElementT &SrcData)
Definition ResizableCircularQueue.h:152
ElementT & Enqueue()
Definition ResizableCircularQueue.h:204
void Trim()
Definition ResizableCircularQueue.h:320
void PopNoCheck()
Definition ResizableCircularQueue.h:229
void Pop()
Definition ResizableCircularQueue.h:220
Definition IsPODType.h:12
Definition NumericLimits.h:41