UDocumentation UE5.7 10.02.2026 (Source)
API documentation for Unreal Engine 5.7
UObjectAnnotation.h
Go to the documentation of this file.
1// Copyright Epic Games, Inc. All Rights Reserved.
2
3/*=============================================================================
4 UObjectAnnotation.h: Unreal object annotation template
5=============================================================================*/
6
7#pragma once
8
9#include "AutoRTFM.h"
12#include "Misc/ScopeExit.h"
13#include "Misc/ScopeLock.h"
14#include "Misc/ScopeRWLock.h"
17
31template<typename TAnnotation, bool bAutoRemove>
33{
34public:
35
42 virtual void NotifyUObjectDeleted(const UObjectBase *Object, int32 Index) override
43 {
44#if !(UE_BUILD_SHIPPING || UE_BUILD_TEST)
45 if (!bAutoRemove)
46 {
48 // in this case we are only verifying that the external assurances of removal are met
50 }
51 else
52#endif
53 {
55 }
56 }
57
63
68 {
69 // default constructor is required to be default annotation
70 check(AnnotationCacheValue.IsDefault());
71 }
72
77 {
78#if UE_AUTORTFM
80 {
81 AutoRTFM::EContextStatus Status = AutoRTFM::Close([this]
82 {
83 AutoRTFM::PopOnCommitHandler(this);
84 });
85 checkSlow(Status == AutoRTFM::EContextStatus::OnTrack);
86 }
87#endif
89 }
90
91private:
92 template<typename T>
93 void AddAnnotationInternal(const UObjectBase* Object, T&& Annotation)
94 {
96 bool bProcessRegistration = false;
98 if (LocalAnnotation.IsDefault())
99 {
100 RemoveAnnotation(Object); // adding the default annotation is the same as removing an annotation
101 }
102 else
103 {
105 const bool bWasEmpty = (AnnotationMap.Num() == 0);
106
108 SetAnnotationCacheKeyAndValue(Object, MoveTemp(LocalAnnotation));
109
110 if (bWasEmpty)
111 {
112 // we are adding the first one, so if we are auto removing or verifying removal, register now
113#if (UE_BUILD_SHIPPING || UE_BUILD_TEST)
114 if (bAutoRemove)
115#endif
116 {
118 }
119 }
120 }
121
123 {
124 ProcessRegistration();
125 }
126 }
127
128 void ProcessRegistration()
129 {
130 // Always take the UObjectDeleteListeners mutex first to preserve lock order in all case
131 // and avoid deadlock. This is important because we need to follow this lock flow :
132 // ConditionalFinishDestroy -> RemoveObjectFromDeleteListeners (UObjectDeleteListenersCritical) -> NotifyUObjectDeleted -> RemoveAnnotation (AnnotationMapCritical)
135 {
137 };
138
140 if (AnnotationMap.Num() == 0)
141 {
142 if (bRegistered)
143 {
145 bRegistered = false;
146 }
147 }
148 else
149 {
150 if (!bRegistered)
151 {
153 bRegistered = true;
154 }
155 }
156 }
157public:
164 void AddAnnotation(const UObjectBase* Object, TAnnotation&& Annotation)
165 {
166 AddAnnotationInternal(Object, MoveTemp(Annotation));
167 }
168
169 void AddAnnotation(const UObjectBase* Object, const TAnnotation& Annotation)
170 {
171 AddAnnotationInternal(Object, Annotation);
172 }
180 {
181 check(Object);
182 bool bProcessRegistration = false;
183
184 TAnnotation Result;
185 {
186 SetAnnotationCacheKeyAndValue(Object, TAnnotation());
187
189 const bool bHadElements = (AnnotationMap.Num() > 0);
190 AnnotationMap.RemoveAndCopyValue(Object, Result);
191 const bool bIsNowEmpty = (AnnotationMap.Num() == 0);
192
194 {
195 // we are removing the last one, so if we are auto removing or verifying removal, unregister now
196#if (UE_BUILD_SHIPPING || UE_BUILD_TEST)
197 if (bAutoRemove)
198#endif
199 {
201 }
202 }
203 }
204
206 {
207 ProcessRegistration();
208 }
209 return Result;
210 }
217 {
218 check(Object);
219 bool bProcessRegistration = false;
220
221 {
222 SetAnnotationCacheKeyAndValue(Object, TAnnotation());
223
225 const bool bHadElements = (AnnotationMap.Num() > 0);
226 AnnotationMap.Remove(Object);
227 const bool bIsNowEmpty = (AnnotationMap.Num() == 0);
228
230 {
231 // we are removing the last one, so if we are auto removing or verifying removal, unregister now
232#if (UE_BUILD_SHIPPING || UE_BUILD_TEST)
233 if (bAutoRemove)
234#endif
235 {
237 }
238 }
239 }
240
242 {
243 ProcessRegistration();
244 }
245 }
251 {
252 bool bProcessRegistration = false;
253
254 {
255 SetAnnotationCacheKeyAndValue(nullptr, TAnnotation());
256 const bool bHadElements = (AnnotationMap.Num() > 0);
258 AnnotationMap.Empty();
259
260 if (bHadElements)
261 {
262 // we are removing the last one, so if we are auto removing or verifying removal, unregister now
263#if (UE_BUILD_SHIPPING || UE_BUILD_TEST)
264 if (bAutoRemove)
265#endif
266 {
268 }
269 }
270 }
271
273 {
274 ProcessRegistration();
275 }
276 }
277
284 {
285 check(Object);
286
287
288 // If we are within a transaction, we don't touch the annotation cache, as it can be altered from the open.
289 // Look up the annotation directly from the map.
290 if (AutoRTFM::IsTransactional())
291 {
293 TAnnotation* Entry = AnnotationMap.Find(Object);
294 return Entry ? *Entry : TAnnotation();
295 }
296
297 {
298 // Check cache
301 {
303 }
304 }
305
306 // Update the cache if it isn't a match.
308 TAnnotation* Entry = AnnotationMap.Find(Object);
309 SetAnnotationCacheKeyAndValue(Object, Entry ? *Entry : TAnnotation());
310
311 return Entry ? *Entry : TAnnotation();
312 }
313
322
331
332 virtual SIZE_T GetAllocatedSize() const override
333 {
335 return AnnotationMap.GetAllocatedSize();
336 }
337
338private:
339 // Sets the AnnotationCacheKey and AnnotationCacheValue if called outside of
340 // an AutoRTFM transaction.
341 // This is a no-op in a transaction to avoid writes to the same memory locations
342 // from open and closed code. If a transaction is committed or aborted, we reset
343 // the cache to avoid reading back a stale value.
344 void SetAnnotationCacheKeyAndValue(const UObjectBase* Key, const TAnnotation& Value)
345 {
346 if (AutoRTFM::IsTransactional())
347 {
348 MaybeRegisterAutoRTFMHandlers();
349 }
350 else
351 {
355 }
356 }
357
358 void SetAnnotationCacheKeyAndValue(const UObjectBase* Key, TAnnotation&& Value)
359 {
360 if (AutoRTFM::IsTransactional())
361 {
362 MaybeRegisterAutoRTFMHandlers();
363 }
364 else
365 {
369 }
370 }
371
372 void MaybeRegisterAutoRTFMHandlers()
373 {
374#if UE_AUTORTFM
376 {
377 checkSlow(AutoRTFM::IsTransactional()); // Precondition: our caller should have checked this
378
379 AutoRTFM::EContextStatus Status = AutoRTFM::Close([this]
380 {
382
383 // We avoid touching the cache key and value within a transaction, so after a transaction completes,
384 // the cache value may be outdated. To avoid stale data, we null out the cache key at the end of a
385 // transaction. It will be automatically repopulated the next time GetAnnotation is called.
386 AutoRTFM::PushOnCommitHandler(this, [this]
387 {
388 AnnotationCacheKey = nullptr;
390 });
391 });
392
393 checkSlow(Status == AutoRTFM::EContextStatus::OnTrack);
394 }
395#endif
396 }
397
398protected:
404
409
415
420
424 bool bRegistered = false;
425
426#if UE_AUTORTFM
430 bool bRegisteredAutoRTFMHandlers = false;
431#endif
432};
433
434
445template<typename TAnnotation, bool bAutoRemove>
446class FUObjectAnnotationSparseSearchable : public FUObjectAnnotationSparse<TAnnotation, bAutoRemove>
447{
449public:
456 virtual void NotifyUObjectDeleted(const UObjectBase *Object, int32 Index) override
457 {
459 }
460
461 virtual void OnUObjectArrayShutdown() override
462 {
465 }
466
474
481 UObject* Find(const TAnnotation& Annotation)
482 {
483 UE::TScopeLock InverseAnnotationMapLock(InverseAnnotationMapCritical);
484 checkSlow(!Annotation.IsDefault()); // it is not legal to search for the default annotation
485 return (UObject*)InverseAnnotationMap.FindRef(Annotation);
486 }
487
488private:
489 template<typename T>
490 void AddAnnotationInternal(const UObjectBase* Object, T&& Annotation)
491 {
492 UE::TScopeLock InverseAnnotationMapLock(InverseAnnotationMapCritical);
493 if (Annotation.IsDefault())
494 {
495 RemoveAnnotation(Object); // adding the default annotation is the same as removing an annotation
496 }
497 else
498 {
500 int32 NumExistingRemoved = InverseAnnotationMap.Remove(ExistingAnnotation);
502
503 Super::AddAnnotation(Object, Annotation);
504 // should not exist in the mapping; we require uniqueness
505 int32 NumRemoved = InverseAnnotationMap.Remove(Annotation);
506 checkSlow(NumRemoved == 0);
507 InverseAnnotationMap.Add(Forward<T>(Annotation), Object);
508 }
509 }
510
511
512public:
513
520 void AddAnnotation(const UObjectBase* Object, const TAnnotation& Annotation)
521 {
522 AddAnnotationInternal(Object, Annotation);
523 }
524
525 void AddAnnotation(const UObjectBase* Object, TAnnotation&& Annotation)
526 {
527 AddAnnotationInternal(Object, MoveTemp(Annotation));
528 }
529
536 {
537 UE::TScopeLock InverseAnnotationMapLock(InverseAnnotationMapCritical);
538 TAnnotation Annotation = this->GetAndRemoveAnnotation(Object);
539 if (Annotation.IsDefault())
540 {
541 // should not exist in the mapping
542 checkSlow(!InverseAnnotationMap.Find(Annotation));
543 }
544 else
545 {
546 int32 NumRemoved = InverseAnnotationMap.Remove(Annotation);
547 checkSlow(NumRemoved == 1);
548 }
549 }
555 {
556 UE::TScopeLock InverseAnnotationMapLock(InverseAnnotationMapCritical);
558 InverseAnnotationMap.Empty();
559 }
560
561 virtual SIZE_T GetAllocatedSize() const override
562 {
563 return InverseAnnotationMap.GetAllocatedSize() + Super::GetAllocatedSize();
564 }
565private:
566
570 TMap<TAnnotation, const UObjectBase *> InverseAnnotationMap;
571 FTransactionallySafeCriticalSection InverseAnnotationMapCritical;
572};
573
574
576{
582 Mark(false)
583 {
584 }
590 Mark(InMark)
591 {
592 }
598 {
599 return !Mark;
600 }
601
605 bool Mark;
606
607};
608
609template <> struct TIsPODType<FBoolAnnotation> { enum { Value = true }; };
610
611
618class FUObjectAnnotationSparseBool : private FUObjectAnnotationSparse<FBoolAnnotation,true>
619{
620public:
627 {
628 this->AddAnnotation(Object,FBoolAnnotation(true));
629 }
636 {
637 this->RemoveAnnotation(Object);
638 }
639
645 {
646 this->RemoveAllAnnotations();
647 }
648
655 {
656 return this->GetAnnotation(Object).Mark;
657 }
658
666
668 {
669 return this->GetAnnotationMap().Num();
670 }
671};
672
688template<typename TAnnotation, bool bAutoRemove, int32 NumAnnotationsPerChunk = 64 * 1024>
690{
691 struct TAnnotationChunk
692 {
693 int32 Num;
694 TAnnotation* Items;
695
696 TAnnotationChunk()
697 : Num(0)
698 , Items(nullptr)
699 {}
700 };
701
702
706 int32 NumAnnotations;
708 int32 MaxAnnotations;
710 uint32 CurrentAllocatedMemory;
712 uint32 MaxAllocatedMemory;
713
715 FTransactionallySafeRWLock AnnotationArrayCritical;
716
720 void ExpandChunksToIndex(int32 Index) TSAN_SAFE
721 {
722 check(Index >= 0);
723 int32 ChunkIndex = Index / NumAnnotationsPerChunk;
724 if (ChunkIndex >= Chunks.Num())
725 {
726 Chunks.AddZeroed(ChunkIndex + 1 - Chunks.Num());
727 }
728 check(ChunkIndex < Chunks.Num());
729 MaxAnnotations = Chunks.Num() * NumAnnotationsPerChunk;
730 }
731
735 TAnnotation& AllocateAnnotation(int32 Index) TSAN_SAFE
736 {
737 ExpandChunksToIndex(Index);
738
739 const int32 ChunkIndex = Index / NumAnnotationsPerChunk;
741
742 TAnnotationChunk& Chunk = Chunks[ChunkIndex];
743 if (!Chunk.Items)
744 {
745 Chunk.Items = new TAnnotation[NumAnnotationsPerChunk];
746 CurrentAllocatedMemory += NumAnnotationsPerChunk * sizeof(TAnnotation);
747 MaxAllocatedMemory = FMath::Max(CurrentAllocatedMemory, MaxAllocatedMemory);
748 }
749 if (Chunk.Items[WithinChunkIndex].IsDefault())
750 {
751 Chunk.Num++;
752 check(Chunk.Num <= NumAnnotationsPerChunk);
753 NumAnnotations++;
754 }
755
756 return Chunk.Items[WithinChunkIndex];
757 }
758
762 void FreeAnnotation(int32 Index) TSAN_SAFE
763 {
764 const int32 ChunkIndex = Index / NumAnnotationsPerChunk;
766
767 if (ChunkIndex >= Chunks.Num())
768 {
769 return;
770 }
771
772 TAnnotationChunk& Chunk = Chunks[ChunkIndex];
773 if (!Chunk.Items)
774 {
775 return;
776 }
777
778 if (Chunk.Items[WithinChunkIndex].IsDefault())
779 {
780 return;
781 }
782
783 Chunk.Items[WithinChunkIndex] = TAnnotation();
784 Chunk.Num--;
785 check(Chunk.Num >= 0);
786 if (Chunk.Num == 0)
787 {
788 delete[] Chunk.Items;
789 Chunk.Items = nullptr;
791 check(CurrentAllocatedMemory >= ChunkMemory);
792 CurrentAllocatedMemory -= ChunkMemory;
793 }
794 NumAnnotations--;
795 check(NumAnnotations >= 0);
796 }
797
801 void FreeAllAnnotations() TSAN_SAFE
802 {
803 for (TAnnotationChunk& Chunk : Chunks)
804 {
805 delete[] Chunk.Items;
806 }
807 Chunks.Empty();
808 NumAnnotations = 0;
809 MaxAnnotations = 0;
810 CurrentAllocatedMemory = 0;
811 MaxAllocatedMemory = 0;
812 }
813
817 template<typename T>
818 void AddAnnotationInternal(int32 Index, T&& Annotation)
819 {
820 check(Index >= 0);
821 if (Annotation.IsDefault())
822 {
823 FreeAnnotation(Index); // adding the default annotation is the same as removing an annotation
824 }
825 else
826 {
827 if (NumAnnotations == 0 && Chunks.Num() == 0)
828 {
829 // we are adding the first one, so if we are auto removing or verifying removal, register now
830#if (UE_BUILD_SHIPPING || UE_BUILD_TEST)
831 if (bAutoRemove)
832#endif
833 {
835 }
836 }
837
838 TAnnotation& NewAnnotation = AllocateAnnotation(Index);
839 NewAnnotation = Forward<T>(Annotation);
840 }
841 }
842
843public:
844
847 : NumAnnotations(0)
848 , MaxAnnotations(0)
849 , CurrentAllocatedMemory(0)
850 , MaxAllocatedMemory(0)
851 {
852 }
853
858
859public:
860
867 void AddAnnotation(const UObjectBase *Object, const TAnnotation& Annotation)
868 {
869 check(Object);
871 }
872
873 void AddAnnotation(const UObjectBase* Object, TAnnotation&& Annotation)
874 {
875 check(Object);
877 }
878
885 void AddAnnotation(int32 Index, const TAnnotation& Annotation)
886 {
887 UE::TWriteScopeLock AnnotationArrayLock(AnnotationArrayCritical);
888 AddAnnotationInternal(Index, Annotation);
889 }
890
892 {
893 UE::TWriteScopeLock AnnotationArrayLock(AnnotationArrayCritical);
894 AddAnnotationInternal(Index, MoveTemp(Annotation));
895 }
896
909 {
910 UE::TWriteScopeLock AnnotationArrayLock(AnnotationArrayCritical);
911
912 if (NumAnnotations == 0 && Chunks.Num() == 0)
913 {
914 // we are adding the first one, so if we are auto removing or verifying removal, register now
915#if (UE_BUILD_SHIPPING || UE_BUILD_TEST)
916 if (bAutoRemove)
917#endif
918 {
920 }
921 }
922
923 ExpandChunksToIndex(Index);
924
925 const int32 ChunkIndex = Index / NumAnnotationsPerChunk;
927
928 TAnnotationChunk& Chunk = Chunks[ChunkIndex];
929 if (!Chunk.Items)
930 {
931 Chunk.Items = new TAnnotation[NumAnnotationsPerChunk];
932 CurrentAllocatedMemory += NumAnnotationsPerChunk * sizeof(TAnnotation);
933 MaxAllocatedMemory = FMath::Max(CurrentAllocatedMemory, MaxAllocatedMemory);
934 }
935 if (Chunk.Items[WithinChunkIndex].IsDefault())
936 {
937 Chunk.Num++;
938 check(Chunk.Num <= NumAnnotationsPerChunk);
939 NumAnnotations++;
940 Chunk.Items[WithinChunkIndex] = NewAnnotationFn();
941 check(!Chunk.Items[WithinChunkIndex].IsDefault());
942 }
943 return Chunk.Items[WithinChunkIndex];
944 }
945
962 {
963 UE::TWriteScopeLock AnnotationArrayLock(AnnotationArrayCritical);
964 FreeAnnotation(Index);
965 }
966
977
984 {
985 check(Index >= 0);
986
987 TAnnotation Result = TAnnotation();
988
990 {
991 UE::TReadScopeLock AnnotationArrayLock(AnnotationArrayCritical);
992
993 const int32 ChunkIndex = Index / NumAnnotationsPerChunk;
994 if (ChunkIndex < Chunks.Num())
995 {
997
998 TAnnotationChunk& Chunk = Chunks[ChunkIndex];
999 if (Chunk.Items != nullptr)
1000 {
1001 Result = Chunk.Items[WithinChunkIndex];
1002 }
1003 }
1004 };
1005
1006 return Result;
1007 }
1008
1015 {
1016 return NumAnnotations;
1017 }
1018
1025 {
1026 return MaxAnnotations;
1027 }
1028
1034 UE_DEPRECATED(5.3, "Use GetMaxAnnotations instead")
1036 {
1037 return MaxAnnotations;
1038 }
1039
1047 {
1048 return Index >= 0 && Index < MaxAnnotations;
1049 }
1050
1055 {
1056 bool bHadAnnotations = (NumAnnotations > 0);
1057 UE::TWriteScopeLock AnnotationArrayLock(AnnotationArrayCritical);
1058 FreeAllAnnotations();
1059 if (bHadAnnotations)
1060 {
1061 // we are removing the last one, so if we are auto removing or verifying removal, unregister now
1062#if (UE_BUILD_SHIPPING || UE_BUILD_TEST)
1063 if (bAutoRemove)
1064#endif
1065 {
1067 }
1068 }
1069 }
1070
1075 {
1076 UE::TWriteScopeLock AnnotationArrayLock(AnnotationArrayCritical);
1077 for (TAnnotationChunk& Chunk : Chunks)
1078 {
1079 if (Chunk.Num == 0 && Chunk.Items)
1080 {
1081 delete[] Chunk.Items;
1082 Chunk.Items = nullptr;
1083 const uint32 ChunkMemory = NumAnnotationsPerChunk * sizeof(TAnnotationChunk);
1084 check(CurrentAllocatedMemory >= ChunkMemory);
1085 CurrentAllocatedMemory -= ChunkMemory;
1086 }
1087 }
1088 }
1089
1091 virtual SIZE_T GetAllocatedSize() const override
1092 {
1093 SIZE_T AllocatedSize = Chunks.GetAllocatedSize();
1094 for (const TAnnotationChunk& Chunk : Chunks)
1095 {
1096 if (Chunk.Items)
1097 {
1098 AllocatedSize += NumAnnotationsPerChunk * sizeof(TAnnotation);
1099 }
1100 }
1101 return AllocatedSize;
1102 }
1103
1106 {
1107 return Chunks.GetAllocatedSize() + MaxAllocatedMemory;
1108 }
1109
1117 {
1118#if !(UE_BUILD_SHIPPING || UE_BUILD_TEST)
1119 if (!bAutoRemove)
1120 {
1121 // in this case we are only verifying that the external assurances of removal are met
1122 check(Index >= MaxAnnotations || GetAnnotation(Index).IsDefault());
1123 }
1124 else
1125#endif
1126 {
1128 }
1129 }
1130
1131 virtual void OnUObjectArrayShutdown() override
1132 {
1135 }
1136};
1137
1151template<typename TAnnotation, bool bAutoRemove>
1153{
1154public:
1155
1163 {
1164#if !(UE_BUILD_SHIPPING || UE_BUILD_TEST)
1165 if (!bAutoRemove)
1166 {
1167 // in this case we are only verifying that the external assurances of removal are met
1168 check(Index >= AnnotationArray.Num() || AnnotationArray[Index].IsDefault());
1169 }
1170 else
1171#endif
1172 {
1174 }
1175 }
1176
1177 virtual void OnUObjectArrayShutdown() override
1178 {
1181 }
1182
1187 {
1189 }
1190
1197 void AddAnnotation(const UObjectBase* Object, const TAnnotation& Annotation)
1198 {
1199 check(Object);
1201 }
1202
1203 void AddAnnotation(const UObjectBase* Object, TAnnotation&& Annotation)
1204 {
1205 check(Object);
1207 }
1208
1215 void AddAnnotation(int32 Index, const TAnnotation& Annotation)
1216 {
1217 bool bProcessRegistration = false;
1218 {
1219 UE::TRWScopeLock AnnotationArrayLock(AnnotationArrayCritical, SLT_Write);
1220 bProcessRegistration = AddAnnotationInternal(Index, Annotation);
1221 }
1222
1224 {
1225 ProcessRegistration();
1226 }
1227 }
1228
1230 {
1231 bool bProcessRegistration = false;
1232 {
1233 UE::TRWScopeLock AnnotationArrayLock(AnnotationArrayCritical, SLT_Write);
1234 bProcessRegistration = AddAnnotationInternal(Index, MoveTemp(Annotation));
1235 }
1236
1238 {
1239 ProcessRegistration();
1240 }
1241 }
1242
1243
1244private:
1245 void ProcessRegistration()
1246 {
1247 // Always take the UObjectDeleteListeners mutex first to preserve lock order in all case
1248 // and avoid deadlock. This is important because we need to follow this lock flow :
1249 // ConditionalFinishDestroy -> RemoveObjectFromDeleteListeners (UObjectDeleteListenersCritical) -> NotifyUObjectDeleted -> RemoveAnnotation (AnnotationMapCritical)
1252 {
1254 };
1255
1256 UE::TWriteScopeLock AnnotationMapLock(AnnotationArrayCritical);
1257 if (AnnotationArray.Num() == 0)
1258 {
1259 if (bRegistered)
1260 {
1262 bRegistered = false;
1263 }
1264 }
1265 else
1266 {
1267 if (!bRegistered)
1268 {
1270 bRegistered = true;
1271 }
1272 }
1273 }
1274
1275 template<typename T>
1276 [[nodiscard]] bool AddAnnotationInternal(int32 Index, T&& Annotation)
1277 {
1278 bool bProcessRegistration = false;
1279
1280 check(Index >= 0);
1281 if (Annotation.IsDefault())
1282 {
1283 RemoveAnnotationInternal(Index); // adding the default annotation is the same as removing an annotation
1284 }
1285 else
1286 {
1287 if (AnnotationArray.Num() == 0)
1288 {
1289 // we are adding the first one, so if we are auto removing or verifying removal, register now
1290#if (UE_BUILD_SHIPPING || UE_BUILD_TEST)
1291 if (bAutoRemove)
1292#endif
1293 {
1294 bProcessRegistration = true;
1295 }
1296 }
1297 if (Index >= AnnotationArray.Num())
1298 {
1299 int32 AddNum = 1 + Index - AnnotationArray.Num();
1300 int32 Start = AnnotationArray.AddUninitialized(AddNum);
1301 while (AddNum--)
1302 {
1303 new (AnnotationArray.GetData() + Start++) TAnnotation();
1304 }
1305 }
1306 AnnotationArray[Index] = Forward<T>(Annotation);
1307 }
1308
1309 return bProcessRegistration;
1310 }
1311
1312public:
1329 {
1330 UE::TRWScopeLock AnnotationArrayLock(AnnotationArrayCritical, SLT_Write);
1331 RemoveAnnotationInternal(Index);
1332 }
1333
1334private:
1335 void RemoveAnnotationInternal(int32 Index)
1336 {
1337 check(Index >= 0);
1338 if (Index < AnnotationArray.Num())
1339 {
1340 AnnotationArray[Index] = TAnnotation();
1341 }
1342 }
1343
1344public:
1350 {
1351 bool bProcessRegistration = false;
1352 {
1353 UE::TRWScopeLock AnnotationArrayLock(AnnotationArrayCritical, SLT_Write);
1354 bool bHadElements = (AnnotationArray.Num() > 0);
1355 AnnotationArray.Empty();
1356 if (bHadElements)
1357 {
1358 // we are removing the last one, so if we are auto removing or verifying removal, unregister now
1359#if (UE_BUILD_SHIPPING || UE_BUILD_TEST)
1360 if (bAutoRemove)
1361#endif
1362 {
1363 bProcessRegistration = true;
1364 }
1365 }
1366 }
1367
1368 ProcessRegistration();
1369 }
1370
1377 {
1378 check(Object);
1380 // Since we are potentially dealing with a corrupt ptr validation is broken into two checks.
1381 // First to tell if something is wrong and the second to try to provide
1382 // more information to the user (however in a potentially unsafe way by reading the ptr).
1383 ensureAlwaysMsgf(Index >= 0, TEXT("Corrupt object with negative Index passed to GetAnnotation: Index == %d"), Index);
1384 checkf(Index >= 0, TEXT("Failed GetAnnotation for Object '%s'"), *static_cast<const UObjectBaseUtility*>(Object)->GetPathName());
1385 return GetAnnotation(Index);
1386 }
1387
1394 {
1395 check(Index >= 0);
1396 UE::TRWScopeLock AnnotationArrayLock(AnnotationArrayCritical, SLT_ReadOnly);
1397 if (Index < AnnotationArray.Num())
1398 {
1399 return AnnotationArray[Index];
1400 }
1401 return TAnnotation();
1402 }
1403
1415
1424 {
1425 bool bProcessRegistration = false;
1426 {
1427 UE::TRWScopeLock AnnotationArrayLock(AnnotationArrayCritical, SLT_Write);
1428 if (Index >= AnnotationArray.Num())
1429 {
1430 bProcessRegistration = AddAnnotationInternal(Index, TAnnotation());
1431 }
1432 }
1433
1435 {
1436 ProcessRegistration();
1437 }
1438 return AnnotationArray[Index];
1439 }
1440
1442 virtual SIZE_T GetAllocatedSize() const override
1443 {
1444 return AnnotationArray.GetAllocatedSize();
1445 }
1446
1447private:
1448
1452 TArray<TAnnotation> AnnotationArray;
1453 FTransactionallySafeRWLock AnnotationArrayCritical;
1454
1458 bool bRegistered = false;
1459};
1460
1465{
1466 typedef uint32 TBitType;
1467 enum {BitsPerElement = sizeof(TBitType) * 8};
1468public:
1469
1477 {
1478 RemoveAnnotation(Index);
1479 }
1480
1481 virtual void OnUObjectArrayShutdown() override
1482 {
1483 RemoveAllAnnotations();
1485 }
1486
1491 {
1492 RemoveAllAnnotations();
1493 }
1494
1500 inline void Set(const UObjectBase *Object)
1501 {
1504 checkSlow(Index >= 0);
1505 if (AnnotationArray.Num() == 0)
1506 {
1508 }
1509 if (Index >= AnnotationArray.Num() * BitsPerElement)
1510 {
1511 int32 AddNum = 1 + Index - AnnotationArray.Num() * BitsPerElement;
1512 int32 AddElements = (AddNum + BitsPerElement - 1) / BitsPerElement;
1513 checkSlow(AddElements);
1514 AnnotationArray.AddZeroed(AddElements);
1515 checkSlow(Index < AnnotationArray.Num() * BitsPerElement);
1516 }
1517 AnnotationArray[Index / BitsPerElement] |= TBitType(TBitType(1) << (Index % BitsPerElement));
1518 }
1524 inline void Clear(const UObjectBase *Object)
1525 {
1528 RemoveAnnotation(Index);
1529 }
1530
1536 {
1537 RemoveAllAnnotations();
1538 }
1539
1545 inline bool Get(const UObjectBase *Object)
1546 {
1549 checkSlow(Index >= 0);
1550 if (Index < AnnotationArray.Num() * BitsPerElement)
1551 {
1552 return !!(AnnotationArray[Index / BitsPerElement] & TBitType(TBitType(1) << (Index % BitsPerElement)));
1553 }
1554 return false;
1555 }
1556
1557 virtual SIZE_T GetAllocatedSize() const override
1558 {
1559 return AnnotationArray.GetAllocatedSize();
1560 }
1561
1562private:
1568 void RemoveAnnotation(int32 Index)
1569 {
1570 checkSlow(Index >= 0);
1571 if (Index < AnnotationArray.Num() * BitsPerElement)
1572 {
1573 AnnotationArray[Index / BitsPerElement] &= ~TBitType(TBitType(1) << (Index % BitsPerElement));
1574 }
1575 }
1580 void RemoveAllAnnotations()
1581 {
1582 bool bHadElements = (AnnotationArray.Num() > 0);
1583 AnnotationArray.Empty();
1584 if (bHadElements)
1585 {
1587 }
1588 }
1589
1593 TArray<TBitType> AnnotationArray;
1594};
#define checkSlow(expr)
Definition AssertionMacros.h:332
#define ensureAlwaysMsgf(InExpression, InFormat,...)
Definition AssertionMacros.h:467
#define check(expr)
Definition AssertionMacros.h:314
#define checkf(expr, format,...)
Definition AssertionMacros.h:315
#define UE_DEPRECATED(Version, Message)
Definition CoreMiscDefines.h:302
#define TSAN_SAFE
Definition CoreMiscDefines.h:144
#define TEXT(x)
Definition Platform.h:1272
FPlatformTypes::SIZE_T SIZE_T
An unsigned integer the same size as a pointer, the same as UPTRINT.
Definition Platform.h:1150
FPlatformTypes::int32 int32
A 32-bit signed integer.
Definition Platform.h:1125
#define UE_FORCEINLINE_HINT
Definition Platform.h:723
UE_FORCEINLINE_HINT TSharedRef< CastToType, Mode > StaticCastSharedRef(TSharedRef< CastFromType, Mode > const &InSharedRef)
Definition SharedPointer.h:127
@ Num
Definition MetalRHIPrivate.h:234
#define ON_SCOPE_EXIT
Definition ScopeExit.h:73
@ SLT_ReadOnly
Definition ScopeRWLock.h:138
@ SLT_Write
Definition ScopeRWLock.h:139
::FCriticalSection FTransactionallySafeCriticalSection
Definition TransactionallySafeCriticalSection.h:16
FUObjectArray GUObjectArray
Definition UObjectHash.cpp:55
UE_INTRINSIC_CAST UE_REWRITE constexpr std::remove_reference_t< T > && MoveTemp(T &&Obj) noexcept
Definition UnrealTemplate.h:520
uint32_t uint32
Definition binka_ue_file_header.h:6
Definition UObjectAnnotation.h:690
void AddAnnotation(const UObjectBase *Object, const TAnnotation &Annotation)
Definition UObjectAnnotation.h:867
void RemoveAnnotation(int32 Index)
Definition UObjectAnnotation.h:961
void RemoveAllAnnotations()
Definition UObjectAnnotation.h:1054
UE_FORCEINLINE_HINT int32 GetAnnotationCount() const
Definition UObjectAnnotation.h:1014
virtual void OnUObjectArrayShutdown() override
Definition UObjectAnnotation.h:1131
virtual SIZE_T GetAllocatedSize() const override
Definition UObjectAnnotation.h:1091
TAnnotation & AddOrGetAnnotation(int32 Index, TFunctionRef< TAnnotation()> NewAnnotationFn)
Definition UObjectAnnotation.h:908
FUObjectAnnotationChunked() TSAN_SAFE
Definition UObjectAnnotation.h:846
virtual ~FUObjectAnnotationChunked()
Definition UObjectAnnotation.h:854
uint32 GetMaxAllocatedSize() const
Definition UObjectAnnotation.h:1105
void AddAnnotation(const UObjectBase *Object, TAnnotation &&Annotation)
Definition UObjectAnnotation.h:873
UE_FORCEINLINE_HINT int32 GetMaxAnnotations() const TSAN_SAFE
Definition UObjectAnnotation.h:1024
TAnnotation & AddOrGetAnnotation(const UObjectBase *Object, TFunctionRef< TAnnotation()> NewAnnotationFn)
Definition UObjectAnnotation.h:897
UE_FORCEINLINE_HINT int32 GetMaxAnnottations() const TSAN_SAFE
Definition UObjectAnnotation.h:1035
void AddAnnotation(int32 Index, TAnnotation &&Annotation)
Definition UObjectAnnotation.h:891
void RemoveAnnotation(const UObjectBase *Object)
Definition UObjectAnnotation.h:951
TAnnotation GetAnnotation(int32 Index)
Definition UObjectAnnotation.h:983
void AddAnnotation(int32 Index, const TAnnotation &Annotation)
Definition UObjectAnnotation.h:885
UE_FORCEINLINE_HINT bool IsValidIndex(int32 Index) const
Definition UObjectAnnotation.h:1046
TAnnotation GetAnnotation(const UObjectBase *Object)
Definition UObjectAnnotation.h:972
void TrimAnnotations()
Definition UObjectAnnotation.h:1074
virtual void NotifyUObjectDeleted(const UObjectBase *Object, int32 Index)
Definition UObjectAnnotation.h:1116
Definition UObjectAnnotation.h:1465
void Set(const UObjectBase *Object)
Definition UObjectAnnotation.h:1500
void Clear(const UObjectBase *Object)
Definition UObjectAnnotation.h:1524
virtual SIZE_T GetAllocatedSize() const override
Definition UObjectAnnotation.h:1557
virtual void NotifyUObjectDeleted(const UObjectBase *Object, int32 Index)
Definition UObjectAnnotation.h:1476
virtual ~FUObjectAnnotationDenseBool()
Definition UObjectAnnotation.h:1490
bool Get(const UObjectBase *Object)
Definition UObjectAnnotation.h:1545
UE_FORCEINLINE_HINT void ClearAll()
Definition UObjectAnnotation.h:1535
virtual void OnUObjectArrayShutdown() override
Definition UObjectAnnotation.h:1481
Definition UObjectAnnotation.h:1153
void AddAnnotation(const UObjectBase *Object, TAnnotation &&Annotation)
Definition UObjectAnnotation.h:1203
virtual void OnUObjectArrayShutdown() override
Definition UObjectAnnotation.h:1177
void AddAnnotation(int32 Index, const TAnnotation &Annotation)
Definition UObjectAnnotation.h:1215
virtual ~FUObjectAnnotationDense()
Definition UObjectAnnotation.h:1186
void RemoveAnnotation(int32 Index)
Definition UObjectAnnotation.h:1328
void RemoveAllAnnotations()
Definition UObjectAnnotation.h:1349
virtual void NotifyUObjectDeleted(const UObjectBase *Object, int32 Index)
Definition UObjectAnnotation.h:1162
TAnnotation GetAnnotation(const UObjectBase *Object)
Definition UObjectAnnotation.h:1376
void AddAnnotation(int32 Index, TAnnotation &&Annotation)
Definition UObjectAnnotation.h:1229
virtual SIZE_T GetAllocatedSize() const override
Definition UObjectAnnotation.h:1442
TAnnotation & GetAnnotationRef(int32 Index)
Definition UObjectAnnotation.h:1423
void RemoveAnnotation(const UObjectBase *Object)
Definition UObjectAnnotation.h:1318
TAnnotation GetAnnotation(int32 Index)
Definition UObjectAnnotation.h:1393
void AddAnnotation(const UObjectBase *Object, const TAnnotation &Annotation)
Definition UObjectAnnotation.h:1197
TAnnotation & GetAnnotationRef(const UObjectBase *Object)
Definition UObjectAnnotation.h:1410
Definition UObjectAnnotation.h:619
UE_FORCEINLINE_HINT int32 Num() const
Definition UObjectAnnotation.h:667
UE_FORCEINLINE_HINT void Reserve(int32 ExpectedNumElements)
Definition UObjectAnnotation.h:662
UE_FORCEINLINE_HINT void ClearAll()
Definition UObjectAnnotation.h:644
UE_FORCEINLINE_HINT void Set(const UObjectBase *Object)
Definition UObjectAnnotation.h:626
UE_FORCEINLINE_HINT bool Get(const UObjectBase *Object)
Definition UObjectAnnotation.h:654
UE_FORCEINLINE_HINT void Clear(const UObjectBase *Object)
Definition UObjectAnnotation.h:635
Definition UObjectAnnotation.h:447
virtual void OnUObjectArrayShutdown() override
Definition UObjectAnnotation.h:461
void RemoveAllAnnotations()
Definition UObjectAnnotation.h:554
void AddAnnotation(const UObjectBase *Object, TAnnotation &&Annotation)
Definition UObjectAnnotation.h:525
virtual void NotifyUObjectDeleted(const UObjectBase *Object, int32 Index) override
Definition UObjectAnnotation.h:456
UObject * Find(const TAnnotation &Annotation)
Definition UObjectAnnotation.h:481
virtual SIZE_T GetAllocatedSize() const override
Definition UObjectAnnotation.h:561
void RemoveAnnotation(const UObjectBase *Object)
Definition UObjectAnnotation.h:535
virtual ~FUObjectAnnotationSparseSearchable()
Definition UObjectAnnotation.h:470
void AddAnnotation(const UObjectBase *Object, const TAnnotation &Annotation)
Definition UObjectAnnotation.h:520
Definition UObjectAnnotation.h:33
virtual void NotifyUObjectDeleted(const UObjectBase *Object, int32 Index) override
Definition UObjectAnnotation.h:42
void AddAnnotation(const UObjectBase *Object, const TAnnotation &Annotation)
Definition UObjectAnnotation.h:169
TAnnotation GetAndRemoveAnnotation(const UObjectBase *Object)
Definition UObjectAnnotation.h:179
FTransactionallySafeRWLock AnnotationMapCritical
Definition UObjectAnnotation.h:402
virtual void OnUObjectArrayShutdown() override
Definition UObjectAnnotation.h:58
TAnnotation GetAnnotation(const UObjectBase *Object)
Definition UObjectAnnotation.h:283
FTransactionallySafeRWLock AnnotationCacheCritical
Definition UObjectAnnotation.h:403
const UObjectBase * AnnotationCacheKey
Definition UObjectAnnotation.h:414
void RemoveAllAnnotations()
Definition UObjectAnnotation.h:250
void Reserve(int32 ExpectedNumElements)
Definition UObjectAnnotation.h:326
TMap< const UObjectBase *, TAnnotation > AnnotationMap
Definition UObjectAnnotation.h:408
bool bRegistered
Definition UObjectAnnotation.h:424
const TMap< const UObjectBase *, TAnnotation > & GetAnnotationMap() const
Definition UObjectAnnotation.h:318
FUObjectAnnotationSparse()
Definition UObjectAnnotation.h:67
virtual ~FUObjectAnnotationSparse()
Definition UObjectAnnotation.h:76
void AddAnnotation(const UObjectBase *Object, TAnnotation &&Annotation)
Definition UObjectAnnotation.h:164
void RemoveAnnotation(const UObjectBase *Object)
Definition UObjectAnnotation.h:216
TAnnotation AnnotationCacheValue
Definition UObjectAnnotation.h:419
virtual SIZE_T GetAllocatedSize() const override
Definition UObjectAnnotation.h:332
Definition UObjectArray.h:984
UE_FORCEINLINE_HINT int32 ObjectToIndex(const class UObjectBase *Object) const
Definition UObjectArray.h:1078
COREUOBJECT_API void AddUObjectDeleteListener(FUObjectDeleteListener *Listener)
Definition UObjectArray.cpp:458
COREUOBJECT_API void RemoveUObjectDeleteListener(FUObjectDeleteListener *Listener)
Definition UObjectArray.cpp:472
void UnlockUObjectDeleteListeners()
Definition UObjectArray.h:1476
void LockUObjectDeleteListeners()
Definition UObjectArray.h:1468
Definition Array.h:670
UE_FORCEINLINE_HINT SizeType AddUninitialized()
Definition Array.h:1664
UE_REWRITE SizeType Num() const
Definition Array.h:1144
UE_NODEBUG UE_FORCEINLINE_HINT ElementType * GetData() UE_LIFETIMEBOUND
Definition Array.h:1027
SizeType AddZeroed()
Definition Array.h:2755
UE_NODEBUG UE_FORCEINLINE_HINT SIZE_T GetAllocatedSize(void) const
Definition Array.h:1059
void Empty(SizeType Slack=0)
Definition Array.h:2273
Definition AssetRegistryState.h:50
Definition UnrealString.h.inl:34
Definition CriticalSection.h:14
Definition ScopeRWLock.h:154
Definition ScopeRWLock.h:21
Definition ScopeLock.h:21
Definition ScopeRWLock.h:60
Definition UObjectBaseUtility.h:45
Definition UObjectBase.h:59
Definition Object.h:95
@ Start
Definition GeoEnum.h:100
@ false
Definition radaudio_common.h:23
U16 Index
Definition radfft.cpp:71
Definition UObjectAnnotation.h:576
UE_FORCEINLINE_HINT bool IsDefault()
Definition UObjectAnnotation.h:597
FBoolAnnotation()
Definition UObjectAnnotation.h:581
bool Mark
Definition UObjectAnnotation.h:605
FBoolAnnotation(bool InMark)
Definition UObjectAnnotation.h:589
Definition IsPODType.h:12
@ Value
Definition IsPODType.h:13