UDocumentation UE5.7 10.02.2026 (Source)
API documentation for Unreal Engine 5.7
IndexedHandle.h
Go to the documentation of this file.
1// Copyright Epic Games, Inc. All Rights Reserved.
2
3#pragma once
4
5#include "CoreMinimal.h"
6#include "Containers/Array.h"
7#include <atomic>
8#include "IndexedHandle.generated.h"
9
10#if !(UE_BUILD_SHIPPING || UE_BUILD_TEST)
11#define UE_DO_INDEXED_HANDLE_MANAGER_ID 1
12#else
13#define UE_DO_INDEXED_HANDLE_MANAGER_ID 0
14#endif
15
16
21USTRUCT()
23{
25
27
32
34 {
35 return Index == Other.Index;
36 }
37
39 {
40 return !operator==(Other);
41 }
42
44 int32 GetIndex() const { return Index; }
45
47 bool IsValid() const { return Index >= 0; }
48
54 operator bool() const { return IsValid(); }
55
58
61 {
62 Index = InIndex;
63 }
64
66 {
67 return static_cast<uint32>(Handle.GetIndex());
68 }
69
70protected:
72};
73
75USTRUCT()
77{
79
80 FIndexedHandleBase() = default;
81
86
88 {
89 return FSimpleIndexedHandleBase::operator==(Other) && SerialNumber == Other.SerialNumber;
90 }
91
93 {
94 return !operator==(Other);
95 }
96
97 uint32 GetSerialNumber() const { return SerialNumber; }
99
101 {
102 return HashCombine(static_cast<uint32>(Handle.GetIndex()), Handle.GetSerialNumber());
103 }
104
105protected:
106 uint32 SerialNumber = 0;
107
108#if UE_DO_INDEXED_HANDLE_MANAGER_ID
109public:
110 uint32 ManagerID = 0;
111#endif
112};
113
115USTRUCT()
117{
119
121
131
133 {
134 return Index == Other.Index && SerialNumber == Other.SerialNumber;
135 }
136
138 {
139 return !operator==(Other);
140 }
141
143 int16 GetIndex() const { return Index; }
144
146 bool IsValid() const { return Index >= 0; }
147
153 operator bool() const { return IsValid(); }
154
157
160 {
161 Index = InIndex;
162 }
163
164 uint16 GetSerialNumber() const { return SerialNumber; }
166
168 {
169 return (static_cast<uint32>(Handle.GetIndex()) << 16) + static_cast<uint32>(Handle.GetSerialNumber());
170 }
171
172protected:
174 uint16 SerialNumber = 0;
175
176#if UE_DO_INDEXED_HANDLE_MANAGER_ID
177public:
178 uint32 ManagerID = 0;
179#endif
180};
181
187template<typename TIndexedHandle, typename TIndexType, typename TSerialType, bool bOptimizeHandleReuse = false>
189{
190protected:
192
193public:
195 {
196#if UE_DO_INDEXED_HANDLE_MANAGER_ID
197 ManagerID = ManagerIDCounter.fetch_add(1);
198#endif
199 }
200
202 {
203 TIndexedHandle* Handle = nullptr;
204
205 //if no free handle indices then create one
206 if (FreeHandleIndices.Num() == 0)
207 {
208 checkf(Handles.Num() <= static_cast<typename FHandleArray::SizeType>(TNumericLimits<TIndexType>::Max()), TEXT("Handles are overflowing the numeric limits of the handle TIndexType!"));
210 }
211 else //otherwise use an existing handle index
212 {
213 const TIndexType Idx = FreeHandleIndices.Pop();
214 Handle = &Handles[Idx];
215 checkf(!Handle->IsValid(), TEXT("Free handle must be set invalid before reuse"));
216 Handle->SetIndex(Idx);
217 Handle->SetSerialNumber(SerialNumberCounter.fetch_add(1));
218 }
219
220#if UE_DO_INDEXED_HANDLE_MANAGER_ID
221 Handle->ManagerID = ManagerID;
222#endif
223
224 return *Handle;
225 }
226
228 {
229 const bool bIsValid = IsValidHandle(IndexedHandle);
230
231 if (ensureMsgf(bIsValid, TEXT("Trying to Remove Invalid Handle with Index %d, Serial Number %d"), IndexedHandle.GetIndex(), IndexedHandle.GetSerialNumber()))
232 {
233 if constexpr (bOptimizeHandleReuse)
234 {
235 const TIndexType Idx = IndexedHandle.GetIndex();
236 const int32 InsertPosition = Algo::LowerBound(FreeHandleIndices, Idx, [](const TIndexType& Lhs, const TIndexType& Rhs) {return Lhs > Rhs;});
238 }
239 else
240 {
242 }
243
244 Handles[IndexedHandle.GetIndex()].Invalidate();
245
246 //increase the serial numbers when a handle is removed
247 Handles[IndexedHandle.GetIndex()].SetSerialNumber(SerialNumberCounter.fetch_add(1));
248 }
249
250 return bIsValid;
251 }
252
254 {
255#if UE_DO_INDEXED_HANDLE_MANAGER_ID
256 if (!ensureMsgf(ManagerID == IndexedHandle.ManagerID, TEXT("ManagerID %d does not match IndexedHandle.ManagerID %d, handles must only be used by the same manager they were created by!"), ManagerID, IndexedHandle.ManagerID))
257 {
258 return false;
259 }
260#endif // UE_DO_INDEXED_HANDLE_MANAGER_ID
261
262 return ((IndexedHandle.GetIndex() >= 0) && (IndexedHandle.GetIndex() < Handles.Num())
263 && (IndexedHandle.GetSerialNumber() == Handles[IndexedHandle.GetIndex()].GetSerialNumber())
264 && (IndexedHandle.GetIndex() == Handles[IndexedHandle.GetIndex()].GetIndex()));
265 }
266
267 const TArray<TIndexedHandle>& GetHandles() const { return Handles; }
268
271
272 // Defaulted copy constructor, but it acts differently from the copy assignment operator - notably, doesn't allocate a new ManagerID.
274
276 {
277 Handles = Other.Handles;
278 FreeHandleIndices = Other.FreeHandleIndices;
279 //Leave SerialNumberCounter well alone
280
281#if UE_DO_INDEXED_HANDLE_MANAGER_ID
282 //assign new ManagerID to the new Manager
283 ManagerID = ManagerIDCounter.fetch_add(1);
284#endif // UE_DO_INDEXED_HANDLE_MANAGER_ID
285 return *this;
286 }
287
292 {
293 while (Handles.Num() > 0 && FreeHandleIndices.Num() > 0 && FreeHandleIndices.Remove(Handles.Num() - 1))
294 {
296 }
297
298 return Handles.Num();
299 }
300
301
302 void Reset()
303 {
304 Handles.Reset();
306 //Don't reset the SerialNumberCounter as we need that to increase from where it left off to keep handle consistency
307 }
308
309protected:
313
314 static std::atomic<TSerialType> SerialNumberCounter;
315
316#if UE_DO_INDEXED_HANDLE_MANAGER_ID
318 static std::atomic<uint32> ManagerIDCounter;
320#endif // UE_DO_INDEXED_HANDLE_MANAGER_ID
321};
322
323template<typename TIndexedHandle, typename TIndexType, typename TSerialType, bool bOptimizeHandleReuse>
325
326#if UE_DO_INDEXED_HANDLE_MANAGER_ID
327template<typename TIndexedHandle, typename TIndexType, typename TSerialType, bool bOptimizeHandleReuse>
329#endif // UE_DO_INDEXED_HANDLE_MANAGER_ID
330
331template<typename TIndexedHandle, bool bOptimizeHandleReuse = false>
332struct FIndexedHandleManager : public FIndexedHandleManagerBase<TIndexedHandle, int32, uint32, bOptimizeHandleReuse>
333{
334};
335
336template<typename TIndexedHandle, bool bOptimizeHandleReuse = false>
337struct FCompactIndexedHandleManager : public FIndexedHandleManagerBase<TIndexedHandle, int16, uint16, bOptimizeHandleReuse>
338{
339};
#define check(expr)
Definition AssertionMacros.h:314
#define ensureMsgf( InExpression, InFormat,...)
Definition AssertionMacros.h:465
#define checkf(expr, format,...)
Definition AssertionMacros.h:315
@ INDEX_NONE
Definition CoreMiscDefines.h:150
FPlatformTypes::int16 int16
A 16-bit signed integer.
Definition Platform.h:1123
#define TEXT(x)
Definition Platform.h:1272
FPlatformTypes::int32 int32
A 32-bit signed integer.
Definition Platform.h:1125
UE_FORCEINLINE_HINT TSharedRef< CastToType, Mode > StaticCastSharedRef(TSharedRef< CastFromType, Mode > const &InSharedRef)
Definition SharedPointer.h:127
const bool
Definition NetworkReplayStreaming.h:178
#define MAX_int16
Definition NumericLimits.h:24
#define MAX_uint16
Definition NumericLimits.h:20
#define GENERATED_BODY(...)
Definition ObjectMacros.h:765
#define USTRUCT(...)
Definition ObjectMacros.h:746
constexpr uint32 HashCombine(uint32 A, uint32 C)
Definition TypeHash.h:36
uint16_t uint16
Definition binka_ue_file_header.h:7
uint32_t uint32
Definition binka_ue_file_header.h:6
Definition Array.h:670
SizeType Remove(const ElementType &Item)
Definition Array.h:3091
UE_REWRITE SizeType Num() const
Definition Array.h:1144
void Reset(SizeType NewSize=0)
Definition Array.h:2246
typename InAllocatorType::SizeType SizeType
Definition Array.h:675
UE_FORCEINLINE_HINT ElementType & Emplace_GetRef(ArgsType &&... Args) UE_LIFETIMEBOUND
Definition Array.h:2613
UE_NODEBUG UE_FORCEINLINE_HINT SizeType Add(ElementType &&Item)
Definition Array.h:2696
ElementType Pop(EAllowShrinking AllowShrinking=UE::Core::Private::AllowShrinkingByDefault< AllocatorType >())
Definition Array.h:1196
SizeType Insert(std::initializer_list< ElementType > InitList, const SizeType InIndex)
Definition Array.h:1875
UE_REWRITE auto LowerBound(const RangeType &Range, const ValueType &Value, SortPredicateType SortPredicate) -> decltype(GetNum(Range))
Definition BinarySearch.h:92
U16 Index
Definition radfft.cpp:71
Definition IndexedHandle.h:117
int16 GetIndex() const
Definition IndexedHandle.h:143
void SetSerialNumber(int16 InSerialNumber)
Definition IndexedHandle.h:165
bool operator==(const FCompactIndexedHandleBase &Other) const
Definition IndexedHandle.h:132
friend uint32 GetTypeHash(const FCompactIndexedHandleBase &Handle)
Definition IndexedHandle.h:167
bool IsValid() const
Definition IndexedHandle.h:146
uint16 GetSerialNumber() const
Definition IndexedHandle.h:164
bool operator!=(const FCompactIndexedHandleBase &Other) const
Definition IndexedHandle.h:137
void Invalidate()
Definition IndexedHandle.h:156
void SetIndex(int16 InIndex)
Definition IndexedHandle.h:159
Definition IndexedHandle.h:338
Definition IndexedHandle.h:77
friend uint32 GetTypeHash(const FIndexedHandleBase &Handle)
Definition IndexedHandle.h:100
uint32 GetSerialNumber() const
Definition IndexedHandle.h:97
bool operator==(const FIndexedHandleBase &Other) const
Definition IndexedHandle.h:87
bool operator!=(const FIndexedHandleBase &Other) const
Definition IndexedHandle.h:92
void SetSerialNumber(uint32 InSerialNumber)
Definition IndexedHandle.h:98
Definition IndexedHandle.h:189
const TArray< TIndexedHandle > & GetHandles() const
Definition IndexedHandle.h:267
FIndexedHandleManagerBase & operator=(const FIndexedHandleManagerBase &Other)
Definition IndexedHandle.h:275
TIndexedHandle GetNextHandle()
Definition IndexedHandle.h:201
FIndexedHandleManagerBase()
Definition IndexedHandle.h:194
int32 ShrinkHandles()
Definition IndexedHandle.h:291
FIndexedHandleManagerBase(const FIndexedHandleManagerBase &Other)=default
bool IsValidHandle(TIndexedHandle IndexedHandle) const
Definition IndexedHandle.h:253
int32 CalcNumUsedHandles() const
Definition IndexedHandle.h:270
bool RemoveHandle(TIndexedHandle IndexedHandle)
Definition IndexedHandle.h:227
static std::atomic< uint32 > ManagerIDCounter
Definition IndexedHandle.h:318
FHandleArray Handles
Definition IndexedHandle.h:311
TArray< TIndexedHandle > FHandleArray
Definition IndexedHandle.h:191
uint32 ManagerID
Definition IndexedHandle.h:319
TArray< TIndexType > FreeHandleIndices
Definition IndexedHandle.h:312
static std::atomic< TSerialType > SerialNumberCounter
Definition IndexedHandle.h:314
void Reset()
Definition IndexedHandle.h:302
Definition IndexedHandle.h:333
Definition IndexedHandle.h:23
bool operator!=(const FSimpleIndexedHandleBase &Other) const
Definition IndexedHandle.h:38
bool operator==(const FSimpleIndexedHandleBase &Other) const
Definition IndexedHandle.h:33
void SetIndex(int32 InIndex)
Definition IndexedHandle.h:60
void Invalidate()
Definition IndexedHandle.h:57
bool IsValid() const
Definition IndexedHandle.h:47
friend uint32 GetTypeHash(const FSimpleIndexedHandleBase &Handle)
Definition IndexedHandle.h:65
int32 GetIndex() const
Definition IndexedHandle.h:44
Definition NumericLimits.h:41