UDocumentation UE5.7 10.02.2026 (Source)
API documentation for Unreal Engine 5.7
Array.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"
9#include "HAL/UnrealMemory.h"
17
18#include "Algo/Heapify.h"
19#include "Algo/HeapSort.h"
20#include "Algo/IsHeap.h"
22#include "Algo/StableSort.h"
24#include "Templates/IdentityFunctor.h"
25#include "Templates/Invoke.h"
26#include "Templates/Less.h"
28#include "Templates/Requires.h"
29#include "Templates/Sorting.h"
31#include "Traits/ElementType.h"
33
34#include <limits>
35#include <type_traits>
36
37#if UE_BUILD_SHIPPING || UE_BUILD_TEST
38 #define TARRAY_RANGED_FOR_CHECKS 0
39#else
40 #define TARRAY_RANGED_FOR_CHECKS 1
41#endif
42
43template <typename T>
45{
46 enum { Value = std::is_arithmetic_v<T> };
47};
48
49// Forward declarations
50
51template <typename T, typename AllocatorType> inline void* operator new(size_t Size, TArray<T, AllocatorType>& Array);
52template <typename T, typename AllocatorType> inline void* operator new(size_t Size, TArray<T, AllocatorType>& Array, typename TArray<T, AllocatorType>::SizeType Index);
53
62template <typename ContainerType, typename ElementType, typename SizeType>
64{
65public:
66 UE_NODEBUG [[nodiscard]] TIndexedContainerIterator(ContainerType& InContainer, SizeType StartIndex = 0)
67 : Container(InContainer)
68 , Index (StartIndex)
69 {
70 }
71
74 {
75 ++Index;
76 return *this;
77 }
79 {
81 ++Index;
82 return Tmp;
83 }
84
87 {
88 --Index;
89 return *this;
90 }
92 {
94 --Index;
95 return Tmp;
96 }
97
100 {
101 Index += Offset;
102 return *this;
103 }
104
106 {
107 TIndexedContainerIterator Tmp(*this);
108 return Tmp += Offset;
109 }
110
112 {
113 return *this += -Offset;
114 }
115
117 {
118 TIndexedContainerIterator Tmp(*this);
119 return Tmp -= Offset;
120 }
121
123 {
124 return Container[ Index ];
125 }
126
128 {
129 return &Container[ Index ];
130 }
131
133 UE_NODEBUG [[nodiscard]] UE_FORCEINLINE_HINT explicit operator bool() const
134 {
135 return Container.IsValidIndex(Index);
136 }
137
139 UE_NODEBUG [[nodiscard]] SizeType GetIndex() const
140 {
141 return Index;
142 }
143
146 {
147 Index = 0;
148 }
149
152 {
153 Index = Container.Num();
154 }
155
158 {
159 Container.RemoveAt(Index);
160 Index--;
161 }
162
169 {
170 Container.RemoveAtSwap(Index);
171 Index--;
172 }
173
175 {
176 return &Container == &Rhs.Container && Index == Rhs.Index;
177 }
178#if !PLATFORM_COMPILER_HAS_GENERATED_COMPARISON_OPERATORS
180 {
181 return &Container != &Rhs.Container || Index != Rhs.Index;
182 }
183#endif
184
185private:
186 ContainerType& Container;
187 SizeType Index;
188};
189
190
192template <typename ContainerType, typename ElementType, typename SizeType>
197
198
199#if TARRAY_RANGED_FOR_CHECKS
204 template <typename ElementType, typename SizeType, bool bReverse = false>
206 {
207 // This iterator type only supports the minimal functionality needed to support
208 // C++ ranged-for syntax. For example, it does not provide post-increment ++ or any operation you wouldn't expect from a raw pointer.
209 //
210 // We do add an operator-- to help FString implementation
211
212 UE_NODEBUG [[nodiscard]] explicit TCheckedPointerIterator(const SizeType& InNum, ElementType* InPtr)
213 : Ptr (InPtr)
214 , CurrentNum(InNum)
215 , InitialNum(InNum)
216 {
217 }
218
220 {
221 if constexpr (bReverse)
222 {
223 return Ptr - 1;
224 }
225 else
226 {
227 return Ptr;
228 }
229 }
230
232 {
233 if constexpr (bReverse)
234 {
235 return *(Ptr - 1);
236 }
237 else
238 {
239 return *Ptr;
240 }
241 }
242
244 {
245 if constexpr (bReverse)
246 {
247 --Ptr;
248 }
249 else
250 {
251 ++Ptr;
252 }
253 return *this;
254 }
255
257 {
258 if constexpr (bReverse)
259 {
260 ++Ptr;
261 }
262 else
263 {
264 --Ptr;
265 }
266 return *this;
267 }
268
270 {
271 // We only need to do the check in this operator, because no other operator will be
272 // called until after this one returns.
273 //
274 // Also, we should only need to check one side of this comparison - if the other iterator isn't
275 // even from the same array then the compiler has generated bad code.
276 ensureMsgf(CurrentNum == InitialNum, TEXT("Array has changed during ranged-for iteration!"));
277 return Ptr != Rhs.Ptr;
278 }
279
281 {
282 return !(*this != Rhs);
283 }
284
285
286 private:
287 ElementType* Ptr;
288 const SizeType& CurrentNum;
289 SizeType InitialNum;
290 };
291#endif
292
293
294template <typename ElementType, typename IteratorType>
296{
298 : Iter(InIter)
299 {
300 }
301
303 {
304 return *(ElementType*)*Iter;
305 }
306
308 {
309 ++Iter;
310 return *this;
311 }
312
314 {
315 return Iter != Rhs.Iter;
316 }
317
318private:
319 IteratorType Iter;
320};
321
322namespace UE::Core::Private
323{
324 // Simply forwards to an unqualified GetData(), but can be called from within a container or view
325 // where GetData() is already a member and so hides any others.
326 template <typename T>
327 [[nodiscard]] UE_FORCEINLINE_HINT decltype(auto) GetDataHelper(T&& Arg)
328 {
329 return GetData(Forward<T>(Arg));
330 }
331
332 template <typename FromArrayType, typename ToArrayType>
333 UE_NODEBUG [[nodiscard]] constexpr bool CanMoveTArrayPointersBetweenArrayTypes()
334 {
335 using FromAllocatorType = typename FromArrayType::AllocatorType;
336 using ToAllocatorType = typename ToArrayType::AllocatorType;
337 using FromElementType = typename FromArrayType::ElementType;
338 using ToElementType = typename ToArrayType::ElementType;
339 using UnqualifiedFromElementType = std::remove_cv_t<FromElementType>;
340 using UnqualifiedToElementType = std::remove_cv_t<ToElementType>;
341
342 // Allocators must be equal or move-compatible...
343 if constexpr (std::is_same_v<FromAllocatorType, ToAllocatorType> || TCanMoveBetweenAllocators<FromAllocatorType, ToAllocatorType>::Value)
344 {
345 return
347 (
348 std::is_same_v <const ToElementType, const FromElementType> || // The element type of the container must be the same, or...
349 TIsBitwiseConstructible<UnqualifiedToElementType, UnqualifiedFromElementType>::Value // ... the element type of the source container must be bitwise constructible from the element type in the destination container
350 );
351 }
352 else
353 {
354 return false;
355 }
356 }
357
358 // Assume elements are compatible with themselves - avoids problems with generated copy
359 // constructors of arrays of forwarded types, e.g.:
360 //
361 // struct FThing;
362 //
363 // struct FOuter
364 // {
365 // TArray<FThing> Arr; // this will cause errors without this workaround
366 // };
367 template <typename DestType, typename SourceType>
368 constexpr bool TArrayElementsAreCompatible_V = std::disjunction_v<std::is_same<DestType, std::decay_t<SourceType>>, std::is_constructible<DestType, SourceType>>;
369
370 template <typename ElementType, typename AllocatorType>
371 UE_NODEBUG static char (&ResolveIsTArrayPtr(const volatile TArray<ElementType, AllocatorType>*))[2];
372 UE_NODEBUG static char(&ResolveIsTArrayPtr(...))[1];
373
374 template <typename T>
375 constexpr bool TIsTArrayOrDerivedFromTArray_V = sizeof(ResolveIsTArrayPtr((T*)nullptr)) == 2;
376
377 [[noreturn]] CORE_API void OnInvalidArrayNum(unsigned long long NewNum);
378
379 // A hacky way to get the SizeType, since it's defined in the
380 // (outer) allocator type, not the (inner) allocator instance type
381 template <typename AllocatorInstanceType>
382 using TAllocatorSizeType_T = decltype(std::declval<AllocatorInstanceType&>().GetInitialCapacity());
383
384 // Flags are passed as a uint32 to minimize PDB impact of these generated symbols.
385 //
386 // 1 == TAllocatorTraits<>::SupportsElementAlignment
387 // 2 == TAllocatorTraits<>::SupportsSlackTracking
388 //
389 // When C++20 is guaranteed, concept checks can be used instead.
390 template <typename AllocatorType>
391 UE_NODEBUG [[nodiscard]] constexpr uint32 GetAllocatorFlags()
392 {
393 uint32 Result = 0;
395 {
396 Result |= 1;
397 }
399 {
400 Result |= 2;
401 }
402 return Result;
403 }
404
405
406 // Called only when we KNOW we are going to do a realloc increasing by 1.
407 // In this case, we know that max == num and can simplify things in a very
408 // hot location in the code.
409 // This returns the old ArrayMax in order to save a register clobber/reload.
410 template <uint32 Flags, typename AllocatorInstanceType>
412 uint32 ElementSize,
413 uint32 ElementAlignment,
414 AllocatorInstanceType& AllocatorInstance,
416 )
417 {
419 using USizeType = std::make_unsigned_t<SizeType>;
420
421 const USizeType UOldMax = (USizeType)ArrayMax;
422 const USizeType UNewNum = UOldMax + 1U;
423 const SizeType OldMax = (SizeType)UOldMax;
424 const SizeType NewNum = (SizeType)UNewNum;
425
426 // This should only happen when we've underflowed or overflowed SizeType
427 if (NewNum < OldMax)
428 {
429 OnInvalidArrayNum((unsigned long long)UNewNum);
430 }
431
432 SizeType NewMax;
433 if constexpr (!!(Flags & 1)) // TAllocatorTraits<AllocatorType>::SupportsElementAlignment
434 {
435 NewMax = AllocatorInstance.CalculateSlackGrow(NewNum, OldMax, ElementSize, ElementAlignment);
436 AllocatorInstance.ResizeAllocation(UOldMax, NewMax, ElementSize, ElementAlignment);
437 }
438 else
439 {
440 NewMax = AllocatorInstance.CalculateSlackGrow(NewNum, OldMax, ElementSize);
441 AllocatorInstance.ResizeAllocation(UOldMax, NewMax, ElementSize);
442 }
444 #if UE_ENABLE_ARRAY_SLACK_TRACKING
445 if constexpr (!!(Flags & 2)) // TAllocatorTraits<AllocatorType>::SupportsSlackTracking
446 {
447 AllocatorInstance.SlackTrackerLogNum(NewNum);
448 }
449 #endif
450
451 return OldMax;
452 }
453
454 // Version for small sizes/alignments. This allows the parameter setup to be a single instruction
455 // note the uint16 limitation allows for a single instruction setup on arm.
456 template <uint32 Flags, typename AllocatorInstanceType>
459 AllocatorInstanceType& AllocatorInstance,
461 )
462 {
464 }
465
466 template <uint32 Flags, typename AllocatorInstanceType>
468 uint32 ElementSize,
469 uint32 ElementAlignment,
470 AllocatorInstanceType& AllocatorInstance,
472 )
473 {
474 return ReallocGrow1_DoAlloc_Impl<Flags, AllocatorInstanceType>(ElementSize, ElementAlignment, AllocatorInstance, ArrayMax);
475 }
476
477 // This should be used for repeated growing operations when reallocations are to be amortized over multiple inserts.
478 template <uint32 Flags, typename AllocatorInstanceType>
480 uint32 ElementSize,
481 uint32 ElementAlignment,
483 AllocatorInstanceType& AllocatorInstance,
486 )
487 {
489 using USizeType = std::make_unsigned_t<SizeType>;
490
491 const USizeType UCount = (USizeType)Count;
492 const USizeType UOldNum = (USizeType)ArrayNum;
493 const USizeType UOldMax = (USizeType)ArrayMax;
494 const USizeType UNewNum = UOldNum + UCount;
495 const SizeType OldNum = (SizeType)UOldNum;
496 const SizeType OldMax = (SizeType)UOldMax;
497 const SizeType NewNum = (SizeType)UNewNum;
498
499 checkSlow((OldNum >= 0) & (OldMax >= OldNum) & (Count >= 0)); // & for one branch
500
501 ArrayNum = NewNum;
502
503#if DO_GUARD_SLOW
504 if (UNewNum > UOldMax)
505#else
506 // SECURITY - This check will guard against negative counts too, in case the checkSlow above is compiled out.
507 // However, it results in slightly worse code generation.
508 if (UCount > UOldMax - UOldNum)
509#endif
510 {
511 // This should only happen when we've underflowed or overflowed SizeType
512 if (NewNum < OldNum)
513 {
514 OnInvalidArrayNum((unsigned long long)UNewNum);
515 }
516 SizeType NewMax;
517 if constexpr (!!(Flags & 1)) // TAllocatorTraits<AllocatorType>::SupportsElementAlignment
518 {
519 NewMax = AllocatorInstance.CalculateSlackGrow(NewNum, OldMax, ElementSize, ElementAlignment);
520 AllocatorInstance.ResizeAllocation(UOldNum, NewMax, ElementSize, ElementAlignment);
521 }
522 else
523 {
524 NewMax = AllocatorInstance.CalculateSlackGrow(NewNum, OldMax, ElementSize);
525 AllocatorInstance.ResizeAllocation(UOldNum, NewMax, ElementSize);
526 }
528#if UE_ENABLE_ARRAY_SLACK_TRACKING
529 if constexpr (!!(Flags & 2)) // TAllocatorTraits<AllocatorType>::SupportsSlackTracking
530 {
531 AllocatorInstance.SlackTrackerLogNum(NewNum);
532 }
533#endif
534 }
535
536 return OldNum;
537 }
538
539 // This should be used for repeated shrinking operations when reallocations are to be amortized over multiple removals.
540 template <uint32 Flags, typename AllocatorInstanceType>
541 FORCENOINLINE void ReallocShrink(
542 uint32 ElementSize,
543 uint32 ElementAlignment,
544 AllocatorInstanceType& AllocatorInstance,
547 )
548 {
550
551 SizeType OldArrayMax = ArrayMax;
552
553 if constexpr (!!(Flags & 1)) // TAllocatorTraits<AllocatorType>::SupportsElementAlignment
554 {
555 SizeType NewArrayMax = AllocatorInstance.CalculateSlackShrink(ArrayNum, OldArrayMax, ElementSize, ElementAlignment);
557 {
559 AllocatorInstance.ResizeAllocation(ArrayNum, NewArrayMax, ElementSize, ElementAlignment);
560 }
561 }
562 else
563 {
564 SizeType NewArrayMax = AllocatorInstance.CalculateSlackShrink(ArrayNum, OldArrayMax, ElementSize);
566 {
568 AllocatorInstance.ResizeAllocation(ArrayNum, NewArrayMax, ElementSize);
569 }
570 }
571 }
572
573 // This should be used for setting an allocation to a specific size.
574 // Precondition: NewMax >= ArrayNum.
575 template <uint32 Flags, typename AllocatorInstanceType>
576 FORCENOINLINE void ReallocTo(
577 uint32 ElementSize,
578 uint32 ElementAlignment,
580 AllocatorInstanceType& AllocatorInstance,
583 )
584 {
585 if constexpr (!!(Flags & 1)) // TAllocatorTraits<AllocatorType>::SupportsElementAlignment
586 {
587 if (NewMax)
588 {
589 NewMax = AllocatorInstance.CalculateSlackReserve(NewMax, ElementSize, ElementAlignment);
590 }
591 if (NewMax != ArrayMax)
592 {
594 AllocatorInstance.ResizeAllocation(ArrayNum, NewMax, ElementSize, ElementAlignment);
595 }
596 }
597 else
598 {
599 if (NewMax)
600 {
601 NewMax = AllocatorInstance.CalculateSlackReserve(NewMax, ElementSize);
602 }
603 if (NewMax != ArrayMax)
604 {
606 AllocatorInstance.ResizeAllocation(ArrayNum, NewMax, ElementSize);
607 }
608 }
609 }
610
611 template <uint32 Flags, typename AllocatorInstanceType>
612 FORCENOINLINE void ReallocForCopy(
613 uint32 ElementSize,
614 uint32 ElementAlignment,
617 AllocatorInstanceType& AllocatorInstance,
620 )
621 {
622 if constexpr (!!(Flags & 1)) // TAllocatorTraits<AllocatorType>::SupportsElementAlignment
623 {
624 if (NewMax)
625 {
626 NewMax = AllocatorInstance.CalculateSlackReserve(NewMax, ElementSize, ElementAlignment);
627 }
628 if (NewMax > PrevMax)
629 {
630 AllocatorInstance.ResizeAllocation(0, NewMax, ElementSize, ElementAlignment);
631 }
632 else
633 {
634 NewMax = PrevMax;
635 }
636 }
637 else
638 {
639 if (NewMax)
640 {
641 NewMax = AllocatorInstance.CalculateSlackReserve(NewMax, ElementSize);
642 }
643 if (NewMax > PrevMax)
644 {
645 AllocatorInstance.ResizeAllocation(0, NewMax, ElementSize);
646 }
647 else
648 {
649 NewMax = PrevMax;
650 }
651 }
653 }
654}
655
656
668template<typename InElementType, typename InAllocatorType>
670{
671 template <typename OtherInElementType, typename OtherAllocator>
672 friend class TArray;
673
674public:
675 using SizeType = typename InAllocatorType::SizeType ;
678
679private:
680 using USizeType = typename std::make_unsigned_t<SizeType>;
681
682public:
683 using ElementAllocatorType = std::conditional_t<
684 AllocatorType::NeedsElementType,
685 typename AllocatorType::template ForElementType<ElementType>,
686 typename AllocatorType::ForAnyElementType
687 >;
688
689 static_assert(std::is_signed_v<SizeType>, "TArray only supports signed index types");
690
695 : ArrayNum(0)
696 , ArrayMax(AllocatorInstance.GetInitialCapacity())
697 {
698 }
699
701 [[nodiscard]] explicit consteval TArray(EConstEval)
703 , ArrayNum(0)
704 , ArrayMax(AllocatorInstance.GetInitialCapacity())
705 {
706 }
707
716 {
717 if (Count < 0)
718 {
719 // Cast to USizeType first to prevent sign extension on negative sizes, producing unusually large values.
720 UE::Core::Private::OnInvalidArrayNum((unsigned long long)(USizeType)Count);
721 }
722
723 check(Ptr != nullptr || Count == 0);
724
725 CopyToEmpty(Ptr, Count, 0);
726 }
727
728 template <typename OtherElementType, typename OtherSizeType>
730
734 [[nodiscard]] TArray(std::initializer_list<InElementType> InitList)
735 {
736 // This is not strictly legal, as std::initializer_list's iterators are not guaranteed to be pointers, but
737 // this appears to be the case on all of our implementations. Also, if it's not true on a new implementation,
738 // it will fail to compile rather than behave badly.
739 CopyToEmpty(InitList.begin(), (SizeType)InitList.size(), 0);
740 }
741
747 template <
748 typename OtherElementType,
749 typename OtherAllocator
750 UE_REQUIRES(UE::Core::Private::TArrayElementsAreCompatible_V<ElementType, const OtherElementType&>)
751 >
753 {
754 CopyToEmpty(Other.GetData(), Other.Num(), 0);
755 }
756
763 {
764 CopyToEmpty(Other.GetData(), Other.Num(), 0);
765 }
766
775 {
776 CopyToEmptyWithSlack(Other.GetData(), Other.Num(), 0, ExtraSlack);
777 }
778
785 TArray& operator=(std::initializer_list<InElementType> InitList)
786 {
788 // This is not strictly legal, as std::initializer_list's iterators are not guaranteed to be pointers, but
789 // this appears to be the case on all of our implementations. Also, if it's not true on a new implementation,
790 // it will fail to compile rather than behave badly.
791 CopyToEmpty(InitList.begin(), (SizeType)InitList.size(), ArrayMax);
792 return *this;
793 }
794
803 template<typename OtherAllocatorType>
805 {
807 CopyToEmpty(Other.GetData(), Other.Num(), ArrayMax);
808 return *this;
809 }
810
818 {
819 if (this != &Other)
820 {
822 CopyToEmpty(Other.GetData(), Other.Num(), ArrayMax);
823 }
824 return *this;
825 }
826
827 template <typename OtherElementType, typename OtherSizeType>
829
830private:
831
832 UE_FORCEINLINE_HINT void SlackTrackerNumChanged()
833 {
834#if UE_ENABLE_ARRAY_SLACK_TRACKING
836 {
837 AllocatorInstance.SlackTrackerLogNum(ArrayNum);
838 }
839#endif
840 }
841
849 template <typename FromArrayType, typename ToArrayType>
850 static UE_FORCEINLINE_HINT void MoveOrCopy(ToArrayType& ToArray, FromArrayType& FromArray, SizeType PrevMax)
851 {
852 if constexpr (UE::Core::Private::CanMoveTArrayPointersBetweenArrayTypes<FromArrayType, ToArrayType>())
853 {
854 // Move
855
856 static_assert(std::is_same_v<TArray, ToArrayType>, "MoveOrCopy is expected to be called with the current array type as the destination");
857
858 using FromAllocatorType = typename FromArrayType::AllocatorType;
859 using ToAllocatorType = typename ToArrayType::AllocatorType;
860
862 {
863 ToArray.AllocatorInstance.template MoveToEmptyFromOtherAllocator<FromAllocatorType>(FromArray.AllocatorInstance);
864 }
865 else
866 {
867 ToArray.AllocatorInstance.MoveToEmpty(FromArray.AllocatorInstance);
868 }
869
870 ToArray .ArrayNum = (SizeType)FromArray.ArrayNum;
871 ToArray .ArrayMax = (SizeType)FromArray.ArrayMax;
872
873 // Ensure the destination container could hold the source range (when the allocator size types shrink)
874 if constexpr (sizeof(USizeType) < sizeof(typename FromArrayType::USizeType))
875 {
876 if (ToArray.ArrayNum != FromArray.ArrayNum || ToArray.ArrayMax != FromArray.ArrayMax)
877 {
878 // Cast to USizeType first to prevent sign extension on negative sizes, producing unusually large values.
879 UE::Core::Private::OnInvalidArrayNum((unsigned long long)(USizeType)ToArray.ArrayNum);
880 }
881 }
882
883 FromArray.ArrayNum = 0;
884 FromArray.ArrayMax = FromArray.AllocatorInstance.GetInitialCapacity();
885
886 FromArray.SlackTrackerNumChanged();
887 ToArray.SlackTrackerNumChanged();
888 }
889 else
890 {
891 // Copy
892
893 ToArray.CopyToEmpty(FromArray.GetData(), FromArray.Num(), PrevMax);
894 }
895 }
896
906 template <typename FromArrayType, typename ToArrayType>
907 static UE_FORCEINLINE_HINT void MoveOrCopyWithSlack(ToArrayType& ToArray, FromArrayType& FromArray, SizeType PrevMax, SizeType ExtraSlack)
908 {
909 if constexpr (UE::Core::Private::CanMoveTArrayPointersBetweenArrayTypes<FromArrayType, ToArrayType>())
910 {
911 // Move
912
913 MoveOrCopy(ToArray, FromArray, PrevMax);
914
915 USizeType LocalArrayNum = (USizeType)ToArray.ArrayNum;
916 USizeType NewMax = (USizeType)LocalArrayNum + (USizeType)ExtraSlack;
917
918 // This should only happen when we've underflowed or overflowed SizeType
920 {
921 UE::Core::Private::OnInvalidArrayNum((unsigned long long)ExtraSlack);
922 }
923
924 ToArray.Reserve(NewMax);
925 }
926 else
927 {
928 // Copy
929
930 ToArray.CopyToEmptyWithSlack(FromArray.GetData(), FromArray.Num(), PrevMax, ExtraSlack);
931 }
932 }
933
934public:
941 {
942 MoveOrCopy(*this, Other, 0);
943 }
944
950 template <
951 typename OtherElementType,
952 typename OtherAllocator
953 UE_REQUIRES(UE::Core::Private::TArrayElementsAreCompatible_V<ElementType, OtherElementType&&>)
954 >
956 {
957 MoveOrCopy(*this, Other, 0);
958 }
959
967 template <
968 typename OtherElementType
969 UE_REQUIRES(UE::Core::Private::TArrayElementsAreCompatible_V<ElementType, OtherElementType&&>)
970 >
972 {
973 MoveOrCopyWithSlack(*this, Other, 0, ExtraSlack);
974 }
975
982 {
983 if (this != &Other)
984 {
986 MoveOrCopy(*this, Other, ArrayMax);
987 }
988 return *this;
989 }
990
993 {
994 UE_STATIC_ASSERT_WARN(TIsTriviallyRelocatable_V<InElementType>, "TArray can only be used with trivially relocatable types");
995
997
998 // note ArrayNum, ArrayMax and data pointer are not invalidated
999 // they are left unchanged and use-after-destruct will see them the same as before destruct
1000 }
1001
1003 // Start - intrusive TOptional<TArray> state //
1005 constexpr static bool bHasIntrusiveUnsetOptionalState = true;
1007
1009 : ArrayNum(0)
1010 , ArrayMax(-1)
1011 {
1012 // Use ArrayMax == -1 as our intrusive state so that the destructor still works without change, as it doesn't use ArrayMax.
1013 }
1015 {
1016 return ArrayMax == -1;
1017 }
1019 // End - intrusive TOptional<TArray> state //
1021
1031
1038 {
1039 return const_cast<TArray*>(this)->GetData();
1040 }
1041
1048 {
1049 return sizeof(ElementType);
1050 }
1051
1060 {
1061 return AllocatorInstance.GetAllocatedSize(ArrayMax, sizeof(ElementType));
1062 }
1063
1073
1079 {
1080 checkSlow((ArrayNum >= 0) & (ArrayMax >= ArrayNum)); // & for one branch
1081 }
1082
1089 {
1091
1092 // Template property, branch will be optimized out
1093 if constexpr (AllocatorType::RequireRangeCheck)
1094 {
1095 checkf((Index >= 0) & (Index < ArrayNum),TEXT("Array index out of bounds: %lld into an array of size %lld"),(long long)Index, (long long)ArrayNum); // & for one branch
1096 }
1097 }
1098
1106 {
1108
1109 // Template property, branch will be optimized out
1110 if constexpr (AllocatorType::RequireRangeCheck)
1111 {
1112 checkf((Count >= 0) & (Index >= 0) & (Index + Count <= ArrayNum), TEXT("Array range out of bounds: index %lld and length %lld into an array of size %lld"), (long long)Index, (long long)Count, (long long)ArrayNum); // & for one branch
1113 }
1114 }
1115
1123 {
1124 return Index >= 0 && Index < ArrayNum;
1125 }
1126
1134 {
1135 return ArrayNum == 0;
1136 }
1137
1145 {
1146 return ArrayNum;
1147 }
1148
1151 {
1152 return static_cast<SIZE_T>(ArrayNum) * sizeof(ElementType);
1153 }
1154
1162 {
1163 return ArrayMax;
1164 }
1165
1176
1185 {
1186 return (*const_cast<TArray*>(this))[Index];
1187 }
1188
1196 ElementType Pop(EAllowShrinking AllowShrinking = UE::Core::Private::AllowShrinkingByDefault<AllocatorType>())
1197 {
1198 RangeCheck(0);
1200 RemoveAtImpl(ArrayNum - 1);
1202 {
1203 UE::Core::Private::ReallocShrink<UE::Core::Private::GetAllocatorFlags<AllocatorType>()>(
1204 sizeof(ElementType),
1205 alignof(ElementType),
1207 ArrayNum,
1208 ArrayMax
1209 );
1210 }
1211 return Result;
1212 }
1215 {
1216 return Pop(bAllowShrinking ? EAllowShrinking::Yes : EAllowShrinking::No);
1217 }
1218
1225 {
1226 Add(MoveTempIfPossible(Item));
1227 }
1228
1238 {
1239 Add(Item);
1240 }
1241
1253 {
1254 return const_cast<TArray*>(this)->Top();
1255 }
1256
1269 {
1270 return const_cast<TArray*>(this)->Last(IndexFromTheEnd);
1271 }
1272
1279 {
1281 if (ArrayMax != ArrayNum)
1282 {
1283 UE::Core::Private::ReallocTo<UE::Core::Private::GetAllocatorFlags<AllocatorType>()>(
1284 sizeof(ElementType),
1285 alignof(ElementType),
1286 ArrayNum,
1288 ArrayNum,
1289 ArrayMax
1290 );
1291 }
1292 }
1293
1303 {
1304 Index = this->Find(Item);
1305 return Index != INDEX_NONE;
1306 }
1307
1315 [[nodiscard]] SizeType Find(const ElementType& Item) const
1316 {
1317 const ElementType* RESTRICT Start = GetData();
1318 for (const ElementType* RESTRICT Data = Start, *RESTRICT DataEnd = Data + ArrayNum; Data != DataEnd; ++Data)
1319 {
1320 if (*Data == Item)
1321 {
1322 return static_cast<SizeType>(Data - Start);
1323 }
1324 }
1325 return INDEX_NONE;
1326 }
1327
1337 {
1338 Index = this->FindLast(Item);
1339 return Index != INDEX_NONE;
1340 }
1341
1349 {
1350 for (const ElementType* RESTRICT Start = GetData(), *RESTRICT Data = Start + ArrayNum; Data != Start; )
1351 {
1352 --Data;
1353 if (*Data == Item)
1354 {
1355 return static_cast<SizeType>(Data - Start);
1356 }
1357 }
1358 return INDEX_NONE;
1359 }
1360
1368 template <typename Predicate>
1370 {
1371 check(Count >= 0 && Count <= this->Num());
1372 for (const ElementType* RESTRICT Start = GetData(), *RESTRICT Data = Start + Count; Data != Start; )
1373 {
1374 --Data;
1375 if (::Invoke(Pred, *Data))
1376 {
1377 return static_cast<SizeType>(Data - Start);
1378 }
1379 }
1380 return INDEX_NONE;
1381 }
1382
1389 template <typename Predicate>
1394
1402 template <typename KeyType>
1403 [[nodiscard]] SizeType IndexOfByKey(const KeyType& Key) const
1404 {
1405 const ElementType* RESTRICT Start = GetData();
1406 for (const ElementType* RESTRICT Data = Start, *RESTRICT DataEnd = Start + ArrayNum; Data != DataEnd; ++Data)
1407 {
1408 if (*Data == Key)
1409 {
1410 return static_cast<SizeType>(Data - Start);
1411 }
1412 }
1413 return INDEX_NONE;
1414 }
1415
1422 template <typename Predicate>
1424 {
1425 const ElementType* RESTRICT Start = GetData();
1426 for (const ElementType* RESTRICT Data = Start, *RESTRICT DataEnd = Start + ArrayNum; Data != DataEnd; ++Data)
1427 {
1428 if (::Invoke(Pred, *Data))
1429 {
1430 return static_cast<SizeType>(Data - Start);
1431 }
1432 }
1433 return INDEX_NONE;
1434 }
1435
1444 template <typename KeyType>
1445 [[nodiscard]] ElementType* FindByKey(const KeyType& Key)
1446 {
1447 for (ElementType* RESTRICT Data = GetData(), *RESTRICT DataEnd = Data + ArrayNum; Data != DataEnd; ++Data)
1448 {
1449 if (*Data == Key)
1450 {
1451 return Data;
1452 }
1453 }
1454
1455 return nullptr;
1456 }
1457 template <typename KeyType>
1458 [[nodiscard]] UE_REWRITE const ElementType* FindByKey(const KeyType& Key) const
1459 {
1460 return const_cast<TArray*>(this)->FindByKey(Key);
1461 }
1462
1470 template <typename Predicate>
1472 {
1473 for (ElementType* RESTRICT Data = GetData(), *RESTRICT DataEnd = Data + ArrayNum; Data != DataEnd; ++Data)
1474 {
1475 if (::Invoke(Pred, *Data))
1476 {
1477 return Data;
1478 }
1479 }
1480
1481 return nullptr;
1482 }
1483 template <typename Predicate>
1485 {
1486 return const_cast<TArray*>(this)->FindByPredicate(Pred);
1487 }
1488
1497 template <typename Predicate>
1499 {
1501 for (const ElementType* RESTRICT Data = GetData(), *RESTRICT DataEnd = Data + ArrayNum; Data != DataEnd; ++Data)
1502 {
1503 if (::Invoke(Pred, *Data))
1504 {
1505 FilterResults.Add(*Data);
1506 }
1507 }
1508 return FilterResults;
1509 }
1510
1517 template <typename ComparisonType>
1518 [[nodiscard]] bool Contains(const ComparisonType& Item) const
1519 {
1520 for (const ElementType* RESTRICT Data = GetData(), *RESTRICT DataEnd = Data + ArrayNum; Data != DataEnd; ++Data)
1521 {
1522 if (*Data == Item)
1523 {
1524 return true;
1525 }
1526 }
1527 return false;
1528 }
1529
1537 template <typename Predicate>
1539 {
1540 return FindByPredicate(Pred) != nullptr;
1541 }
1542
1550 {
1551 SizeType Count = Num();
1552
1553 return Count == OtherArray.Num() && CompareItems(GetData(), OtherArray.GetData(), Count);
1554 }
1555
1562#if !PLATFORM_COMPILER_HAS_GENERATED_COMPARISON_OPERATORS
1564 {
1565 return !(*this == OtherArray);
1566 }
1567#endif
1568
1594 {
1595 constexpr int32 ElementSize = sizeof(ElementType);
1596 // Serialize element size to detect mismatch across platforms.
1597 int32 SerializedElementSize = ElementSize;
1599
1601 || (Ar.IsSaving() // if we are saving, we always do the ordinary serialize as a way to make sure it matches up with bulk serialization
1602 && !Ar.IsCooking() // but cooking and transacting is performance critical, so we skip that
1603 && !Ar.IsTransacting())
1604 || Ar.IsByteSwapping() // if we are byteswapping, we need to do that per-element
1605 )
1606 {
1607 Ar << *this;
1608 }
1609 else
1610 {
1611 CountBytes(Ar);
1612 if (Ar.IsLoading())
1613 {
1614 // Basic sanity checking to ensure that sizes match.
1615 if (!ensure(SerializedElementSize == ElementSize))
1616 {
1617 Ar.SetError();
1618 return;
1619 }
1620
1621 // Serialize the number of elements, block allocate the right amount of memory and deserialize
1622 // the data as a giant memory blob in a single call to Serialize. Please see the function header
1623 // for detailed documentation on limitations and implications.
1625 Ar << NewArrayNum;
1626 if (!ensure(NewArrayNum >= 0 && std::numeric_limits<SizeType>::max() / (SizeType)ElementSize >= NewArrayNum))
1627 {
1628 Ar.SetError();
1629 return;
1630 }
1633 Ar.Serialize(GetData(), (int64)NewArrayNum * (int64)ElementSize);
1634 }
1635 else if (Ar.IsSaving())
1636 {
1638 Ar << ArrayCount;
1639 Ar.Serialize(GetData(), (int64)ArrayCount * (int64)ElementSize);
1640 }
1641 }
1642 }
1643
1650 {
1651 Ar.CountBytes(ArrayNum*sizeof(ElementType), ArrayMax*sizeof(ElementType));
1652 }
1653
1665 {
1666 // Begin sensitive code! Single element additions/insertions get inlined _everywhere_ and thus
1667 // punch above their weight with respect to exe size, so we pay a lot of attention to every instruction
1668 // here until we get in to the NOINLINE functions that actually handle the growth.
1669
1670 // Modulo some register allocation and pointer offsets, inlined sites on x64 for the "Tiny" path should look roughly like:
1671 //
1672 // mov eax, dword ptr [array + 8h] // load arraynum
1673 // cmp eax, dword ptr [array + 0Ch] // load arraymax
1674 // jne [to ArrayNum++]
1675 // mov ecx, immediate representing size/alignment
1676 // lea r8, [array + 0Ch]] // array max
1677 // lea rdx, [array] // allocator instance
1678 // call
1679 // lea ecx, [rax+1] // ArrayNum++
1680 // mov dword ptr [array + 8h], ecx // Save ArrayNum
1681 //
1682
1683 // Single cmp, which we can assume because we are adding a single element.
1684 if (ArrayNum == ArrayMax)
1685 {
1686 // Both branches here write the return in to ArrayNum. This is because the function call clobbers the registers
1687 // and if we assign as part of the return into something we need, the compiler doesn't have to reload the data
1688 // into the clobbered register.
1689
1690 // When we can pack size and alignment into a single 16 bit load, we save a parameter setup instruction
1691 // for the function call. The 16 bit part is load-bearing for arm codegen.
1692 // PVS believes this is overwrought because technically sizeof() <= 255 implies alignof <= 255. I think this is far more
1693 // clear and costs nothing.
1694 if constexpr (sizeof(ElementType) <= 255 && alignof(ElementType) <= 255) // -V590
1695 {
1696 // Note that the realloc functions are templated ONLY on allocator instance so they are not duplicated
1697 // in the code for every type!
1698 ArrayNum = UE::Core::Private::ReallocGrow1_DoAlloc_Tiny<UE::Core::Private::GetAllocatorFlags<AllocatorType>()>(sizeof(ElementType) | (alignof(ElementType) << 8), AllocatorInstance, ArrayMax);
1699 }
1700 else
1701 {
1702 ArrayNum = UE::Core::Private::ReallocGrow1_DoAlloc<UE::Core::Private::GetAllocatorFlags<AllocatorType>()>(sizeof(ElementType), alignof(ElementType), AllocatorInstance, ArrayMax);
1703 }
1704 }
1705 // End sensitive code!
1706
1708 ArrayNum++;
1709 return OldArrayNum;
1710 }
1712 {
1713 // Should be SetNumUninitialized?
1714 return UE::Core::Private::ReallocGrow<UE::Core::Private::GetAllocatorFlags<AllocatorType>()>(
1715 sizeof(ElementType),
1716 alignof(ElementType),
1717 Count,
1719 ArrayNum,
1720 ArrayMax
1721 );
1722 }
1723
1724private:
1725 void InsertUninitializedImpl(SizeType Index)
1726 {
1727 // Begin sensitive code! See comments in AddUninitialized() before touching!
1728 if (ArrayNum == ArrayMax)
1729 {
1730 if constexpr (sizeof(ElementType) <= 255 && alignof(ElementType) <= 255) // -V590
1731 {
1732 ArrayNum = UE::Core::Private::ReallocGrow1_DoAlloc_Tiny<UE::Core::Private::GetAllocatorFlags<AllocatorType>()>(sizeof(ElementType) | (alignof(ElementType) << 8), AllocatorInstance, ArrayMax);
1733 }
1734 else
1735 {
1736 ArrayNum = UE::Core::Private::ReallocGrow1_DoAlloc<UE::Core::Private::GetAllocatorFlags<AllocatorType>()>(sizeof(ElementType), alignof(ElementType), AllocatorInstance, ArrayMax);
1737 }
1738 }
1739 // End sensitive code!
1741 ArrayNum++;
1743 RelocateConstructItems<ElementType>((void*)(Data + 1), Data, OldNum - Index);
1744 }
1745 void InsertUninitializedImpl(SizeType Index, SizeType Count)
1746 {
1747 // Should be SetNumUninitialized?
1748 SizeType OldNum = UE::Core::Private::ReallocGrow<UE::Core::Private::GetAllocatorFlags<AllocatorType>()>(
1749 sizeof(ElementType),
1750 alignof(ElementType),
1751 Count,
1753 ArrayNum,
1754 ArrayMax
1755 );
1757 RelocateConstructItems<ElementType>((void*)(Data + Count), Data, OldNum - Index);
1758 }
1759 template <
1760 typename OtherSizeType
1761 UE_REQUIRES(sizeof(OtherSizeType) > sizeof(SizeType))
1762 >
1763 UE_NODEBUG void InsertUninitializedImpl(SizeType Index, OtherSizeType Count)
1764 {
1765 checkf((OtherSizeType)(SizeType)Count == Count, TEXT("Invalid number of elements to add to this array type: %lld"), (long long)(SizeType)Count);
1766 return InsertUninitializedImpl(Index, (SizeType)Count);
1767 }
1768
1769public:
1783 {
1784 InsertUninitializedImpl(Index);
1785 }
1787 {
1788 InsertUninitializedImpl(Index, Count);
1789 }
1790
1804 {
1805 InsertUninitializedImpl(Index);
1807 }
1809 {
1810 InsertUninitializedImpl(Index, Count);
1812 }
1813
1826 {
1827 InsertUninitializedImpl(Index, 1);
1828 ElementType* Ptr = GetData() + Index;
1829 FMemory::Memzero(Ptr, sizeof(ElementType));
1830 return *Ptr;
1831 }
1832
1842 {
1843 InsertUninitializedImpl(Index);
1845 }
1847 {
1848 InsertUninitializedImpl(Index, Count);
1850 }
1851
1861 {
1862 InsertUninitializedImpl(Index, 1);
1863 ElementType* Ptr = GetData() + Index;
1865 return *Ptr;
1866 }
1867
1875 SizeType Insert(std::initializer_list<ElementType> InitList, const SizeType InIndex)
1876 {
1878
1879 InsertUninitializedImpl(InIndex, NumNewElements);
1881
1882 return InIndex;
1883 }
1884
1892 template <typename OtherAllocator>
1894 {
1895 check((const void*)this != (const void*)&Items);
1896
1897 auto NumNewElements = Items.Num();
1898
1899 InsertUninitializedImpl(InIndex, NumNewElements);
1901
1902 return InIndex;
1903 }
1904
1912 template <typename OtherAllocator>
1914 {
1915 check((const void*)this != (const void*)&Items);
1916
1917 auto NumNewElements = Items.Num();
1918
1919 InsertUninitializedImpl(InIndex, NumNewElements);
1920 RelocateConstructItems<ElementType>((void*)(GetData() + InIndex), Items.GetData(), NumNewElements);
1921 Items.ArrayNum = 0;
1922
1923 Items.SlackTrackerNumChanged();
1924
1925 return InIndex;
1926 }
1927
1938 {
1939 check(Ptr != nullptr);
1940
1941 InsertUninitializedImpl(Index, Count);
1942 ConstructItems<ElementType>((void*)(GetData() + Index), Ptr, Count);
1943
1944 return Index;
1945 }
1946
1956 {
1957 checkf(Addr < GetData() || Addr >= (GetData() + ArrayMax), TEXT("Attempting to use a container element (%p) which already comes from the container being modified (%p, ArrayMax: %lld, ArrayNum: %lld, SizeofElement: %zu)!"), Addr, GetData(), (long long)ArrayMax, (long long)ArrayNum, sizeof(ElementType));
1958 }
1959
1970 {
1971 CheckAddress(&Item);
1972
1973 // construct a copy in place at Index (this new operator will insert at
1974 // Index, then construct that memory with Item)
1975 InsertUninitializedImpl(Index);
1976 ::new((void*)(GetData() + Index)) ElementType(MoveTempIfPossible(Item));
1977 return Index;
1978 }
1979
1989 {
1990 CheckAddress(&Item);
1991
1992 // construct a copy in place at Index (this new operator will insert at
1993 // Index, then construct that memory with Item)
1994 InsertUninitializedImpl(Index);
1995 ::new((void*)(GetData() + Index)) ElementType(Item);
1996 return Index;
1997 }
1998
2009 {
2010 CheckAddress(&Item);
2011
2012 // construct a copy in place at Index (this new operator will insert at
2013 // Index, then construct that memory with Item)
2014 InsertUninitializedImpl(Index);
2015 ElementType* Ptr = GetData() + Index;
2016 ::new((void*)Ptr) ElementType(MoveTempIfPossible(Item));
2017 return *Ptr;
2018 }
2019
2029 {
2030 CheckAddress(&Item);
2031
2032 // construct a copy in place at Index (this new operator will insert at
2033 // Index, then construct that memory with Item)
2034 InsertUninitializedImpl(Index);
2035 ElementType* Ptr = GetData() + Index;
2036 ::new((void*)Ptr) ElementType(Item);
2037 return *Ptr;
2038 }
2039
2040private:
2041 void RemoveAtImpl(SizeType Index)
2042 {
2043 ElementType* Dest = GetData() + Index;
2044
2045 DestructItem(Dest);
2046
2047 // Skip relocation in the common case that there is nothing to move.
2048 SizeType NumToMove = (ArrayNum - Index) - 1;
2049 if (NumToMove)
2050 {
2051 RelocateConstructItems<ElementType>((void*)Dest, Dest + 1, NumToMove);
2052 }
2053 --ArrayNum;
2054
2055 SlackTrackerNumChanged();
2056 }
2057
2058 void RemoveAtImpl(SizeType Index, SizeType Count)
2059 {
2060 ElementType* Dest = GetData() + Index;
2061
2062 DestructItems(Dest, Count);
2063
2064 // Skip relocation in the common case that there is nothing to move.
2066 if (NumToMove)
2067 {
2069 }
2070 ArrayNum -= Count;
2071
2072 SlackTrackerNumChanged();
2073 }
2074
2075public:
2083 void RemoveAt(SizeType Index, EAllowShrinking AllowShrinking = UE::Core::Private::AllowShrinkingByDefault<AllocatorType>())
2084 {
2086 RemoveAtImpl(Index);
2088 {
2089 UE::Core::Private::ReallocShrink<UE::Core::Private::GetAllocatorFlags<AllocatorType>()>(
2090 sizeof(ElementType),
2091 alignof(ElementType),
2093 ArrayNum,
2094 ArrayMax
2095 );
2096 }
2097 }
2098
2108 template <UE::CIntegral CountType>
2109 UE_FORCEINLINE_HINT void RemoveAt(SizeType Index, CountType Count, EAllowShrinking AllowShrinking = UE::Core::Private::AllowShrinkingByDefault<AllocatorType>())
2110 {
2111 static_assert(!std::is_same_v<CountType, bool>, "TArray::RemoveAt: unexpected bool passed as the Count argument");
2113 if (Count)
2114 {
2115 RemoveAtImpl(Index, (SizeType)Count);
2117 {
2118 UE::Core::Private::ReallocShrink<UE::Core::Private::GetAllocatorFlags<AllocatorType>()>(
2119 sizeof(ElementType),
2120 alignof(ElementType),
2122 ArrayNum,
2123 ArrayMax
2124 );
2125 }
2126 }
2127 }
2128 template <typename CountType>
2131 {
2133 }
2134
2135private:
2136 void RemoveAtSwapImpl(SizeType Index)
2137 {
2138 ElementType* Data = GetData();
2139 ElementType* Dest = Data + Index;
2140
2141 DestructItem(Dest);
2142
2143 // Replace the elements in the hole created by the removal with elements from the end of the array, so the range of indices used by the array is contiguous.
2145 const SizeType NumElementsToMoveIntoHole = FPlatformMath::Min(1, NumElementsAfterHole);
2147 {
2149 }
2150 --ArrayNum;
2151
2152 SlackTrackerNumChanged();
2153 }
2154
2155 void RemoveAtSwapImpl(SizeType Index, SizeType Count)
2156 {
2158 ElementType* Dest = Data + Index;
2159
2160 DestructItems(Dest, Count);
2161
2162 // Replace the elements in the hole created by the removal with elements from the end of the array, so the range of indices used by the array is contiguous.
2164 const SizeType NumElementsToMoveIntoHole = FPlatformMath::Min(Count, NumElementsAfterHole);
2166 {
2168 }
2169 ArrayNum -= Count;
2170
2171 SlackTrackerNumChanged();
2172 }
2173
2174public:
2185 UE_FORCEINLINE_HINT void RemoveAtSwap(SizeType Index, EAllowShrinking AllowShrinking = UE::Core::Private::AllowShrinkingByDefault<AllocatorType>())
2186 {
2188 RemoveAtSwapImpl(Index);
2190 {
2191 UE::Core::Private::ReallocShrink<UE::Core::Private::GetAllocatorFlags<AllocatorType>()>(
2192 sizeof(ElementType),
2193 alignof(ElementType),
2195 ArrayNum,
2196 ArrayMax
2197 );
2198 }
2199 }
2200
2213 template <UE::CIntegral CountType>
2214 UE_FORCEINLINE_HINT void RemoveAtSwap(SizeType Index, CountType Count, EAllowShrinking AllowShrinking = UE::Core::Private::AllowShrinkingByDefault<AllocatorType>())
2215 {
2216 static_assert(!std::is_same_v<CountType, bool>, "TArray::RemoveAtSwap: unexpected bool passed as the Count argument");
2218 if (Count)
2219 {
2220 RemoveAtSwapImpl(Index, Count);
2222 {
2223 UE::Core::Private::ReallocShrink<UE::Core::Private::GetAllocatorFlags<AllocatorType>()>(
2224 sizeof(ElementType),
2225 alignof(ElementType),
2227 ArrayNum,
2228 ArrayMax
2229 );
2230 }
2231 }
2232 }
2233 template <typename CountType>
2234 UE_ALLOWSHRINKING_BOOL_DEPRECATED("RemoveAtSwap")
2239
2246 void Reset(SizeType NewSize = 0)
2247 {
2248 if (NewSize < 0)
2249 {
2250 // Cast to USizeType first to prevent sign extension on negative sizes, producing unusually large values.
2251 UE::Core::Private::OnInvalidArrayNum((unsigned long long)(USizeType)NewSize);
2252 }
2253
2254 // If we have space to hold the expected size, then don't reallocate
2255 if (NewSize <= ArrayMax)
2256 {
2258 ArrayNum = 0;
2259
2260 SlackTrackerNumChanged();
2261 }
2262 else
2263 {
2264 Empty(NewSize);
2265 }
2266 }
2267
2273 void Empty(SizeType Slack = 0)
2274 {
2275 if (Slack < 0)
2276 {
2277 // Cast to USizeType first to prevent sign extension on negative sizes, producing unusually large values.
2278 UE::Core::Private::OnInvalidArrayNum((unsigned long long)(USizeType)Slack);
2279 }
2280
2282
2283 checkSlow(Slack >= 0);
2284 ArrayNum = 0;
2285
2286 SlackTrackerNumChanged();
2287
2288 if (ArrayMax != Slack)
2289 {
2290 UE::Core::Private::ReallocTo<UE::Core::Private::GetAllocatorFlags<AllocatorType>()>(
2291 sizeof(ElementType),
2292 alignof(ElementType),
2293 Slack,
2295 ArrayNum,
2296 ArrayMax
2297 );
2298 }
2299 }
2300
2308 void SetNum(SizeType NewNum, EAllowShrinking AllowShrinking = UE::Core::Private::AllowShrinkingByDefault<AllocatorType>())
2309 {
2310 if (NewNum > Num())
2311 {
2312 const SizeType Diff = NewNum - ArrayNum;
2313 const SizeType Index = AddUninitialized(Diff);
2314 DefaultConstructItems<ElementType>((void*)((uint8*)AllocatorInstance.GetAllocation() + Index * sizeof(ElementType)), Diff);
2315 }
2316 else if (NewNum < 0)
2317 {
2318 // Cast to USizeType first to prevent sign extension on negative sizes, producing unusually large values.
2319 UE::Core::Private::OnInvalidArrayNum((unsigned long long)(USizeType)NewNum);
2320 }
2321 else if (NewNum < Num())
2322 {
2324 }
2325 }
2328 {
2330 }
2331
2340 void SetNumZeroed(SizeType NewNum, EAllowShrinking AllowShrinking = UE::Core::Private::AllowShrinkingByDefault<AllocatorType>())
2341 {
2342 if (NewNum > Num())
2343 {
2344 AddZeroed(NewNum - Num());
2345 }
2346 else if (NewNum < 0)
2347 {
2348 // Cast to USizeType first to prevent sign extension on negative sizes, producing unusually large values.
2349 UE::Core::Private::OnInvalidArrayNum((unsigned long long)(USizeType)NewNum);
2350 }
2351 else if (NewNum < Num())
2352 {
2354 }
2355 }
2356 UE_ALLOWSHRINKING_BOOL_DEPRECATED("SetNumZeroed")
2358 {
2360 }
2361
2369 void SetNumUninitialized(SizeType NewNum, EAllowShrinking AllowShrinking = UE::Core::Private::AllowShrinkingByDefault<AllocatorType>())
2370 {
2371 if (NewNum > Num())
2372 {
2374 }
2375 else if (NewNum < 0)
2376 {
2377 // Cast to USizeType first to prevent sign extension on negative sizes, producing unusually large values.
2378 UE::Core::Private::OnInvalidArrayNum((unsigned long long)(USizeType)NewNum);
2379 }
2380 else if (NewNum < Num())
2381 {
2383 }
2384 }
2385 UE_ALLOWSHRINKING_BOOL_DEPRECATED("SetNumUninitialized")
2390
2396 {
2397 checkSlow(NewNum <= Num() && NewNum >= 0);
2398 ArrayNum = NewNum;
2399
2400 SlackTrackerNumChanged();
2401 }
2402
2411 template <typename OtherElementType, typename OtherAllocatorType>
2413 {
2414 check((void*)this != (void*)&Source);
2415
2416 SizeType SourceCount = Source.Num();
2417
2418 // Do nothing if the source is empty.
2419 if (!SourceCount)
2420 {
2421 return;
2422 }
2423
2424 // Allocate memory for the new elements.
2426 ConstructItems<ElementType>((void*)(GetData() + Pos), Source.GetData(), SourceCount);
2427 }
2428
2435 template <typename OtherElementType, typename OtherAllocator>
2437 {
2438 check((void*)this != (void*)&Source);
2439
2440 SizeType SourceCount = Source.Num();
2441
2442 // Do nothing if the source is empty.
2443 if (!SourceCount)
2444 {
2445 return;
2446 }
2447
2448 // Allocate memory for the new elements.
2450 RelocateConstructItems<ElementType>((void*)(GetData() + Pos), Source.GetData(), SourceCount);
2451 Source.ArrayNum = 0;
2452
2453 Source.SlackTrackerNumChanged();
2454 }
2455
2462 template <
2463 typename RangeType
2466 !UE::Core::Private::TIsTArrayOrDerivedFromTArray_V<std::remove_reference_t<RangeType>> &&
2467 UE::Core::Private::TArrayElementsAreCompatible_V<ElementType, TElementType_T<RangeType>>
2468 )
2469 >
2470 void Append(RangeType&& Source)
2471 {
2472 auto InCount = GetNum(Source);
2473 checkf((InCount >= 0) && ((sizeof(InCount) < sizeof(SizeType)) || (InCount <= static_cast<decltype(InCount)>(TNumericLimits<SizeType>::Max()))), TEXT("Invalid range size: %lld"), (long long)InCount);
2474
2475 // Do nothing if the source is empty.
2476 if (!InCount)
2477 {
2478 return;
2479 }
2480
2482
2483 // Allocate memory for the new elements.
2485 ConstructItems<ElementType>((void*)(GetData() + Pos), UE::Core::Private::GetDataHelper(Source), SourceCount);
2486 }
2487
2496 {
2497 check(Ptr != nullptr || Count == 0);
2498
2500 ConstructItems<ElementType>((void*)(GetData() + Pos), Ptr, Count);
2501 }
2502
2509 UE_FORCEINLINE_HINT void Append(std::initializer_list<ElementType> InitList)
2510 {
2511 SizeType Count = (SizeType)InitList.size();
2512
2514 ConstructItems<ElementType>((void*)(GetData() + Pos), InitList.begin(), Count);
2515 }
2516
2526 {
2528 return *this;
2529 }
2530
2538 {
2539 Append(Other);
2540 return *this;
2541 }
2542
2548 UE_NODEBUG TArray& operator+=(std::initializer_list<ElementType> InitList)
2549 {
2551 return *this;
2552 }
2553
2560 template <typename... ArgsType>
2562 {
2563 // If this fails to compile when trying to call Emplace with a non-public constructor,
2564 // do not make TArray a friend.
2565 //
2566 // Instead, prefer this pattern:
2567 //
2568 // class FMyType
2569 // {
2570 // private:
2571 // struct FPrivateToken { explicit FPrivateToken() = default; };
2572 //
2573 // public:
2574 // // This has an equivalent access level to a private constructor,
2575 // // as only friends of FMyType will have access to FPrivateToken,
2576 // // but Emplace can legally call it since it's public.
2577 // explicit FMyType(FPrivateToken, int32 Int, float Real, const TCHAR* String);
2578 // };
2579 //
2580 // TArray<FMyType> Arr:
2581 //
2582 // // Won't compile if the caller doesn't have access to FMyType::FPrivateToken
2583 // Arr.Emplace(FMyType::FPrivateToken{}, 5, 3.14f, TEXT("Banana"));
2584 //
2585
2586 // Begin sensitive code! See comments in AddUninitialized() before touching!
2587 if (ArrayNum == ArrayMax)
2588 {
2589 if constexpr (sizeof(ElementType) <= 255 && alignof(ElementType) <= 255) // -V590
2590 {
2591 ArrayNum = UE::Core::Private::ReallocGrow1_DoAlloc_Tiny<UE::Core::Private::GetAllocatorFlags<AllocatorType>()>(sizeof(ElementType) | (alignof(ElementType) << 8), AllocatorInstance, ArrayMax);
2592 }
2593 else
2594 {
2595 ArrayNum = UE::Core::Private::ReallocGrow1_DoAlloc<UE::Core::Private::GetAllocatorFlags<AllocatorType>()>(sizeof(ElementType), alignof(ElementType), AllocatorInstance, ArrayMax);
2596 }
2597 }
2598 // End sensitive code!
2600 ArrayNum++;
2601 void* Ptr = (char*)AllocatorInstance.GetAllocation() + sizeof(ElementType) * OldArrayNum;
2602 (void)new (Ptr) ElementType(Forward<ArgsType>(Args)...);
2603 return OldArrayNum;
2604 }
2605
2612 template <typename... ArgsType>
2614 {
2615 // If this fails to compile when trying to call Emplace with a non-public constructor,
2616 // do not make TArray a friend.
2617 //
2618 // Instead, prefer this pattern:
2619 //
2620 // class FMyType
2621 // {
2622 // private:
2623 // struct FPrivateToken { explicit FPrivateToken() = default; };
2624 //
2625 // public:
2626 // // This has an equivalent access level to a private constructor,
2627 // // as only friends of FMyType will have access to FPrivateToken,
2628 // // but Emplace can legally call it since it's public.
2629 // explicit FMyType(FPrivateToken, int32 Int, float Real, const TCHAR* String);
2630 // };
2631 //
2632 // TArray<FMyType> Arr:
2633 //
2634 // // Won't compile if the caller doesn't have access to FMyType::FPrivateToken
2635 // Arr.Emplace(FMyType::FPrivateToken{}, 5, 3.14f, TEXT("Banana"));
2636 //
2637 // Begin sensitive code! See comments in AddUninitialized() before touching!
2638 if (ArrayNum == ArrayMax)
2639 {
2640 if constexpr (sizeof(ElementType) <= 255 && alignof(ElementType) <= 255) // -V590
2641 {
2642 // Looks weird but saves the register reload
2643 ArrayNum = UE::Core::Private::ReallocGrow1_DoAlloc_Tiny<UE::Core::Private::GetAllocatorFlags<AllocatorType>()>(sizeof(ElementType) | (alignof(ElementType) << 8), AllocatorInstance, ArrayMax);
2644 }
2645 else
2646 {
2647 // Looks weird but saves the register reload
2648 ArrayNum = UE::Core::Private::ReallocGrow1_DoAlloc<UE::Core::Private::GetAllocatorFlags<AllocatorType>()>(sizeof(ElementType), alignof(ElementType), AllocatorInstance, ArrayMax);
2649 }
2650 }
2651 // End sensitive code!
2653 ArrayNum++;
2654 void* Ptr = (char*)AllocatorInstance.GetAllocation() + sizeof(ElementType) * OldArrayNum;
2655 return *new (Ptr) ElementType(Forward<ArgsType>(Args)...);
2656 }
2657
2664 template <typename... ArgsType>
2666 {
2667 InsertUninitializedImpl(Index, 1);
2668 ::new((void*)(GetData() + Index)) ElementType(Forward<ArgsType>(Args)...);
2669 }
2670
2678 template <typename... ArgsType>
2680 {
2681 InsertUninitializedImpl(Index, 1);
2682 ElementType* Ptr = GetData() + Index;
2683 ::new((void*)Ptr) ElementType(Forward<ArgsType>(Args)...);
2684 return *Ptr;
2685 }
2686
2697 {
2698 CheckAddress(&Item);
2699 return Emplace(MoveTempIfPossible(Item));
2700 }
2701
2710 {
2711 CheckAddress(&Item);
2712 return Emplace(Item);
2713 }
2714
2729
2742
2756 {
2758 FMemory::Memzero((uint8*)AllocatorInstance.GetAllocation() + Index * sizeof(ElementType), sizeof(ElementType));
2759 return Index;
2760 }
2762 {
2764 FMemory::Memzero((uint8*)AllocatorInstance.GetAllocation() + Index*sizeof(ElementType), Count*sizeof(ElementType));
2765 return Index;
2766 }
2767
2780 {
2782 ElementType* Ptr = GetData() + Index;
2783 FMemory::Memzero(Ptr, sizeof(ElementType));
2784 return *Ptr;
2785 }
2786
2796 {
2798 DefaultConstructItems<ElementType>((void*)((uint8*)AllocatorInstance.GetAllocation() + Index * sizeof(ElementType)), 1);
2799 return Index;
2800 }
2802 {
2804 DefaultConstructItems<ElementType>((void*)((uint8*)AllocatorInstance.GetAllocation() + Index * sizeof(ElementType)), Count);
2805 return Index;
2806 }
2807
2816 {
2818 ElementType* Ptr = GetData() + Index;
2820 return *Ptr;
2821 }
2822
2823#if !UE_DEPRECATE_MUTABLE_TOBJECTPTR
2825 template <
2826 typename AliasElementType = ElementType
2828 >
2835#endif
2836
2838 template <
2839 typename AliasElementType = ElementType
2841 >
2843 {
2845 ElementCompat::ReinterpretRangeContiguous(begin(), end(), Num());
2846 return *reinterpret_cast<const TArray<typename ElementCompat::ReinterpretType>*>(this);
2847 }
2848
2855 template <
2856 typename AliasElementType = ElementType
2858 >
2866
2874 template <
2875 typename OtherAllocator,
2876 typename AliasElementType = ElementType
2878 >
2886
2895 template <
2896 typename OtherAllocator,
2897 typename AliasElementType = ElementType
2899 >
2901 {
2903
2904 auto NumNewElements = Items.Num();
2905
2906 InsertUninitializedImpl(InIndex, NumNewElements);
2907 ConstructItems<ElementType>((void*)(GetData() + InIndex), Items.GetData(), NumNewElements);
2908
2909 return InIndex;
2910 }
2911
2920 template <
2921 typename OtherAllocator,
2922 typename AliasElementType = ElementType
2924 >
2926 {
2927 check((const void*)this != (const void*)&Items);
2929
2930 auto NumNewElements = Items.Num();
2931
2932 InsertUninitializedImpl(InIndex, NumNewElements);
2933 RelocateConstructItems<ElementType>((void*)(GetData() + InIndex), Items.GetData(), NumNewElements);
2934 Items.ArrayNum = 0;
2935
2936 Items.SlackTrackerNumChanged();
2937
2938 return InIndex;
2939 }
2940
2949 template <
2950 typename AliasElementType = ElementType
2952 >
2961
2962private:
2963
2970 template <typename ArgsType>
2971 SizeType AddUniqueImpl(ArgsType&& Args)
2972 {
2974 if (Find(Args, Index))
2975 {
2976 return Index;
2977 }
2978
2979 return Add(Forward<ArgsType>(Args));
2980 }
2981
2982public:
2983
2994 {
2995 return AddUniqueImpl(MoveTempIfPossible(Item));
2996 }
2997
3006 {
3007 return AddUniqueImpl(Item);
3008 }
3009
3017 {
3018 checkSlow(Number >= 0);
3019 if (Number < 0)
3020 {
3021 // Cast to USizeType first to prevent sign extension on negative sizes, producing unusually large values.
3022 UE::Core::Private::OnInvalidArrayNum((unsigned long long)(USizeType)Number);
3023 }
3024 else if (Number > ArrayMax)
3025 {
3026 UE::Core::Private::ReallocTo<UE::Core::Private::GetAllocatorFlags<AllocatorType>()>(
3027 sizeof(ElementType),
3028 alignof(ElementType),
3029 Number,
3031 ArrayNum,
3032 ArrayMax
3033 );
3034 }
3035 }
3036
3043 void Init(const ElementType& Element, SizeType Number)
3044 {
3045 Empty(Number);
3046 for (SizeType Index = 0; Index < Number; ++Index)
3047 {
3048 Add(Element);
3049 }
3050 }
3051
3061 {
3062 SizeType Index = Find(Item);
3063 if (Index == INDEX_NONE)
3064 {
3065 return 0;
3066 }
3067
3068 auto* RemovePtr = GetData() + Index;
3069
3070 // Destruct items that match the specified Item.
3073
3074 // Update the array count
3075 --ArrayNum;
3076
3077 SlackTrackerNumChanged();
3078
3079 // Removed one item
3080 return 1;
3081 }
3082
3092 {
3093 CheckAddress(&Item);
3094
3095 // Element is non-const to preserve compatibility with existing code with a non-const operator==() member function
3096 return RemoveAll([&Item](ElementType& Element) { return Element == Item; });
3097 }
3098
3107 template <class PREDICATE_CLASS>
3109 {
3110 const SizeType OriginalNum = ArrayNum;
3111 if (!OriginalNum)
3112 {
3113 return 0; // nothing to do, loop assumes one item so need to deal with this edge case here
3114 }
3115
3116 ElementType* Data = GetData();
3117
3118 SizeType WriteIndex = 0;
3119 SizeType ReadIndex = 0;
3120 bool bNotMatch = !::Invoke(Predicate, Data[ReadIndex]); // use a ! to guarantee it can't be anything other than zero or one
3121 do
3122 {
3123 SizeType RunStartIndex = ReadIndex++;
3124 while (ReadIndex < OriginalNum && bNotMatch == !::Invoke(Predicate, Data[ReadIndex]))
3125 {
3126 ReadIndex++;
3127 }
3128 SizeType RunLength = ReadIndex - RunStartIndex;
3129 checkSlow(RunLength > 0);
3130 if (bNotMatch)
3131 {
3132 // this was a non-matching run, we need to move it
3133 if (WriteIndex != RunStartIndex)
3134 {
3135 RelocateConstructItems<ElementType>((void*)(Data + WriteIndex), Data + RunStartIndex, RunLength);
3136 }
3137 WriteIndex += RunLength;
3138 }
3139 else
3140 {
3141 // this was a matching run, delete it
3143 }
3145 } while (ReadIndex < OriginalNum);
3146
3147 ArrayNum = WriteIndex;
3148
3149 SlackTrackerNumChanged();
3150
3151 return OriginalNum - ArrayNum;
3152 }
3153
3162 template <class PREDICATE_CLASS>
3163 SizeType RemoveAllSwap(const PREDICATE_CLASS& Predicate, EAllowShrinking AllowShrinking = UE::Core::Private::AllowShrinkingByDefault<AllocatorType>())
3164 {
3165 bool bRemoved = false;
3166 const SizeType OriginalNum = ArrayNum;
3167 for (SizeType ItemIndex = 0; ItemIndex < Num();)
3168 {
3169 if (::Invoke(Predicate, (*this)[ItemIndex]))
3170 {
3171 bRemoved = true;
3173 }
3174 else
3175 {
3176 ++ItemIndex;
3177 }
3178 }
3179
3180 if (bRemoved && AllowShrinking == EAllowShrinking::Yes)
3181 {
3182 UE::Core::Private::ReallocShrink<UE::Core::Private::GetAllocatorFlags<AllocatorType>()>(
3183 sizeof(ElementType),
3184 alignof(ElementType),
3186 ArrayNum,
3187 ArrayMax
3188 );
3189 }
3190
3191 return OriginalNum - ArrayNum;
3192 }
3193 template <class PREDICATE_CLASS>
3194 UE_ALLOWSHRINKING_BOOL_DEPRECATED("RemoveAllSwap")
3196 {
3197 return RemoveAllSwap(Predicate, bAllowShrinking ? EAllowShrinking::Yes : EAllowShrinking::No);
3198 }
3199
3211 SizeType RemoveSingleSwap(const ElementType& Item, EAllowShrinking AllowShrinking = UE::Core::Private::AllowShrinkingByDefault<AllocatorType>())
3212 {
3213 SizeType Index = Find(Item);
3214 if (Index == INDEX_NONE)
3215 {
3216 return 0;
3217 }
3218
3220
3221 // Removed one item
3222 return 1;
3223 }
3224 UE_ALLOWSHRINKING_BOOL_DEPRECATED("RemoveSingleSwap")
3226 {
3227 return RemoveSingleSwap(Item, bAllowShrinking ? EAllowShrinking::Yes : EAllowShrinking::No);
3228 }
3229
3244 SizeType RemoveSwap(const ElementType& Item, EAllowShrinking AllowShrinking = UE::Core::Private::AllowShrinkingByDefault<AllocatorType>())
3245 {
3246 CheckAddress(&Item);
3247
3248 const SizeType OriginalNum = ArrayNum;
3249 bool bRemoved = false;
3250 for (SizeType Index = 0; Index < ArrayNum; Index++)
3251 {
3252 if ((*this)[Index] == Item)
3253 {
3254 bRemoved = true;
3256 }
3257 }
3258
3259 if (bRemoved && AllowShrinking == EAllowShrinking::Yes)
3260 {
3261 UE::Core::Private::ReallocShrink<UE::Core::Private::GetAllocatorFlags<AllocatorType>()>(
3262 sizeof(ElementType),
3263 alignof(ElementType),
3265 ArrayNum,
3266 ArrayMax
3267 );
3268 }
3269
3270 return OriginalNum - ArrayNum;
3271 }
3274 {
3275 return RemoveSwap(Item, bAllowShrinking ? EAllowShrinking::Yes : EAllowShrinking::No);
3276 }
3277
3291
3309
3324 template<typename SearchType>
3325 bool FindItemByClass(SearchType **Item = nullptr, SizeType *ItemIndex = nullptr, SizeType StartIndex = 0) const
3326 {
3327 UClass* SearchClass = SearchType::StaticClass();
3328 for (SizeType Idx = StartIndex; Idx < ArrayNum; Idx++)
3329 {
3330 if ((*this)[Idx] != nullptr && (*this)[Idx]->IsA(SearchClass))
3331 {
3332 if (Item != nullptr)
3333 {
3334 *Item = (SearchType*)((*this)[Idx]);
3335 }
3336 if (ItemIndex != nullptr)
3337 {
3338 *ItemIndex = Idx;
3339 }
3340 return true;
3341 }
3342 }
3343 return false;
3344 }
3345
3346 // Iterators
3349
3356 {
3357 return TIterator(*this);
3358 }
3359
3366 {
3367 return TConstIterator(*this);
3368 }
3369
3370 #if TARRAY_RANGED_FOR_CHECKS
3375 #else
3380 #endif
3381
3382public:
3383
3388 #if TARRAY_RANGED_FOR_CHECKS
3397 #else
3406 #endif
3407
3408public:
3409
3422
3433 template <class PREDICATE_CLASS>
3439
3454
3467 template <class PREDICATE_CLASS>
3473
3474#if defined(_MSC_VER) && !defined(__clang__) // Relies on MSVC-specific lazy template instantiation to support arrays of incomplete types
3475private:
3483 {
3484 return GetData()[Index];
3485 }
3486#endif
3487
3488private:
3496 template <typename OtherElementType, typename OtherSizeType>
3498 {
3500 checkf((OtherSizeType)NewNum == OtherNum, TEXT("Invalid number of elements to add to this array type: %lld"), (long long)NewNum);
3501
3502 ArrayNum = NewNum;
3503 if (OtherNum || PrevMax)
3504 {
3505 UE::Core::Private::ReallocForCopy<UE::Core::Private::GetAllocatorFlags<AllocatorType>()>(
3506 sizeof(ElementType),
3507 alignof(ElementType),
3508 NewNum,
3509 PrevMax,
3511 ArrayNum,
3512 ArrayMax
3513 );
3515 }
3516 else
3517 {
3518 ArrayMax = AllocatorInstance.GetInitialCapacity();
3519 }
3520
3521 SlackTrackerNumChanged();
3522 }
3523
3533 template <typename OtherElementType, typename OtherSizeType>
3534 void CopyToEmptyWithSlack(const OtherElementType* OtherData, OtherSizeType OtherNum, SizeType PrevMax, SizeType ExtraSlack)
3535 {
3537 checkf((OtherSizeType)NewNum == OtherNum, TEXT("Invalid number of elements to add to this array type: %lld"), (long long)NewNum);
3538
3539 ArrayNum = NewNum;
3540 if (OtherNum || ExtraSlack || PrevMax)
3541 {
3542 USizeType NewMax = NewNum + ExtraSlack;
3543
3544 // This should only happen when we've underflowed or overflowed SizeType
3545 if ((SizeType)NewMax < NewNum)
3546 {
3547 UE::Core::Private::OnInvalidArrayNum((unsigned long long)NewMax);
3548 }
3549
3550 UE::Core::Private::ReallocForCopy<UE::Core::Private::GetAllocatorFlags<AllocatorType>()>(
3551 sizeof(ElementType),
3552 alignof(ElementType),
3553 NewNum + ExtraSlack,
3554 PrevMax,
3556 ArrayNum,
3557 ArrayMax
3558 );
3560 }
3561 else
3562 {
3563 ArrayMax = AllocatorInstance.GetInitialCapacity();
3564 }
3565
3566 SlackTrackerNumChanged();
3567 }
3568
3569protected:
3570
3571 template<typename ElementType, typename AllocatorType>
3572 friend class TIndirectArray;
3573
3577
3578public:
3580 {
3582 {
3583 this->AllocatorInstance.WriteMemoryImage(Writer, StaticGetTypeLayoutDesc<ElementType>(), this->ArrayNum);
3584 Writer.WriteBytes(this->ArrayNum);
3585 Writer.WriteBytes(this->ArrayNum);
3586 }
3587 else
3588 {
3589 // Writing non-freezable TArray is only supported for 64-bit target for now
3590 // Would need complete layout macros for all allocator types in order to properly write (empty) 32bit versions
3591 check(Writer.Is64BitTarget());
3592 Writer.WriteBytes(TArray());
3593 }
3594 }
3595
3596 void CopyUnfrozen(const FMemoryUnfreezeContent& Context, void* Dst) const
3597 {
3599 {
3600 TArray* DstArray = ::new(Dst) TArray();
3601 DstArray->SetNumZeroed(this->ArrayNum);
3602 this->AllocatorInstance.CopyUnfrozen(Context, StaticGetTypeLayoutDesc<ElementType>(), this->ArrayNum, DstArray->GetData());
3603 }
3604 else
3605 {
3606 ::new(Dst) TArray();
3607 }
3608 }
3609
3610 static void AppendHash(const FPlatformTypeLayoutParameters& LayoutParams, FSHA1& Hasher)
3611 {
3613 {
3615 }
3616 }
3617
3619 {
3621 {
3622 this->AllocatorInstance.ToString(StaticGetTypeLayoutDesc<ElementType>(), this->ArrayNum, this->ArrayMax, LayoutParams, OutContext);
3623 }
3624 }
3625
3629public:
3639 template <class PREDICATE_CLASS>
3645
3655 {
3657 }
3658
3670 template <class PREDICATE_CLASS>
3672 {
3673 // Add at the end, then sift up
3677
3678 return Result;
3679 }
3680
3692 template <class PREDICATE_CLASS>
3694 {
3695 // Add at the end, then sift up
3696 Add(InItem);
3699
3700 return Result;
3701 }
3702
3718
3734
3747 template <class PREDICATE_CLASS>
3748 void HeapPop(ElementType& OutItem, const PREDICATE_CLASS& Predicate, EAllowShrinking AllowShrinking = UE::Core::Private::AllowShrinkingByDefault<AllocatorType>())
3749 {
3750 OutItem = MoveTemp((*this)[0]);
3752
3755 }
3756 template <class PREDICATE_CLASS>
3758 UE_NODEBUG UE_FORCEINLINE_HINT void HeapPop(ElementType& OutItem, const PREDICATE_CLASS& Predicate, bool bAllowShrinking)
3759 {
3760 HeapPop(OutItem, Predicate, bAllowShrinking ? EAllowShrinking::Yes : EAllowShrinking::No);
3761 }
3762
3775 UE_NODEBUG void HeapPop(ElementType& OutItem, EAllowShrinking AllowShrinking = UE::Core::Private::AllowShrinkingByDefault<AllocatorType>())
3776 {
3778 }
3781 {
3783 }
3784
3790 template <class PREDICATE_CLASS>
3792 {
3793 check(Algo::IsHeap(*this, Predicate));
3794 }
3795
3807 template <class PREDICATE_CLASS>
3808 void HeapPopDiscard(const PREDICATE_CLASS& Predicate, EAllowShrinking AllowShrinking = UE::Core::Private::AllowShrinkingByDefault<AllocatorType>())
3809 {
3813 }
3814 template <class PREDICATE_CLASS>
3815 UE_ALLOWSHRINKING_BOOL_DEPRECATED("HeapPopDiscard")
3816 UE_NODEBUG UE_FORCEINLINE_HINT void HeapPopDiscard(const PREDICATE_CLASS& Predicate, bool bAllowShrinking)
3817 {
3818 HeapPopDiscard(Predicate, bAllowShrinking ? EAllowShrinking::Yes : EAllowShrinking::No);
3819 }
3820
3831 UE_NODEBUG void HeapPopDiscard(EAllowShrinking AllowShrinking = UE::Core::Private::AllowShrinkingByDefault<AllocatorType>())
3832 {
3834 }
3835 UE_ALLOWSHRINKING_BOOL_DEPRECATED("HeapPopDiscard")
3840
3849 {
3850 return (*this)[0];
3851 }
3852
3859 {
3860 return (*this)[0];
3861 }
3862
3875 template <class PREDICATE_CLASS>
3876 void HeapRemoveAt(SizeType Index, const PREDICATE_CLASS& Predicate, EAllowShrinking AllowShrinking = UE::Core::Private::AllowShrinkingByDefault<AllocatorType>())
3877 {
3879
3882 AlgoImpl::HeapSiftUp(GetData(), (SizeType)0, FPlatformMath::Min(Index, Num() - 1), FIdentityFunctor(), PredicateWrapper);
3883 }
3884 template <class PREDICATE_CLASS>
3885 UE_ALLOWSHRINKING_BOOL_DEPRECATED("HeapRemoveAt")
3886 UE_NODEBUG void HeapRemoveAt(SizeType Index, const PREDICATE_CLASS& Predicate, bool bAllowShrinking)
3887 {
3888 HeapRemoveAt(Index, Predicate, bAllowShrinking ? EAllowShrinking::Yes : EAllowShrinking::No);
3889 }
3890
3902 UE_NODEBUG void HeapRemoveAt(SizeType Index, EAllowShrinking AllowShrinking = UE::Core::Private::AllowShrinkingByDefault<AllocatorType>())
3903 {
3905 }
3906 UE_ALLOWSHRINKING_BOOL_DEPRECATED("HeapRemoveAt")
3908 {
3910 }
3911
3921 template <class PREDICATE_CLASS>
3927
3937 {
3939 }
3940
3949
3950 friend struct TArrayPrivateFriend;
3951};
3952
3953
3954namespace Freeze
3955{
3956 template<typename T, typename AllocatorType>
3958 {
3959 Object.WriteMemoryImage(Writer);
3960 }
3961
3962 template<typename T, typename AllocatorType>
3964 {
3965 Object.CopyUnfrozen(Context, OutDst);
3966 return sizeof(Object);
3967 }
3968
3969 template<typename T, typename AllocatorType>
3971 {
3972 return AppendHashForNameAndSize(TypeDesc.Name, sizeof(TArray<T, AllocatorType>), Hasher);
3973 }
3974
3975 template<typename T, typename AllocatorType>
3977 {
3978 // Assume alignment of array is drive by pointer
3979 return FMath::Min(8u, LayoutParams.MaxFieldAlignment);
3980 }
3981
3982 template<typename T, typename AllocatorType>
3984 {
3985 Object.ToString(LayoutParams, OutContext);
3986 }
3987}
3988
3990
3991template <typename InElementType, typename AllocatorType>
3996
3997template <typename T, typename AllocatorType>
3998struct TIsContiguousContainer<TArray<T, AllocatorType>>
3999{
4000 enum { Value = true };
4001};
4002
4006template <typename T> constexpr bool TIsTArray_V = false;
4007
4008template <typename InElementType, typename InAllocatorType> constexpr bool TIsTArray_V< TArray<InElementType, InAllocatorType>> = true;
4009template <typename InElementType, typename InAllocatorType> constexpr bool TIsTArray_V<const TArray<InElementType, InAllocatorType>> = true;
4010template <typename InElementType, typename InAllocatorType> constexpr bool TIsTArray_V< volatile TArray<InElementType, InAllocatorType>> = true;
4011template <typename InElementType, typename InAllocatorType> constexpr bool TIsTArray_V<const volatile TArray<InElementType, InAllocatorType>> = true;
4012
4013template <typename T>
4015{
4017};
4018
4019
4020//
4021// Array operator news.
4022//
4023template <typename T,typename AllocatorType>
4024UE_NODEBUG void* operator new(size_t Size, TArray<T, AllocatorType>& Array)
4025{
4026 check(Size == sizeof(T));
4027 const auto Index = Array.AddUninitialized();
4028 return &Array[Index];
4029}
4030template <typename T,typename AllocatorType>
4032{
4033 check(Size == sizeof(T));
4034 Array.InsertUninitialized(Index);
4035 return &Array[Index];
4036}
4037
4039{
4047 template<typename ElementType, typename AllocatorType>
4049 {
4050 A.CountBytes(Ar);
4051
4052 // For net archives, limit serialization to 16MB, to protect against excessive allocation
4053 using SizeType = typename AllocatorType::SizeType;
4054 constexpr SizeType MaxNetArraySerialize = (16 * 1024 * 1024) / sizeof(ElementType);
4055 SizeType SerializeNum = Ar.IsLoading() ? 0 : A.ArrayNum;
4056
4057 Ar << SerializeNum;
4058
4059 if (SerializeNum == 0)
4060 {
4061 // if we are loading, then we have to reset the size to 0, in case it isn't currently 0
4062 if (Ar.IsLoading())
4063 {
4064 A.Empty();
4065 }
4066 return Ar;
4067 }
4068
4070 {
4071 Ar.SetError();
4072 return Ar;
4073 }
4074
4075 // if we don't need to perform per-item serialization, just read it in bulk
4076 if constexpr (sizeof(ElementType) == 1 || TCanBulkSerialize<ElementType>::Value)
4077 {
4078 A.ArrayNum = SerializeNum;
4079
4080 // Serialize simple bytes which require no construction or destruction.
4081 if ((A.ArrayNum || A.ArrayMax) && Ar.IsLoading())
4082 {
4083 UE::Core::Private::ReallocForCopy<UE::Core::Private::GetAllocatorFlags<AllocatorType>()>(
4084 sizeof(ElementType),
4085 alignof(ElementType),
4086 A.ArrayNum,
4087 A.ArrayMax,
4088 A.AllocatorInstance,
4089 A.ArrayNum,
4090 A.ArrayMax
4091 );
4092 }
4093
4095 {
4097 {
4098 // Per item serialization is required for core variant types loaded from pre LWC archives, to enable conversion from float to double.
4099 A.Empty(SerializeNum);
4100 for (SizeType i = 0; i < SerializeNum; i++)
4101 {
4102 Ar << A.AddDefaulted_GetRef();
4103 }
4104 }
4105 else
4106 {
4107 Ar.Serialize(A.GetData(), A.Num() * sizeof(ElementType));
4108 }
4109 }
4110 else
4111 {
4112 Ar.Serialize(A.GetData(), A.Num() * sizeof(ElementType));
4113 }
4114
4115 }
4116 else if (Ar.IsLoading())
4117 {
4118 // Required for resetting ArrayNum
4119 A.Empty(SerializeNum);
4120
4121 for (SizeType i=0; i<SerializeNum; i++)
4122 {
4123 Ar << A.AddDefaulted_GetRef();
4124 }
4125 }
4126 else
4127 {
4128 A.ArrayNum = SerializeNum;
4129
4130 for (SizeType i=0; i<A.ArrayNum; i++)
4131 {
4132 Ar << A[i];
4133 }
4134 }
4135
4136 A.SlackTrackerNumChanged();
4137
4138 return Ar;
4139 }
4140};
4141
4142
4143template<typename ElementType, typename AllocatorType>
4148
4150template<typename InElementType, typename InAllocatorType>
4152{
4153 uint32 Hash = 0;
4154 for (const InElementType& V : A)
4155 {
4157 }
4158 return Hash;
4159}
4160
4161#if UE_ENABLE_INCLUDE_ORDER_DEPRECATED_IN_5_4
4162#include "Templates/IsSigned.h"
4163#include "Templates/AndOrNot.h"
4165#include "Templates/MakeUnsigned.h"
4166#endif
OODEFFUNC typedef void(OODLE_CALLBACK t_fp_OodleCore_Plugin_Free)(void *ptr)
EAllowShrinking
Definition AllowShrinking.h:10
#define UE_ALLOWSHRINKING_BOOL_DEPRECATED(FunctionName)
Definition AllowShrinking.h:31
#define FORCENOINLINE
Definition AndroidPlatform.h:142
#define FORCEINLINE
Definition AndroidPlatform.h:140
#define checkSlow(expr)
Definition AssertionMacros.h:332
#define check(expr)
Definition AssertionMacros.h:314
#define ensureMsgf( InExpression, InFormat,...)
Definition AssertionMacros.h:465
#define ensure( InExpression)
Definition AssertionMacros.h:464
#define checkf(expr, format,...)
Definition AssertionMacros.h:315
@ INDEX_NONE
Definition CoreMiscDefines.h:150
#define UE_STATIC_ASSERT_WARN(bExpression, Message)
Definition CoreMiscDefines.h:431
EConstEval
Definition CoreMiscDefines.h:161
@ ConstEval
Definition CoreMiscDefines.h:161
UE_NODEBUG UE_FORCEINLINE_HINT TIndexedContainerIterator< ContainerType, ElementType, SizeType > operator+(SizeType Offset, TIndexedContainerIterator< ContainerType, ElementType, SizeType > RHS)
Definition Array.h:193
UE_NODEBUG FArchive & operator<<(FArchive &Ar, TArray< ElementType, AllocatorType > &A)
Definition Array.h:4144
constexpr bool TIsTArray_V
Definition Array.h:4006
uint32 GetTypeHash(const TArray< InElementType, InAllocatorType > &A)
Definition Array.h:4151
#define UE_LIFETIMEBOUND
Definition Platform.h:812
#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
#define UE_NODEBUG
Definition Platform.h:817
FPlatformTypes::int64 int64
A 64-bit signed integer.
Definition Platform.h:1127
FPlatformTypes::int32 int32
A 32-bit signed integer.
Definition Platform.h:1125
#define UE_FORCEINLINE_HINT
Definition Platform.h:723
#define RESTRICT
Definition Platform.h:706
#define UE_REWRITE
Definition Platform.h:747
AUTORTFM_INFER UE_FORCEINLINE_HINT constexpr auto Invoke(FuncType &&Func, ArgTypes &&... Args) -> decltype(((FuncType &&) Func)((ArgTypes &&) Args...))
Definition Invoke.h:44
FORCEINLINE constexpr void DestructItem(ElementType *Element)
Definition MemoryOps.h:56
FORCEINLINE constexpr void DestructItems(ElementType *Element, SizeType Count)
Definition MemoryOps.h:81
FORCEINLINE bool CompareItems(const ElementType *A, const ElementType *B, SizeType Count)
Definition MemoryOps.h:287
UE_FORCEINLINE_HINT TSharedRef< CastToType, Mode > StaticCastSharedRef(TSharedRef< CastFromType, Mode > const &InSharedRef)
Definition SharedPointer.h:127
typename TElementType< T >::Type TElementType_T
Definition ElementType.h:57
#define DECLARE_TEMPLATE_INTRINSIC_TYPE_LAYOUT(TemplatePrefix, T)
Definition MemoryLayout.h:661
const bool
Definition NetworkReplayStreaming.h:178
#define UE_REQUIRES(...)
Definition Requires.h:86
auto GetNum(const TStringConversion< Converter, DefaultConversionSize > &Conversion) -> decltype(Conversion.Length())
Definition StringConv.h:808
auto GetData(const TStringConversion< Converter, DefaultConversionSize > &Conversion) -> decltype(Conversion.Get())
Definition StringConv.h:802
constexpr uint32 HashCombineFast(uint32 A, uint32 B)
Definition TypeHash.h:74
UE_INTRINSIC_CAST UE_REWRITE constexpr std::remove_reference_t< T > && MoveTempIfPossible(T &&Obj) noexcept
Definition UnrealTemplate.h:538
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 Size
Definition VulkanMemory.cpp:4034
uint8_t uint8
Definition binka_ue_file_header.h:8
uint16_t uint16
Definition binka_ue_file_header.h:7
uint32_t uint32
Definition binka_ue_file_header.h:6
Definition Archive.h:1208
virtual void Serialize(void *V, int64 Length)
Definition Archive.h:1689
UE_FORCEINLINE_HINT bool IsCooking() const
Definition Archive.h:641
bool IsByteSwapping()
Definition Archive.h:169
UE_FORCEINLINE_HINT bool IsLoading() const
Definition Archive.h:236
CORE_API void SetError()
Definition Archive.cpp:314
UE_FORCEINLINE_HINT bool IsSaving() const
Definition Archive.h:248
bool IsTransacting() const
Definition Archive.h:254
virtual void CountBytes(SIZE_T InNum, SIZE_T InMax)
Definition Archive.h:125
UE_FORCEINLINE_HINT bool IsError() const
Definition Archive.h:362
UE_FORCEINLINE_HINT bool IsNetArchive() const
Definition Archive.h:631
UE_FORCEINLINE_HINT FPackageFileVersion UEVer() const
Definition Archive.h:204
Definition MemoryImageWriter.h:14
CORE_API uint32 WriteBytes(const void *Data, uint32 Size)
Definition MemoryImage.cpp:2143
bool Is64BitTarget() const
Definition MemoryImageWriter.h:27
Definition MemoryImageWriter.h:78
Definition SecureHash.h:314
Definition ArrayView.h:139
Definition Array.h:670
UE_NODEBUG UE_FORCEINLINE_HINT SizeType FindLastByPredicate(Predicate Pred) const
Definition Array.h:1390
TArray & operator=(TArray< typename TContainerElementTypeCompatibility< ElementType >::CopyFromOtherType, AllocatorType > &&Other)
Definition Array.h:2859
SizeType Find(const ElementType &Item) const
Definition Array.h:1315
UE_FORCEINLINE_HINT SizeType AddUninitialized()
Definition Array.h:1664
UE_REWRITE const ElementType & operator[](SizeType Index) const UE_LIFETIMEBOUND
Definition Array.h:1184
TIndexedContainerIterator< TArray, ElementType, SizeType > TIterator
Definition Array.h:3347
SizeType ArrayMax
Definition Array.h:3576
void BulkSerialize(FArchive &Ar, bool bForcePerElementSerialization=false)
Definition Array.h:1593
InAllocatorType AllocatorType
Definition Array.h:677
UE_FORCEINLINE_HINT SizeType AddUnique(const ElementType &Item)
Definition Array.h:3005
void HeapRemoveAt(SizeType Index, const PREDICATE_CLASS &Predicate, EAllowShrinking AllowShrinking=UE::Core::Private::AllowShrinkingByDefault< AllocatorType >())
Definition Array.h:3876
void WriteMemoryImage(FMemoryImageWriter &Writer) const
Definition Array.h:3579
SizeType Remove(const ElementType &Item)
Definition Array.h:3091
ElementType * FindByPredicate(Predicate Pred)
Definition Array.h:1471
UE_NODEBUG UE_FORCEINLINE_HINT void InsertUninitialized(SizeType Index, SizeType Count)
Definition Array.h:1786
UE_NODEBUG UE_FORCEINLINE_HINT RangedForConstIteratorType begin() const
Definition Array.h:3390
UE_REWRITE SizeType Num() const
Definition Array.h:1144
void Append(TArray< OtherElementType, OtherAllocator > &&Source)
Definition Array.h:2436
UE_NODEBUG UE_FORCEINLINE_HINT ElementType & Last(SizeType IndexFromTheEnd=0) UE_LIFETIMEBOUND
Definition Array.h:1263
UE_NODEBUG UE_FORCEINLINE_HINT void InsertUninitialized(SizeType Index)
Definition Array.h:1782
UE_FORCEINLINE_HINT TArray(const ElementType *Ptr, SizeType Count)
Definition Array.h:715
UE_NODEBUG TIterator CreateIterator()
Definition Array.h:3355
void RemoveAt(SizeType Index, EAllowShrinking AllowShrinking=UE::Core::Private::AllowShrinkingByDefault< AllocatorType >())
Definition Array.h:2083
UE_FORCEINLINE_HINT void CheckAddress(const ElementType *Addr) const
Definition Array.h:1955
UE_NODEBUG void Sort(const PREDICATE_CLASS &Predicate)
Definition Array.h:3434
TCheckedPointerIterator< const ElementType, SizeType, false > RangedForConstIteratorType
Definition Array.h:3372
UE_NODEBUG void HeapSort(const PREDICATE_CLASS &Predicate)
Definition Array.h:3922
void SetNumZeroed(SizeType NewNum, EAllowShrinking AllowShrinking=UE::Core::Private::AllowShrinkingByDefault< AllocatorType >())
Definition Array.h:2340
void HeapPopDiscard(const PREDICATE_CLASS &Predicate, EAllowShrinking AllowShrinking=UE::Core::Private::AllowShrinkingByDefault< AllocatorType >())
Definition Array.h:3808
UE_REWRITE bool operator!=(const TArray &OtherArray) const
Definition Array.h:1563
UE_NODEBUG UE_FORCEINLINE_HINT void Push(ElementType &&Item)
Definition Array.h:1224
void Reset(SizeType NewSize=0)
Definition Array.h:2246
UE_NODEBUG UE_FORCEINLINE_HINT ElementType * GetData() UE_LIFETIMEBOUND
Definition Array.h:1027
void SetNumUnsafeInternal(SizeType NewNum)
Definition Array.h:2395
InElementType ElementType
Definition Array.h:676
UE_FORCEINLINE_HINT void RemoveAtSwap(SizeType Index, EAllowShrinking AllowShrinking=UE::Core::Private::AllowShrinkingByDefault< AllocatorType >())
Definition Array.h:2185
UE_NODEBUG TArray & operator+=(TArray &&Other)
Definition Array.h:2525
UE_NODEBUG void VerifyHeap(const PREDICATE_CLASS &Predicate)
Definition Array.h:3791
UE_FORCEINLINE_HINT void SwapMemory(SizeType FirstIndexToSwap, SizeType SecondIndexToSwap)
Definition Array.h:3284
UE_REWRITE const ElementType * FindByKey(const KeyType &Key) const
Definition Array.h:1458
SizeType AddDefaulted()
Definition Array.h:2795
UE_NODEBUG const ElementAllocatorType & GetAllocatorInstance() const
Definition Array.h:3941
SizeType Insert(const ElementType &Item, SizeType Index)
Definition Array.h:1988
void InsertZeroed(SizeType Index)
Definition Array.h:1803
UE_NODEBUG ElementAllocatorType & GetAllocatorInstance()
Definition Array.h:3945
UE_NODEBUG static UE_FORCEINLINE_HINT constexpr uint32 GetTypeSize()
Definition Array.h:1047
TCheckedPointerIterator< const ElementType, SizeType, true > RangedForConstReverseIteratorType
Definition Array.h:3374
UE_REWRITE SizeType Max() const
Definition Array.h:1161
UE_NODEBUG UE_FORCEINLINE_HINT RangedForConstReverseIteratorType rend() const
Definition Array.h:3396
SizeType HeapPush(ElementType &&InItem, const PREDICATE_CLASS &Predicate)
Definition Array.h:3671
UE_NODEBUG UE_FORCEINLINE_HINT RangedForIteratorType end()
Definition Array.h:3391
UE_FORCEINLINE_HINT void RemoveAtSwap(SizeType Index, CountType Count, EAllowShrinking AllowShrinking=UE::Core::Private::AllowShrinkingByDefault< AllocatorType >())
Definition Array.h:2214
UE_NODEBUG void HeapPopDiscard(EAllowShrinking AllowShrinking=UE::Core::Private::AllowShrinkingByDefault< AllocatorType >())
Definition Array.h:3831
consteval TArray(EConstEval)
Definition Array.h:701
UE_NODEBUG bool operator==(FIntrusiveUnsetOptionalState Tag) const
Definition Array.h:1014
bool Contains(const ComparisonType &Item) const
Definition Array.h:1518
void InsertDefaulted(SizeType Index)
Definition Array.h:1841
UE_NODEBUG UE_FORCEINLINE_HINT RangedForConstIteratorType end() const
Definition Array.h:3392
SizeType RemoveSingleSwap(const ElementType &Item, EAllowShrinking AllowShrinking=UE::Core::Private::AllowShrinkingByDefault< AllocatorType >())
Definition Array.h:3211
UE_FORCEINLINE_HINT TArray(TArray< OtherElementType, OtherAllocator > &&Other)
Definition Array.h:955
TArray(TArray< OtherElementType, AllocatorType > &&Other, SizeType ExtraSlack)
Definition Array.h:971
SizeType RemoveAllSwap(const PREDICATE_CLASS &Predicate, EAllowShrinking AllowShrinking=UE::Core::Private::AllowShrinkingByDefault< AllocatorType >())
Definition Array.h:3163
typename InAllocatorType::SizeType SizeType
Definition Array.h:675
UE_NODEBUG UE_FORCEINLINE_HINT SizeType Add(const ElementType &Item)
Definition Array.h:2709
UE_REWRITE const ElementType & Top() const UE_LIFETIMEBOUND
Definition Array.h:1252
UE_FORCEINLINE_HINT void RemoveAt(SizeType Index, CountType Count, EAllowShrinking AllowShrinking=UE::Core::Private::AllowShrinkingByDefault< AllocatorType >())
Definition Array.h:2109
UE_NODEBUG SizeType HeapPush(const ElementType &InItem)
Definition Array.h:3730
UE_REWRITE const ElementType * GetData() const UE_LIFETIMEBOUND
Definition Array.h:1037
UE_REWRITE bool IsEmpty() const
Definition Array.h:1133
UE_FORCEINLINE_HINT SizeType Emplace(ArgsType &&... Args)
Definition Array.h:2561
static void AppendHash(const FPlatformTypeLayoutParameters &LayoutParams, FSHA1 &Hasher)
Definition Array.h:3610
void InsertDefaulted(SizeType Index, SizeType Count)
Definition Array.h:1846
UE_FORCEINLINE_HINT ElementType & Emplace_GetRef(ArgsType &&... Args) UE_LIFETIMEBOUND
Definition Array.h:2613
ElementType & InsertDefaulted_GetRef(SizeType Index) UE_LIFETIMEBOUND
Definition Array.h:1860
void HeapPop(ElementType &OutItem, const PREDICATE_CLASS &Predicate, EAllowShrinking AllowShrinking=UE::Core::Private::AllowShrinkingByDefault< AllocatorType >())
Definition Array.h:3748
SizeType FindLast(const ElementType &Item) const
Definition Array.h:1348
TIndexedContainerIterator< const TArray, const ElementType, SizeType > TConstIterator
Definition Array.h:3348
ElementType & Insert_GetRef(const ElementType &Item, SizeType Index) UE_LIFETIMEBOUND
Definition Array.h:2028
SizeType RemoveSwap(const ElementType &Item, EAllowShrinking AllowShrinking=UE::Core::Private::AllowShrinkingByDefault< AllocatorType >())
Definition Array.h:3244
UE_FORCEINLINE_HINT void RangeCheck(SizeType Index, SizeType Count) const
Definition Array.h:1105
UE_NODEBUG void Heapify()
Definition Array.h:3654
UE_NODEBUG UE_FORCEINLINE_HINT SIZE_T NumBytes() const
Definition Array.h:1150
void Append(RangeType &&Source)
Definition Array.h:2470
UE_FORCEINLINE_HINT TArray(TArray &&Other)
Definition Array.h:940
void SetNum(SizeType NewNum, EAllowShrinking AllowShrinking=UE::Core::Private::AllowShrinkingByDefault< AllocatorType >())
Definition Array.h:2308
UE_NODEBUG UE_FORCEINLINE_HINT SizeType Add(ElementType &&Item)
Definition Array.h:2696
UE_NODEBUG UE_FORCEINLINE_HINT bool IsValidIndex(SizeType Index) const
Definition Array.h:1122
void Init(const ElementType &Element, SizeType Number)
Definition Array.h:3043
SizeType IndexOfByKey(const KeyType &Key) const
Definition Array.h:1403
UE_FORCEINLINE_HINT TArray(const TArray< OtherElementType, OtherAllocator > &Other)
Definition Array.h:752
UE_NODEBUG void HeapPop(ElementType &OutItem, EAllowShrinking AllowShrinking=UE::Core::Private::AllowShrinkingByDefault< AllocatorType >())
Definition Array.h:3775
UE_NODEBUG TArray & operator+=(std::initializer_list< ElementType > InitList)
Definition Array.h:2548
void Append(const TArray< OtherElementType, OtherAllocatorType > &Source)
Definition Array.h:2412
TArray & operator=(const TArray< ElementType, OtherAllocatorType > &Other)
Definition Array.h:804
UE_NODEBUG UE_FORCEINLINE_HINT RangedForIteratorType begin()
Definition Array.h:3389
SizeType AddDefaulted(SizeType Count)
Definition Array.h:2801
SizeType FindLastByPredicate(Predicate Pred, SizeType Count) const
Definition Array.h:1369
SizeType AddZeroed()
Definition Array.h:2755
UE_NODEBUG TArray & operator+=(const TArray &Other)
Definition Array.h:2537
UE_FORCEINLINE_HINT ElementType & EmplaceAt_GetRef(SizeType Index, ArgsType &&... Args) UE_LIFETIMEBOUND
Definition Array.h:2679
UE_NODEBUG bool operator==(const TArray &OtherArray) const
Definition Array.h:1549
UE_NODEBUG void HeapRemoveAt(SizeType Index, EAllowShrinking AllowShrinking=UE::Core::Private::AllowShrinkingByDefault< AllocatorType >())
Definition Array.h:3902
TArray & operator=(const TArray< typename TContainerElementTypeCompatibility< ElementType >::CopyFromOtherType, OtherAllocator > &Other)
Definition Array.h:2879
UE_NODEBUG UE_FORCEINLINE_HINT void Heapify(const PREDICATE_CLASS &Predicate)
Definition Array.h:3640
SizeType RemoveAll(const PREDICATE_CLASS &Predicate)
Definition Array.h:3108
UE_NODEBUG UE_FORCEINLINE_HINT bool Find(const ElementType &Item, SizeType &Index) const
Definition Array.h:1302
UE_FORCEINLINE_HINT void RangeCheck(SizeType Index) const
Definition Array.h:1088
UE_NODEBUG UE_FORCEINLINE_HINT RangedForReverseIteratorType rbegin()
Definition Array.h:3393
UE_NODEBUG void CountBytes(FArchive &Ar) const
Definition Array.h:1649
UE_NODEBUG UE_FORCEINLINE_HINT SIZE_T GetAllocatedSize(void) const
Definition Array.h:1059
UE_NODEBUG void StableSort()
Definition Array.h:3450
TArray & operator=(const TArray &Other)
Definition Array.h:817
TArray< ElementType > FilterByPredicate(Predicate Pred) const
Definition Array.h:1498
std::conditional_t< AllocatorType::NeedsElementType, typename AllocatorType::template ForElementType< ElementType >, typename AllocatorType::ForAnyElementType > ElementAllocatorType
Definition Array.h:687
UE_FORCEINLINE_HINT void Swap(SizeType FirstIndexToSwap, SizeType SecondIndexToSwap)
Definition Array.h:3300
void Append(const typename TContainerElementTypeCompatibility< ElementType >::CopyFromOtherType *Ptr, SizeType Count)
Definition Array.h:2953
UE_FORCEINLINE_HINT constexpr TArray()
Definition Array.h:694
ElementType Pop(EAllowShrinking AllowShrinking=UE::Core::Private::AllowShrinkingByDefault< AllocatorType >())
Definition Array.h:1196
SizeType AddZeroed(SizeType Count)
Definition Array.h:2761
UE_NODEBUG SizeType HeapPush(ElementType &&InItem)
Definition Array.h:3714
SizeType RemoveSingle(const ElementType &Item)
Definition Array.h:3060
UE_FORCEINLINE_HINT SizeType AddUninitialized(SizeType Count)
Definition Array.h:1711
UE_REWRITE const ElementType & Last(SizeType IndexFromTheEnd=0) const UE_LIFETIMEBOUND
Definition Array.h:1268
UE_NODEBUG UE_FORCEINLINE_HINT SizeType GetSlack() const
Definition Array.h:1069
void SetNumUninitialized(SizeType NewNum, EAllowShrinking AllowShrinking=UE::Core::Private::AllowShrinkingByDefault< AllocatorType >())
Definition Array.h:2369
UE_NODEBUG ElementType & HeapTop() UE_LIFETIMEBOUND
Definition Array.h:3858
void ToString(const FPlatformTypeLayoutParameters &LayoutParams, FMemoryToStringContext &OutContext) const
Definition Array.h:3618
TArray(const TArrayView< OtherElementType, OtherSizeType > &Other)
friend class TArray
Array that allocates elements on the heap.
Definition Array.h:672
bool FindItemByClass(SearchType **Item=nullptr, SizeType *ItemIndex=nullptr, SizeType StartIndex=0) const
Definition Array.h:3325
ElementType & AddDefaulted_GetRef() UE_LIFETIMEBOUND
Definition Array.h:2815
UE_NODEBUG TArray(FIntrusiveUnsetOptionalState Tag)
Definition Array.h:1008
UE_FORCEINLINE_HINT TArray(const TArray &Other)
Definition Array.h:762
TArray(std::initializer_list< InElementType > InitList)
Definition Array.h:734
SizeType IndexOfByPredicate(Predicate Pred) const
Definition Array.h:1423
SizeType Insert(TArray< ElementType, OtherAllocator > &&Items, const SizeType InIndex)
Definition Array.h:1913
UE_FORCEINLINE_HINT void Shrink()
Definition Array.h:1278
UE_NODEBUG const ElementType & HeapTop() const UE_LIFETIMEBOUND
Definition Array.h:3848
UE_NODEBUG UE_FORCEINLINE_HINT RangedForReverseIteratorType rend()
Definition Array.h:3395
UE_FORCEINLINE_HINT SizeType AddUnique(ElementType &&Item)
Definition Array.h:2993
void CopyUnfrozen(const FMemoryUnfreezeContent &Context, void *Dst) const
Definition Array.h:3596
ElementType & InsertZeroed_GetRef(SizeType Index) UE_LIFETIMEBOUND
Definition Array.h:1825
~TArray()
Definition Array.h:992
UE_FORCEINLINE_HINT TArray(const TArray &Other, SizeType ExtraSlack)
Definition Array.h:774
ElementAllocatorType AllocatorInstance
Definition Array.h:3574
ElementType * FindByKey(const KeyType &Key)
Definition Array.h:1445
TArray & operator=(const TArrayView< OtherElementType, OtherSizeType > &Other)
SizeType Insert(ElementType &&Item, SizeType Index)
Definition Array.h:1969
void Append(const ElementType *Ptr, SizeType Count)
Definition Array.h:2495
UE_REWRITE const ElementType * FindByPredicate(Predicate Pred) const
Definition Array.h:1484
TArray & operator=(TArray &&Other)
Definition Array.h:981
UE_NODEBUG void StableSort(const PREDICATE_CLASS &Predicate)
Definition Array.h:3468
static constexpr bool bHasIntrusiveUnsetOptionalState
Definition Array.h:1005
UE_FORCEINLINE_HINT void EmplaceAt(SizeType Index, ArgsType &&... Args)
Definition Array.h:2665
void InsertZeroed(SizeType Index, SizeType Count)
Definition Array.h:1808
UE_NODEBUG UE_FORCEINLINE_HINT bool FindLast(const ElementType &Item, SizeType &Index) const
Definition Array.h:1336
TArray & operator=(std::initializer_list< InElementType > InitList)
Definition Array.h:785
SizeType ArrayNum
Definition Array.h:3575
UE_NODEBUG UE_FORCEINLINE_HINT ElementType & Top() UE_LIFETIMEBOUND
Definition Array.h:1248
UE_NODEBUG UE_FORCEINLINE_HINT ElementType & Add_GetRef(ElementType &&Item) UE_LIFETIMEBOUND
Definition Array.h:2724
ElementType & Insert_GetRef(ElementType &&Item, SizeType Index) UE_LIFETIMEBOUND
Definition Array.h:2008
TCheckedPointerIterator< ElementType, SizeType, true > RangedForReverseIteratorType
Definition Array.h:3373
SizeType Insert(std::initializer_list< ElementType > InitList, const SizeType InIndex)
Definition Array.h:1875
UE_NODEBUG UE_FORCEINLINE_HINT ElementType & operator[](SizeType Index) UE_LIFETIMEBOUND
Definition Array.h:1171
UE_NODEBUG UE_FORCEINLINE_HINT void CheckInvariants() const
Definition Array.h:1078
void Empty(SizeType Slack=0)
Definition Array.h:2273
UE_NODEBUG UE_FORCEINLINE_HINT void Push(const ElementType &Item)
Definition Array.h:1237
SizeType Insert(const TArray< typename TContainerElementTypeCompatibility< ElementType >::CopyFromOtherType, OtherAllocator > &Items, const SizeType InIndex)
Definition Array.h:2900
UE_FORCEINLINE_HINT void Append(std::initializer_list< ElementType > InitList)
Definition Array.h:2509
SizeType HeapPush(const ElementType &InItem, const PREDICATE_CLASS &Predicate)
Definition Array.h:3693
UE_NODEBUG void Sort()
Definition Array.h:3418
UE_FORCEINLINE_HINT void Reserve(SizeType Number)
Definition Array.h:3016
UE_NODEBUG UE_FORCEINLINE_HINT bool ContainsByPredicate(Predicate Pred) const
Definition Array.h:1538
ElementType & AddZeroed_GetRef() UE_LIFETIMEBOUND
Definition Array.h:2779
UE_NODEBUG UE_FORCEINLINE_HINT ElementType & Add_GetRef(const ElementType &Item) UE_LIFETIMEBOUND
Definition Array.h:2737
TCheckedPointerIterator< ElementType, SizeType, false > RangedForIteratorType
Definition Array.h:3371
SizeType Insert(TArray< typename TContainerElementTypeCompatibility< ElementType >::CopyFromOtherType, OtherAllocator > &&Items, const SizeType InIndex)
Definition Array.h:2925
SizeType Insert(const ElementType *Ptr, SizeType Count, SizeType Index)
Definition Array.h:1937
UE_NODEBUG TConstIterator CreateConstIterator() const
Definition Array.h:3365
UE_NODEBUG UE_FORCEINLINE_HINT RangedForConstReverseIteratorType rbegin() const
Definition Array.h:3394
UE_NODEBUG void HeapSort()
Definition Array.h:3936
SizeType Insert(const TArray< ElementType, OtherAllocator > &Items, const SizeType InIndex)
Definition Array.h:1893
Definition Array.h:64
UE_NODEBUG TIndexedContainerIterator & operator-=(SizeType Offset)
Definition Array.h:111
UE_NODEBUG UE_FORCEINLINE_HINT bool operator==(const TIndexedContainerIterator &Rhs) const
Definition Array.h:174
UE_NODEBUG UE_FORCEINLINE_HINT ElementType & operator*() const
Definition Array.h:122
UE_NODEBUG SizeType GetIndex() const
Definition Array.h:139
UE_NODEBUG void RemoveCurrent()
Definition Array.h:157
UE_NODEBUG TIndexedContainerIterator operator-(SizeType Offset) const
Definition Array.h:116
UE_NODEBUG TIndexedContainerIterator operator--(int)
Definition Array.h:91
UE_NODEBUG UE_FORCEINLINE_HINT ElementType * operator->() const
Definition Array.h:127
UE_NODEBUG void RemoveCurrentSwap()
Definition Array.h:168
UE_NODEBUG TIndexedContainerIterator & operator+=(SizeType Offset)
Definition Array.h:99
UE_NODEBUG TIndexedContainerIterator(ContainerType &InContainer, SizeType StartIndex=0)
Definition Array.h:66
UE_NODEBUG void SetToEnd()
Definition Array.h:151
UE_NODEBUG void Reset()
Definition Array.h:145
UE_NODEBUG TIndexedContainerIterator & operator++()
Definition Array.h:73
UE_NODEBUG TIndexedContainerIterator operator++(int)
Definition Array.h:78
UE_NODEBUG TIndexedContainerIterator operator+(SizeType Offset) const
Definition Array.h:105
UE_NODEBUG TIndexedContainerIterator & operator--()
Definition Array.h:86
UE_NODEBUG UE_FORCEINLINE_HINT bool operator!=(const TIndexedContainerIterator &Rhs) const
Definition Array.h:179
Definition IndirectArray.h:20
Definition Class.h:3793
IndexType HeapSiftUp(RangeValueType *Heap, IndexType RootIndex, IndexType NodeIndex, const ProjectionType &InProj, const PredicateType &Predicate)
Definition BinaryHeap.h:109
void HeapSiftDown(RangeValueType *Heap, IndexType Index, const IndexType Count, const ProjectionType &InProj, const PredicateType &Predicate)
Definition BinaryHeap.h:59
UE_REWRITE void Sort(RangeType &&Range)
Definition Sort.h:16
UE_REWRITE void Heapify(RangeType &&Range)
Definition Heapify.h:20
UE_REWRITE bool IsHeap(const RangeType &Range)
Definition IsHeap.h:50
UE_REWRITE void StableSort(RangeType &&Range)
Definition StableSort.h:125
UE_REWRITE void HeapSort(RangeType &&Range)
Definition HeapSort.h:18
void ArrayMax(const TArrayView< const float > &InView1, const TArrayView< const float > &InView2, const TArrayView< float > &OutView)
Definition FloatArrayMath.cpp:740
GeometryCollection::Facades::FMuscleActivationData Data
Definition MuscleActivationConstraints.h:15
Definition Array.h:3955
CORE_API uint32 AppendHashForNameAndSize(const TCHAR *Name, uint32 Size, FSHA1 &Hasher)
Definition MemoryImage.cpp:568
UE_NODEBUG void IntrinsicWriteMemoryImage(FMemoryImageWriter &Writer, const TArray< T, AllocatorType > &Object, const FTypeLayoutDesc &)
Definition Array.h:3957
CORE_API uint32 AppendHash(const FTypeLayoutDesc &TypeDesc, const FPlatformTypeLayoutParameters &LayoutParams, FSHA1 &Hasher)
Definition MemoryImage.cpp:864
UE_NODEBUG uint32 IntrinsicUnfrozenCopy(const FMemoryUnfreezeContent &Context, const TArray< T, AllocatorType > &Object, void *OutDst)
Definition Array.h:3963
UE_NODEBUG void IntrinsicToString(const TArray< T, AllocatorType > &Object, const FTypeLayoutDesc &TypeDesc, const FPlatformTypeLayoutParameters &LayoutParams, FMemoryToStringContext &OutContext)
Definition Array.h:3983
UE_NODEBUG uint32 IntrinsicGetTargetAlignment(const TArray< T, AllocatorType > *DummyObject, const FTypeLayoutDesc &TypeDesc, const FPlatformTypeLayoutParameters &LayoutParams)
Definition Array.h:3976
UE_NODEBUG uint32 IntrinsicAppendHash(const TArray< T, AllocatorType > *DummyObject, const FTypeLayoutDesc &TypeDesc, const FPlatformTypeLayoutParameters &LayoutParams, FSHA1 &Hasher)
Definition Array.h:3970
implementation
Definition PlayInEditorLoadingScope.h:8
UE_STRING_CLASS Result(Forward< LhsType >(Lhs), RhsLen)
Definition String.cpp.inl:732
U16 Index
Definition radfft.cpp:71
Definition IdentityFunctor.h:11
Definition IntrusiveUnsetOptionalState.h:71
Definition MemoryLayout.h:51
static UE_FORCEINLINE_HINT void * Memzero(void *Dest, SIZE_T Count)
Definition UnrealMemory.h:131
Definition MemoryLayout.h:799
Definition MemoryLayout.h:108
const TCHAR * Name
Definition MemoryLayout.h:127
Definition ContainerAllocationPolicies.h:256
Definition Array.h:4039
static FArchive & Serialize(FArchive &Ar, TArray< ElementType, AllocatorType > &A)
Definition Array.h:4048
Definition Array.h:45
@ Value
Definition Array.h:46
Definition ContainerAllocationPolicies.h:261
Definition Array.h:206
UE_NODEBUG TCheckedPointerIterator(const SizeType &InNum, ElementType *InPtr)
Definition Array.h:212
UE_NODEBUG FORCEINLINE bool operator==(const TCheckedPointerIterator &Rhs) const
Definition Array.h:280
UE_NODEBUG UE_FORCEINLINE_HINT ElementType * operator->() const
Definition Array.h:219
UE_NODEBUG UE_FORCEINLINE_HINT TCheckedPointerIterator & operator++()
Definition Array.h:243
UE_NODEBUG UE_FORCEINLINE_HINT ElementType & operator*() const
Definition Array.h:231
UE_NODEBUG UE_FORCEINLINE_HINT TCheckedPointerIterator & operator--()
Definition Array.h:256
UE_NODEBUG UE_FORCEINLINE_HINT bool operator!=(const TCheckedPointerIterator &Rhs) const
Definition Array.h:269
Definition ContainerElementTypeCompatibility.h:15
InElementType CopyFromOtherType
Definition ContainerElementTypeCompatibility.h:17
static constexpr void CopyingFromOtherType()
Definition ContainerElementTypeCompatibility.h:29
Definition Sorting.h:16
Definition Array.h:296
UE_NODEBUG UE_FORCEINLINE_HINT ElementType & operator*() const
Definition Array.h:302
UE_NODEBUG UE_FORCEINLINE_HINT TDereferencingIterator & operator++()
Definition Array.h:307
UE_NODEBUG TDereferencingIterator(IteratorType InIter)
Definition Array.h:297
UE_NODEBUG UE_FORCEINLINE_HINT bool operator!=(const TDereferencingIterator &Rhs) const
Definition Array.h:313
Definition MemoryLayout.h:626
Definition UnrealTypeTraits.h:410
Definition IsContiguousContainer.h:16
static constexpr bool Value
Definition IsContiguousContainer.h:20
Definition Array.h:4015
@ Value
Definition Array.h:4016
Definition IsUECoreType.h:19
Definition UnrealTypeTraits.h:172
Definition Less.h:19
Definition NumericLimits.h:41
Definition ReverseIterate.h:13