UDocumentation UE5.7 10.02.2026 (Source)
API documentation for Unreal Engine 5.7
EventLoopManagedStorage.h
Go to the documentation of this file.
1// Copyright Epic Games, Inc. All Rights Reserved.
2#pragma once
3
4#include "CoreTypes.h"
5#include "Containers/Map.h"
9#include "HAL/PlatformTLS.h"
11#include "Misc/Optional.h"
12#include "Stats/Stats.h"
13#include "Templates/Function.h"
14
15namespace UE::EventLoop {
16
18
20{
21 static constexpr TCHAR Name[] = TEXT("ManagedStorageDefault");
22};
23
25{
26 static inline uint32 GetCurrentThreadId()
27 {
29 }
30
31 static inline bool IsManagerThread(uint32 ManagerThreadId)
32 {
33 return ManagerThreadId == GetCurrentThreadId();
34 }
35
36 static inline void CheckNotInitialized(uint32 ManagerThreadId)
37 {
38 check(ManagerThreadId == 0);
39 }
40
41 static inline void CheckIsManagerThread(uint32 ManagerThreadId)
42 {
43 check(IsManagerThread(ManagerThreadId));
44 }
45};
46
47/*
48 * Default traits for managed storage. Traits are used to implement functionality which can be
49 * mocked to allow testing the class.
50 *
51 * In most cases the default traits can be used without modification.
52 */
75
80template <typename ElementType, typename Traits = FManagedStorageDefaultTraits>
81class TManagedStorage final : public FNoncopyable
82{
83public:
84 /*
85 * Handle which extends the external resource handle to allow O(1) access into the internal storage array.
86 */
87 template <typename ExternalHandleType>
89 {
94
97 : ExternalHandle()
98 , InternalIndex(INDEX_NONE)
99 {
100 }
101
108
110 bool IsValid() const
111 {
112 return ExternalHandle.IsValid();
113 }
114
117 {
118 ExternalHandle.Invalidate();
119 }
120
122 {
123 return ExternalHandle == Other.ExternalHandle;
124 }
125
127 {
128 return ExternalHandle != Other.ExternalHandle;
129 }
130
132 {
133 return GetTypeHash(InHandle.ExternalHandle);
134 }
135
136 FString ToString() const
137 {
138 return IsValid() ? FString::Printf(TEXT("Internal:[ext:%s, idx:%d]"), *ExternalHandle.ToString(), InternalIndex) : FString(TEXT("<invalid>"));
139 }
140
143 {
144 return ExternalHandle;
145 }
146
149 {
150 return InternalIndex;
151 }
152
153 private:
154 ExternalHandleType ExternalHandle;
155 int32 InternalIndex;
156 };
157
158 using FExternalHandle = typename Traits::FExternalHandle;
161
162private:
163 struct FAddRequest
164 {
166 ElementType Data;
167 };
168
169 struct FRemoveRequest
170 {
173 };
174
175 struct FStorageEntry
176 {
177 FInternalHandle InternalHandle;
178 ElementType Data;
179 };
180
181 using FStorageType = TSparseArray<FStorageEntry>;
182
184 FStorageType Storage;
185 /* Mapping of external handles to the array index of the element in Storage. */
186 TMap<FExternalHandle, int32> StorageHandleIndex;
188 TMpscQueue<FAddRequest> AddRequests;
190 TMpscQueue<FRemoveRequest> RemoveRequests;
195 TAtomic<uint32> ManagerThreadId;
196
197public:
199 : Storage()
200 , StorageHandleIndex()
201 , AddRequests()
202 , RemoveRequests()
203 , ManagerThreadId(0)
204 {
205 }
206
208 {
209 }
210
214 inline bool IsManagerThread() const
215 {
216 return Traits::IsManagerThread(ManagerThreadId);
217 }
218
224 void Init()
225 {
226 Traits::CheckNotInitialized(ManagerThreadId);
227 ManagerThreadId = Traits::GetCurrentThreadId();
228 }
229
242 {
244
245 Traits::CheckIsManagerThread(ManagerThreadId);
246
247 uint32 NumChanges = 0;
248
249 // Add new queued items.
250 if (OutAddedHandles)
251 {
252 FAddRequest AddRequest;
253 while (AddRequests.Dequeue(AddRequest))
254 {
255 OutAddedHandles->Add(AddImpl(AddRequest.Handle, MoveTemp(AddRequest.Data)));
256 ++NumChanges;
257 }
258 }
259 else
260 {
261 FAddRequest AddRequest;
262 while (AddRequests.Dequeue(AddRequest))
263 {
264 AddImpl(AddRequest.Handle, MoveTemp(AddRequest.Data));
265 ++NumChanges;
266 }
267 }
268
269 // Remove queued items.
271 {
272 FRemoveRequest RemoveRequest;
273 while (RemoveRequests.Dequeue(RemoveRequest))
274 {
275 OutRemovedHandles->Add(RemoveImpl(RemoveRequest.Handle, RemoveRequest.OnComplete));
276 ++NumChanges;
277 }
278 }
279 else
280 {
281 FRemoveRequest RemoveRequest;
282 while (RemoveRequests.Dequeue(RemoveRequest))
283 {
284 RemoveImpl(RemoveRequest.Handle, RemoveRequest.OnComplete);
285 ++NumChanges;
286 }
287 }
288
289 return NumChanges;
290 }
291
300 FExternalHandle Add(ElementType&& Data)
301 {
302 // Assign new handle for data.
303 FExternalHandle Handle(FExternalHandle::GenerateNewHandle);
304 AddRequests.Enqueue(FAddRequest{Handle, MoveTemp(Data)});
305 return Handle;
306 }
307
320
329 {
330 RemoveImpl(Handle.GetExternalHandle(), nullptr);
331 }
332
333public:
334 /*
335 * STORAGE ACCESS
336 *
337 * NOT thread safe.
338 */
339
340 inline int32 Num() const
341 {
342 CheckThreadForStorageAccess();
343 return Storage.Num();
344 }
345
346 inline bool IsEmpty() const
347 {
348 CheckThreadForStorageAccess();
349 return Storage.IsEmpty();
350 }
351
352 inline ElementType* Find(FExternalHandle Handle)
353 {
354 CheckThreadForStorageAccess();
355
356 // When using an external handle the internal index will be valid if present.
357 if (int32* InternalIndex = StorageHandleIndex.Find(Handle))
358 {
359 FStorageEntry& Entry = Storage[*InternalIndex];
360 return &Entry.Data;
361 }
362
363 return nullptr;
364 }
365
366 inline const ElementType* Find(FExternalHandle Handle) const
367 {
368 return const_cast<TManagedStorage*>(this)->Find(Handle);
369 }
370
371 inline ElementType* Find(FInternalHandle Handle)
372 {
373 CheckThreadForStorageAccess();
374
375 // When using an internal handle the index must be verified in case the handle is stale.
376 const int32 InternalIndex = Handle.GetInternalIndex();
377 if (Storage.IsValidIndex(InternalIndex))
378 {
379 // Check that the internal handle matches the expected value in case
380 // the slot in the array was reused.
381 FStorageEntry& Entry = Storage[InternalIndex];
382 return Entry.InternalHandle == Handle ? &Entry.Data : nullptr;
383 }
384
385 return nullptr;
386 }
387
388 inline const ElementType* Find(FInternalHandle Handle) const
389 {
390 return const_cast<TManagedStorage*>(this)->Find(Handle);
391 }
392
399 template <bool bConst>
401 {
402 private:
403 using TInternalIterator = typename FStorageType::TRangedForIterator;
404 using StorageIteratorType = std::conditional_t<bConst, typename FStorageType::TRangedForConstIterator, typename FStorageType::TRangedForIterator>;
405 using InternalElementType = std::conditional_t<bConst, const ElementType, ElementType>;
407
408 public:
409 explicit TBaseRangeForIterator(StorageIteratorType InStorageIterator)
410 : StorageIterator(InStorageIterator)
411 {
412 if (StorageIterator)
413 {
414 ElementAccess.Emplace(ItElementType{StorageIterator->InternalHandle, StorageIterator->Data});
415 }
416 }
417
419 {
420 ++StorageIterator;
421 if (StorageIterator)
422 {
423 ElementAccess.Emplace(ItElementType{StorageIterator->InternalHandle, StorageIterator->Data});
424 }
425 return *this;
426 }
427
428 inline bool operator==(const TBaseRangeForIterator& Rhs) const { return StorageIterator == Rhs.StorageIterator; }
429 inline bool operator!=(const TBaseRangeForIterator& Rhs) const { return StorageIterator != Rhs.StorageIterator; }
430
432 inline explicit operator bool() const
433 {
434 return !!StorageIterator;
435 }
436
438 inline bool operator !() const
439 {
440 return !(bool)*this;
441 }
442
443 inline ItElementType& operator*() const { return *ElementAccess; }
444 inline ItElementType* operator->() const { return &*ElementAccess; }
445
446 private:
447 StorageIteratorType StorageIterator;
448 mutable TOptional<ItElementType> ElementAccess;
449 };
450
453
455 {
456 CheckThreadForStorageAccess();
457 return TRangedForIterator(Storage.begin());
458 }
459
461 {
462 CheckThreadForStorageAccess();
463 return TRangedForConstIterator(Storage.begin());
464 }
465
467 {
468 CheckThreadForStorageAccess();
469 return TRangedForIterator(Storage.end());
470 }
471
473 {
474 CheckThreadForStorageAccess();
475 return TRangedForConstIterator(Storage.end());
476 }
477
478private:
479 inline void CheckThreadForStorageAccess() const
480 {
481 if constexpr (Traits::bStorageAccessThreadChecksEnabled)
482 {
483 Traits::CheckIsManagerThread(ManagerThreadId);
484 }
485 }
486
487 FInternalHandle AddImpl(const FExternalHandle Handle, ElementType&& Data)
488 {
489 FSparseArrayAllocationInfo Allocation = Storage.AddUninitialized();
491 new(Allocation) FStorageEntry{ InternalHandle, MoveTemp(Data)};
492 StorageHandleIndex.Add(Handle, Allocation.Index);
493 return InternalHandle;
494 }
495
497 {
498 int32 FoundIndex = INDEX_NONE;
499 FInternalHandle InternalHandle;
500 if (StorageHandleIndex.RemoveAndCopyValue(Handle, FoundIndex) && Storage.IsValidIndex(FoundIndex))
501 {
502 InternalHandle = Storage[FoundIndex].InternalHandle;
503 Storage.RemoveAt(FoundIndex);
504 }
505
506 if (OnComplete)
507 {
508 OnComplete();
509 }
510
511 return InternalHandle;
512 }
513};
514
515/* UE::EventLoop */ }
OODEFFUNC typedef void(OODLE_CALLBACK t_fp_OodleCore_Plugin_Free)(void *ptr)
#define check(expr)
Definition AssertionMacros.h:314
@ INDEX_NONE
Definition CoreMiscDefines.h:150
#define TEXT(x)
Definition Platform.h:1272
FPlatformTypes::TCHAR TCHAR
Either ANSICHAR or WIDECHAR, depending on whether the platform supports wide characters or the requir...
Definition Platform.h:1135
FPlatformTypes::int32 int32
A 32-bit signed integer.
Definition Platform.h:1125
#define QUICK_SCOPE_CYCLE_COUNTER(Stat)
Definition Stats.h:652
UE_FORCEINLINE_HINT TSharedRef< CastToType, Mode > StaticCastSharedRef(TSharedRef< CastFromType, Mode > const &InSharedRef)
Definition SharedPointer.h:127
OnComplete(MoveTemp(Response))
const bool
Definition NetworkReplayStreaming.h:178
UE_INTRINSIC_CAST UE_REWRITE constexpr std::remove_reference_t< T > && MoveTemp(T &&Obj) noexcept
Definition UnrealTemplate.h:520
int32 InternalIndex
Definition VulkanMemory.cpp:4036
uint32_t uint32
Definition binka_ue_file_header.h:6
Definition UnrealTemplate.h:321
Definition Array.h:670
Definition Atomic.h:538
Definition UnrealString.h.inl:34
Definition MpscQueue.h:18
TOptional< ElementType > Dequeue()
Definition MpscQueue.h:58
void Enqueue(ArgTypes &&... Args)
Definition MpscQueue.h:49
Definition ContainerAllocationPolicies.h:894
Definition SparseArray.h:524
Definition EventLoopManagedStorage.h:401
ItElementType * operator->() const
Definition EventLoopManagedStorage.h:444
bool operator!() const
Definition EventLoopManagedStorage.h:438
TBaseRangeForIterator(StorageIteratorType InStorageIterator)
Definition EventLoopManagedStorage.h:409
bool operator==(const TBaseRangeForIterator &Rhs) const
Definition EventLoopManagedStorage.h:428
TBaseRangeForIterator & operator++()
Definition EventLoopManagedStorage.h:418
ItElementType & operator*() const
Definition EventLoopManagedStorage.h:443
bool operator!=(const TBaseRangeForIterator &Rhs) const
Definition EventLoopManagedStorage.h:429
Definition EventLoopManagedStorage.h:82
TBaseRangeForIterator< false > TRangedForIterator
Definition EventLoopManagedStorage.h:451
void Remove(const FInternalHandle Handle)
Definition EventLoopManagedStorage.h:328
TManagedStorageInternalHandle< FExternalHandle > FInternalHandle
Definition EventLoopManagedStorage.h:159
TBaseRangeForIterator< true > TRangedForConstIterator
Definition EventLoopManagedStorage.h:452
ElementType * Find(FInternalHandle Handle)
Definition EventLoopManagedStorage.h:371
TManagedStorage()
Definition EventLoopManagedStorage.h:198
TRangedForIterator end()
Definition EventLoopManagedStorage.h:466
ElementType * Find(FExternalHandle Handle)
Definition EventLoopManagedStorage.h:352
typename Traits::FExternalHandle FExternalHandle
Definition EventLoopManagedStorage.h:158
TRangedForConstIterator begin() const
Definition EventLoopManagedStorage.h:460
TRangedForConstIterator end() const
Definition EventLoopManagedStorage.h:472
bool IsManagerThread() const
Definition EventLoopManagedStorage.h:214
~TManagedStorage()
Definition EventLoopManagedStorage.h:207
const ElementType * Find(FInternalHandle Handle) const
Definition EventLoopManagedStorage.h:388
bool IsEmpty() const
Definition EventLoopManagedStorage.h:346
uint32 Update(FInternalHandleArryType *OutAddedHandles=nullptr, FInternalHandleArryType *OutRemovedHandles=nullptr)
Definition EventLoopManagedStorage.h:241
void Init()
Definition EventLoopManagedStorage.h:224
TRangedForIterator begin()
Definition EventLoopManagedStorage.h:454
void Remove(const FExternalHandle Handle, FManagedStorageOnRemoveComplete &&OnRemoveComplete=FManagedStorageOnRemoveComplete())
Definition EventLoopManagedStorage.h:316
const ElementType * Find(FExternalHandle Handle) const
Definition EventLoopManagedStorage.h:366
FExternalHandle Add(ElementType &&Data)
Definition EventLoopManagedStorage.h:300
int32 Num() const
Definition EventLoopManagedStorage.h:340
Definition EventLoopLog.cpp:5
TUniqueFunction< void()> FManagedStorageOnRemoveComplete
Definition EventLoopManagedStorage.h:17
static uint32 GetCurrentThreadId(void)
Definition AndroidPlatformTLS.h:20
Definition SparseArray.h:31
int32 Index
Definition SparseArray.h:32
Definition Optional.h:131
Definition Tuple.h:652
Definition EventLoopManagedStorage.h:20
static constexpr TCHAR Name[]
Definition EventLoopManagedStorage.h:21
Definition EventLoopManagedStorage.h:54
static constexpr bool bStorageAccessThreadChecksEnabled
Definition EventLoopManagedStorage.h:68
Definition EventLoopManagedStorage.h:25
static uint32 GetCurrentThreadId()
Definition EventLoopManagedStorage.h:26
static bool IsManagerThread(uint32 ManagerThreadId)
Definition EventLoopManagedStorage.h:31
static void CheckIsManagerThread(uint32 ManagerThreadId)
Definition EventLoopManagedStorage.h:41
static void CheckNotInitialized(uint32 ManagerThreadId)
Definition EventLoopManagedStorage.h:36
TManagedStorageInternalHandle(EGenerateNewHandleType, ExternalHandleType InExternalHandle, int32 InInternalIndex)
Definition EventLoopManagedStorage.h:103
int32 GetInternalIndex() const
Definition EventLoopManagedStorage.h:148
bool IsValid() const
Definition EventLoopManagedStorage.h:110
bool operator!=(const TManagedStorageInternalHandle &Other) const
Definition EventLoopManagedStorage.h:126
FString ToString() const
Definition EventLoopManagedStorage.h:136
EGenerateNewHandleType
Definition EventLoopManagedStorage.h:91
@ GenerateNewHandle
Definition EventLoopManagedStorage.h:92
ExternalHandleType GetExternalHandle() const
Definition EventLoopManagedStorage.h:142
bool operator==(const TManagedStorageInternalHandle &Other) const
Definition EventLoopManagedStorage.h:121
void Invalidate()
Definition EventLoopManagedStorage.h:116
friend uint32 GetTypeHash(const TManagedStorageInternalHandle &InHandle)
Definition EventLoopManagedStorage.h:131
TManagedStorageInternalHandle()
Definition EventLoopManagedStorage.h:96
Definition EventLoopHandle.h:12