UDocumentation UE5.7 10.02.2026 (Source)
API documentation for Unreal Engine 5.7
DynamicVector.h
Go to the documentation of this file.
1// Copyright Epic Games, Inc. All Rights Reserved.
2
3#pragma once
4
5#include <CoreMinimal.h>
9#include "VectorTypes.h"
10#include "IndexTypes.h"
11#include "Math/NumericLimits.h"
12
13namespace UE
14{
15namespace Geometry
16{
17
18using namespace UE::Math;
19
20/*
21 * Blocked array with fixed, power-of-two sized blocks.
22 *
23 * Iterator functions suitable for use with range-based for are provided
24 */
25template <typename Type, int32 BlockSize = 512>
27{
28 static_assert(BlockSize > 0, "TDynamicVector: BlockSize must be larger than zero.");
29 static_assert(((BlockSize & (BlockSize - 1)) == 0), "TDynamicVector: BlockSize must be a power of two.");
30
31 static constexpr uint32 NumBitsNeeded(const uint32 N) {
32 return N <= 1 ? 0 : 1 + NumBitsNeeded((N + 1) / 2);
33 }
34
35 static constexpr uint32 GetBlockIndex(const uint32 Index)
36 {
37 constexpr int BlockBitsShift = NumBitsNeeded(BlockSize);
38 return Index >> BlockBitsShift;
39 }
40
41 static constexpr uint32 GetIndexInBlock(const uint32 Index)
42 {
43 constexpr int BlockBitMask = BlockSize - 1;
44 return Index & BlockBitMask;
45 }
46
47public:
48 using ElementType = Type;
49
51 {
52 AddAllocatedBlock();
53 }
54
56 : CurBlock(Copy.CurBlock)
57 , CurBlockUsed(Copy.CurBlockUsed)
58 {
59 const int32 N = Copy.Blocks.Num();
60 Blocks.Reserve(N);
61 for (int32 k = 0; k < N; ++k)
62 {
63 Blocks.Add(new TBlock(*Copy.Blocks[k]));
64 }
65 }
66
68 : CurBlock(Moved.CurBlock)
69 , CurBlockUsed(Moved.CurBlockUsed)
70 , Blocks(MoveTemp(Moved.Blocks))
71 {
72 Moved.CurBlock = 0;
73 Moved.CurBlockUsed = 0;
74 Moved.AddAllocatedBlock();
75 }
76
78 {
79 if (this != &Copy)
80 {
81 const int32 N = Copy.Blocks.Num();
82 Empty(N);
83 CurBlock = Copy.CurBlock;
84 CurBlockUsed = Copy.CurBlockUsed;
85 for (int32 k = 0; k < N; ++k)
86 {
87 Blocks.Add(new TBlock(*Copy.Blocks[k]));
88 }
89 }
90 return *this;
91 }
92
94 {
95 if (this != &Moved)
96 {
97 Empty();
98
99 CurBlock = Moved.CurBlock;
100 CurBlockUsed = Moved.CurBlockUsed;
101 Blocks = MoveTemp(Moved.Blocks);
102
103 Moved.CurBlock = 0;
104 Moved.CurBlockUsed = 0;
105 Moved.AddAllocatedBlock();
106 }
107 return *this;
108 }
109
111 {
112 const uint32 N = static_cast<uint32>(Array.Num());
113 SetNum(N);
114 const Type* ArrayPtr = Array.GetData();
115 for (uint32 Idx = 0; Idx < N; ++Idx)
116 {
117 (*this)[Idx] = ArrayPtr[Idx];
118 }
119 }
120
122 {
123 const uint32 N = static_cast<uint32>(Array.Num());
124 SetNum(N);
125 const Type* ArrayPtr = Array.GetData();
126 for (uint32 Idx = 0; Idx < N; ++Idx)
127 {
128 (*this)[Idx] = ArrayPtr[Idx];
129 }
130 }
131
133 {
134 Empty();
135 }
136
137 inline void Clear();
138 inline void Fill(const Type& Value);
139 inline void Resize(unsigned int Count);
140 inline void Resize(unsigned int Count, const Type& InitValue);
142 inline bool SetMinimumSize(unsigned int Count, const Type& InitValue);
143 inline void SetNum(unsigned int Count) { Resize(Count); }
144
145 inline bool IsEmpty() const { return CurBlock == 0 && CurBlockUsed == 0; }
146 inline size_t GetLength() const { return CurBlock * BlockSize + CurBlockUsed; }
147 inline size_t Num() const { return GetLength(); }
148 static constexpr int32 GetBlockSize() { return BlockSize; }
149 inline size_t GetByteCount() const { return Blocks.Num() * BlockSize * sizeof(Type); }
150
151 inline void Add(const Type& Data);
152 template <int32 BlockSizeData> void Add(const TDynamicVector<Type, BlockSizeData>& Data);
153 void Add(const TArray<Type>& Data);
155 inline void PopBack();
156
157 inline void InsertAt(const Type& Data, unsigned int Index);
158 inline void InsertAt(const Type& Data, unsigned int Index, const Type& InitValue);
159 inline Type& ElementAt(unsigned int Index, Type InitialValue = Type{});
160
161 inline const Type& Front() const
162 {
163 checkSlow(CurBlockUsed > 0);
164 return GetElement(0, 0);
165 }
166
167 inline const Type& Back() const
168 {
169 checkSlow(CurBlockUsed > 0);
170 return GetElement(CurBlock, CurBlockUsed - 1);
171 }
172
173#if USING_ADDRESS_SANITISER
175#endif
176 const Type& operator[](uint32 Index) const
177 {
178 checkSlow(Index < Num());
179 return GetElement(GetBlockIndex(Index), GetIndexInBlock(Index));
180 }
181
182#if USING_ADDRESS_SANITISER
184#endif
186 {
187 return const_cast<Type&>(const_cast<const TDynamicVector&>(*this)[Index]);
188 }
189
190 // apply ApplyFunc() to each member sequentially
191 template <typename Func>
192 void Apply(const Func& ApplyFunc);
193
202 {
203 Vec.Serialize<false, false>(Ar);
204 return Ar;
205 }
206
213 template <bool bForceBulkSerialization = false, bool bUseCompression = false>
215
216 /*
217 * FIterator class iterates over values of vector
218 */
220 {
221 public:
222 inline const Type& operator*() const
223 {
224 return (*DVector)[Idx];
225 }
226 inline Type& operator*()
227 {
228 return (*DVector)[Idx];
229 }
230 inline FIterator& operator++() // prefix
231 {
232 Idx++;
233 return *this;
234 }
235 inline FIterator operator++(int) // postfix
236 {
237 FIterator Copy(*this);
238 Idx++;
239 return Copy;
240 }
241 inline bool operator==(const FIterator& Itr2) const
242 {
243 return DVector == Itr2.DVector && Idx == Itr2.Idx;
244 }
245 inline bool operator!=(const FIterator& Itr2) const
246 {
247 return DVector != Itr2.DVector || Idx != Itr2.Idx;
248 }
249
250 private:
251 friend class TDynamicVector;
253 : DVector(DVectorIn), Idx(IdxIn){}
254 TDynamicVector* DVector{};
255 unsigned int Idx{0};
256 };
257
260 {
261 return FIterator{this, 0};
262 }
265 {
266 return FIterator{this, (unsigned int)GetLength()};
267 }
268
269 /*
270 * FConstIterator class iterates over values of vector
271 */
273 {
274 public:
275 inline const Type& operator*() const
276 {
277 return (*DVector)[Idx];
278 }
279 inline FConstIterator& operator++() // prefix
280 {
281 Idx++;
282 return *this;
283 }
284 inline FConstIterator operator++(int) // postfix
285 {
286 FConstIterator Copy(*this);
287 Idx++;
288 return Copy;
289 }
290 inline bool operator==(const FConstIterator& Itr2) const
291 {
292 return DVector == Itr2.DVector && Idx == Itr2.Idx;
293 }
294 inline bool operator!=(const FConstIterator& Itr2) const
295 {
296 return DVector != Itr2.DVector || Idx != Itr2.Idx;
297 }
298
299 private:
300 friend class TDynamicVector;
301 FConstIterator(const TDynamicVector* DVectorIn, unsigned int IdxIn)
302 : DVector(DVectorIn), Idx(IdxIn){}
303 const TDynamicVector* DVector{};
304 unsigned int Idx{0};
305 };
306
309 {
310 return FConstIterator{this, 0};
311 }
314 {
315 return FConstIterator{this, (unsigned int)GetLength()};
316 }
317
318private:
319 struct TBlock
320 {
321 Type Elements[BlockSize];
322 };
323
324 unsigned int CurBlock{0}; //< Current block index; always points to the block with the last item in the vector, or is set to zero if the vector is empty.
325 unsigned int CurBlockUsed{0}; //< Number of used items in the current block.
326
327 TArray<TBlock*> Blocks;
328
329 void AddAllocatedBlock()
330 {
331 Blocks.Add(new TBlock);
332 }
333
335 {
336 for (int32 k = 0, N = Blocks.Num(); k < N; ++k)
337 {
338 delete Blocks[k];
339 }
341 }
342
343 const Type& GetElement(int32 BlockIndex, int32 IndexInBlock) const
344 {
345 checkSlow(0 <= BlockIndex && BlockIndex < Blocks.Num() && 0 <= IndexInBlock && IndexInBlock < BlockSize);
346 return Blocks.GetData()[BlockIndex]->Elements[IndexInBlock];
347 }
348
349 Type& GetElement(int32 BlockIndex, int32 IndexInBlock)
350 {
351 return const_cast<Type&>(const_cast<const TDynamicVector&>(*this).GetElement(BlockIndex, IndexInBlock));
352 }
353
355 {
356 if (Blocks.Num() - NewBlockCount <= 0)
357 {
358 return;
359 }
360
361 for (int32 k = NewBlockCount; k < Blocks.Num(); ++k)
362 {
363 delete Blocks[k];
364 Blocks[k] = nullptr;
365 }
367 }
368
369 template <int32 BlockSizeRhs>
371 {
372 if (Lhs.Num() != Rhs.Num())
373 {
374 return false;
375 }
376
377 if (Lhs.IsEmpty())
378 {
379 return true;
380 }
381
382 if constexpr (BlockSize == BlockSizeRhs)
383 {
384 const uint32 LhsCurBlock = Lhs.CurBlock;
386 {
387 if (!CompareItems(&Lhs.Blocks[BlockIndex]->Elements[0], &Rhs.Blocks[BlockIndex]->Elements[0], BlockSize))
388 {
389 return false;
390 }
391 }
392 return CompareItems(&Lhs.Blocks[LhsCurBlock]->Elements[0], &Rhs.Blocks[LhsCurBlock]->Elements[0], Lhs.CurBlockUsed);
393 }
394 else
395 {
396 for (int32 Index = 0, Num = Lhs.Num(); Index < Num; ++Index)
397 {
398 if (!(Lhs[Index] == Rhs[Index]))
399 {
400 return false;
401 }
402 }
403
404 return true;
405 }
406 }
407
408 template <int32 BlockSizeRhs>
410 {
411 return !(Lhs == Rhs);
412 }
413
414 void SetCurBlock(SIZE_T Count)
415 {
416 // Reset block index for the last item and used item count within the last block.
417 // This is similar to what happens when computing the indices in operator[], but we additionally account for (1) the vector being empty and (2) that the
418 // used item count within the last block needs to be one more than the index of the last item.
419 const int32 LastItemIndex = int32(Count - 1);
420 CurBlock = Count != 0 ? GetBlockIndex(LastItemIndex) : 0;
421 CurBlockUsed = Count != 0 ? GetIndexInBlock(LastItemIndex) + 1 : 0;
422 }
423};
424
425template <class Type, int N>
427{
428public:
429 TDynamicVectorN() = default;
434
435 inline void Clear()
436 {
437 Data.Clear();
438 }
439 inline void Fill(const Type& Value)
440 {
441 Data.Fill(Value);
442 }
443 inline void Resize(unsigned int Count)
444 {
445 Data.Resize(Count * N);
446 }
447 inline void Resize(unsigned int Count, const Type& InitValue)
448 {
449 Data.Resize(Count * N, InitValue);
450 }
451 inline bool IsEmpty() const
452 {
453 return Data.IsEmpty();
454 }
455 inline size_t GetLength() const
456 {
457 return Data.GetLength() / N;
458 }
459 inline int GetBlockSize() const
460 {
461 return Data.GetBlockSize();
462 }
463 inline size_t GetByteCount() const
464 {
465 return Data.GetByteCount();
466 }
467
468 // simple struct to help pass N-dimensional data without presuming a vector type (e.g. just via initializer list)
470 {
471 Type Data[N];
472 };
473
474 inline void Add(const ElementVectorN& AddData)
475 {
476 // todo specialize for N=2,3,4
477 for (int i = 0; i < N; i++)
478 {
479 Data.Add(AddData.Data[i]);
480 }
481 }
482
483 inline void PopBack()
484 {
485 for (int i = 0; i < N; i++)
486 {
487 PopBack();
488 }
489 } // TODO specialize
490
491 inline void InsertAt(const ElementVectorN& AddData, unsigned int Index)
492 {
493 for (int i = 1; i <= N; i++)
494 {
495 Data.InsertAt(AddData.Data[N - i], N * (Index + 1) - i);
496 }
497 }
498
499 inline Type& operator()(unsigned int TopIndex, unsigned int SubIndex)
500 {
501 return Data[TopIndex * N + SubIndex];
502 }
503 inline const Type& operator()(unsigned int TopIndex, unsigned int SubIndex) const
504 {
505 return Data[TopIndex * N + SubIndex];
506 }
507 inline void SetVector2(unsigned int TopIndex, const TVector2<Type>& V)
508 {
509 check(N >= 2);
510 unsigned int i = TopIndex * N;
511 Data[i] = V.X;
512 Data[i + 1] = V.Y;
513 }
514 inline void SetVector3(unsigned int TopIndex, const TVector<Type>& V)
515 {
516 check(N >= 3);
517 unsigned int i = TopIndex * N;
518 Data[i] = V.X;
519 Data[i + 1] = V.Y;
520 Data[i + 2] = V.Z;
521 }
522 inline TVector2<Type> AsVector2(unsigned int TopIndex) const
523 {
524 check(N >= 2);
525 return TVector2<Type>(
526 Data[TopIndex * N + 0],
527 Data[TopIndex * N + 1]);
528 }
529 inline TVector<Type> AsVector3(unsigned int TopIndex) const
530 {
531 check(N >= 3);
532 return TVector<Type>(
533 Data[TopIndex * N + 0],
534 Data[TopIndex * N + 1],
535 Data[TopIndex * N + 2]);
536 }
537 inline FIndex2i AsIndex2(unsigned int TopIndex) const
538 {
539 check(N >= 2);
540 return FIndex2i(
541 (int)Data[TopIndex * N + 0],
542 (int)Data[TopIndex * N + 1]);
543 }
544 inline FIndex3i AsIndex3(unsigned int TopIndex) const
545 {
546 check(N >= 3);
547 return FIndex3i(
548 (int)Data[TopIndex * N + 0],
549 (int)Data[TopIndex * N + 1],
550 (int)Data[TopIndex * N + 2]);
551 }
552 inline FIndex4i AsIndex4(unsigned int TopIndex) const
553 {
554 check(N >= 4);
555 return FIndex4i(
556 (int)Data[TopIndex * N + 0],
557 (int)Data[TopIndex * N + 1],
558 (int)Data[TopIndex * N + 2],
559 (int)Data[TopIndex * N + 3]);
560 }
561
562private:
564
565 friend class FIterator;
566};
567
568template class TDynamicVectorN<double, 2>;
569
576
577template <typename Type, int32 BlockSize>
579{
580 TruncateBlocks(1, EAllowShrinking::No);
581 CurBlock = 0;
582 CurBlockUsed = 0;
583 if (Blocks.Num() == 0)
584 {
585 AddAllocatedBlock();
586 }
587}
588
589template <typename Type, int32 BlockSize>
591{
592 for (uint32 BlockIndex = 0, NumBlocks = Blocks.Num(); BlockIndex < NumBlocks; ++BlockIndex)
593 {
594 const uint32 NumElementsInBlock = BlockIndex < NumBlocks - 1 ? BlockSize : GetLength() - BlockSize * (NumBlocks - 1);
595 for (uint32 IndexInBlock = 0; IndexInBlock < NumElementsInBlock; ++IndexInBlock)
596 {
597 GetElement(BlockIndex, IndexInBlock) = Value;
598 }
599 }
600}
601
602template <typename Type, int32 BlockSize>
604{
605 if (GetLength() == Count)
606 {
607 return;
608 }
609
610 // Determine how many blocks we need, but make sure we have at least one block available.
611 const bool bCountIsNotMultipleOfBlockSize = Count % BlockSize != 0;
612 const int32 NumBlocksNeeded = FMath::Max(1, static_cast<int32>(Count) / BlockSize + bCountIsNotMultipleOfBlockSize);
613
614 // Determine how many blocks are currently allocated.
615 int32 NumBlocksCurrent = Blocks.Num();
616
617 // Allocate needed additional blocks.
619 {
620 AddAllocatedBlock();
622 }
623
624 // Remove unneeded blocks.
626 {
627 TruncateBlocks(NumBlocksNeeded, EAllowShrinking::No);
628 }
629
630 // Set current block.
631 SetCurBlock(Count);
632}
633
634template <typename Type, int32 BlockSize>
635void TDynamicVector<Type, BlockSize>::Resize(unsigned int Count, const Type& InitValue)
636{
637 size_t nCurSize = GetLength();
638 Resize(Count);
639 for (unsigned int Index = (unsigned int)nCurSize; Index < Count; ++Index)
640 {
641 (*this)[Index] = InitValue;
642 }
643}
644
645template <typename Type, int32 BlockSize>
646bool TDynamicVector<Type, BlockSize>::SetMinimumSize(unsigned int Count, const Type& InitValue)
647{
648 size_t nCurSize = GetLength();
649 if (Count <= nCurSize)
650 {
651 return false;
652 }
653 Resize(Count);
654 for (unsigned int Index = (unsigned int)nCurSize; Index < Count; ++Index)
655 {
656 (*this)[Index] = InitValue;
657 }
658 return true;
659}
660
661template <typename Type, int32 BlockSize>
663{
664 checkSlow(size_t(MAX_uint32) >= GetLength() + 1)
665 if (CurBlockUsed == BlockSize)
666 {
667 if (CurBlock == Blocks.Num() - 1)
668 {
669 AddAllocatedBlock();
670 }
671 ++CurBlock;
672 CurBlockUsed = 0;
673 }
674 GetElement(CurBlock, CurBlockUsed) = Data;
675 ++CurBlockUsed;
676}
677
678template <typename Type, int32 BlockSize>
679template <int32 BlockSizeData>
681{
682 // @todo it could be more efficient to use memcopies here...
683 const uint32 Offset = Num();
684 const uint32 DataNum = static_cast<uint32>(Data.Num());
685 SetNum(Offset + DataNum);
686 for (uint32 DataIndex = 0; DataIndex < DataNum; ++DataIndex)
687 {
688 (*this)[Offset + DataIndex] = Data[DataIndex];
689 }
690}
691
692template <typename Type, int32 BlockSize>
694{
695 const uint32 Offset = Num();
696 const uint32 DataNum = static_cast<uint32>(Data.Num());
697 SetNum(Offset + DataNum);
698 for (uint32 DataIndex = 0; DataIndex < DataNum; ++DataIndex)
699 {
700 (*this)[Offset + DataIndex] = Data[DataIndex];
701 }
702}
703
704template <typename Type, int32 BlockSize>
706{
707 const uint32 Offset = Num();
708 const uint32 DataNum = static_cast<uint32>(Data.Num());
709 SetNum(Offset + DataNum);
710 for (uint32 DataIndex = 0; DataIndex < DataNum; ++DataIndex)
711 {
712 (*this)[Offset + DataIndex] = Data[DataIndex];
713 }
714}
715
716template <typename Type, int32 BlockSize>
718{
719 if (CurBlockUsed > 0)
720 {
721 CurBlockUsed--;
722 }
723 if (CurBlockUsed == 0 && CurBlock > 0)
724 {
725 CurBlock--;
726 CurBlockUsed = BlockSize;
727 }
728}
729
730template <typename Type, int32 BlockSize>
731Type& TDynamicVector<Type, BlockSize>::ElementAt(unsigned int Index, Type InitialValue)
732{
733 size_t s = GetLength();
734 if (Index == s)
735 {
736 Add(InitialValue);
737 }
738 else if (Index > s)
739 {
740 Resize(Index);
741 Add(InitialValue);
742 }
743 return (*this)[Index];
744}
745
746template <typename Type, int32 BlockSize>
747void TDynamicVector<Type, BlockSize>::InsertAt(const Type& Data, unsigned int Index)
748{
749 size_t s = GetLength();
750 if (Index == s)
751 {
752 Add(Data);
753 }
754 else if (Index > s)
755 {
756 Resize(Index);
757 Add(Data);
758 }
759 else
760 {
761 (*this)[Index] = Data;
762 }
763}
764
765template <typename Type, int32 BlockSize>
766void TDynamicVector<Type, BlockSize>::InsertAt(const Type& AddData, unsigned int Index, const Type& InitValue)
767{
768 size_t nCurSize = GetLength();
769 InsertAt(AddData, Index);
770 // initialize all new values up to (but not including) the inserted index
771 for (unsigned int i = (unsigned int)nCurSize; i < Index; ++i)
772 {
773 (*this)[i] = InitValue;
774 }
775}
776
777template <typename Type, int32 BlockSize>
778template <typename Func>
780{
781 for (int32 BlockIndex = 0; BlockIndex <= CurBlock; ++BlockIndex)
782 {
783 TBlock* Block = Blocks[BlockIndex];
784 const int32 NumElements = BlockIndex < CurBlock ? BlockSize : CurBlockUsed;
785 for (int32 ElementIndex = 0; ElementIndex < NumElements; ++ElementIndex)
786 {
787 ApplyFunc(Block[ElementIndex]);
788 }
789 }
790}
791
792template <typename Type, int32 BlockSize>
793template <bool bForceBulkSerialization, bool bUseCompression>
795{
797 if (Ar.IsLoading() && Ar.CustomVer(FUE5MainStreamObjectVersion::GUID) < FUE5MainStreamObjectVersion::DynamicMeshCompactedSerialization)
798 {
799 // In this version the serialization was done with a fixed block size of 512, and blocks were serialized in their entirety even if they were not
800 // fully occupied, i.e. the last block might have had garbage in it.
801 // To load this data, we first serialize all legacy blocks into a temporary buffer, and then copy out all valid elements one by one. While this
802 // solution is making an additional copies, it is simple and robust.
803
804 constexpr int32 LegacyBlockSize = 512;
805
808 int32 BlockNum = 0;
809 Ar << LegacyCurBlock;
810 Ar << LegacyCurBlockUsed;
811 Ar << BlockNum;
812
813 // Bulk serialization for a number of double types was enabled as part of the transition to Large World Coordinates.
814 // If the currently stored type is one of these types, and the archive is from before bulk serialization for these types was enabled,
815 // we need to still use per element serialization for legacy data.
816 constexpr bool bIsLWCBulkSerializedDoubleType =
817 std::is_same_v<Type, FVector2d> ||
818 std::is_same_v<Type, FVector3d> ||
819 std::is_same_v<Type, FVector4d> ||
820 std::is_same_v<Type, FQuat4d> ||
821 std::is_same_v<Type, FTransform3d>;
824
825 // Lambda for serializing a block either via bulk serializing the contained data or via serializing the block container itself.
826 // Note that the static_cast<> was necessary to resolve compiler errors when using MSVC.
828 ? static_cast<void(*)(FArchive&, Type*)>([](FArchive& Archive, Type* BlockElements)
829 {
830 Archive.Serialize(BlockElements, static_cast<int64>(LegacyBlockSize) * sizeof(Type));
831 })
832 : static_cast<void(*)(FArchive&, Type*)>([](FArchive& Archive, Type* BlockElements)
833 {
834 for (int32 Index = 0; Index < LegacyBlockSize; ++Index)
835 {
836 Archive << BlockElements[Index];
837 }
838 });
839
840 // Serialize all blocks into a temporary buffer.
843 Type* TempElementBufferPtr = TempElementBuffer.GetData();
845 {
848 }
849
850 // Add all valid elements from the temporary buffer into the vector.
853 CurBlock = 0;
854 CurBlockUsed = 0;
855 AddAllocatedBlock();
856 for (uint32 ElementIndex = 0; ElementIndex < ElementsNum; ElementIndex++)
857 {
858 Add(TempElementBuffer[ElementIndex]);
859 }
860 }
861 else
862 {
864 const SIZE_T CountBytes = sizeof(uint32) + SerializeNum * sizeof(Type);
865 Ar.CountBytes(CountBytes, CountBytes);
866 Ar << SerializeNum;
867 if (SerializeNum == 0 && Ar.IsLoading())
868 {
869 Clear();
870 }
871 else if (SerializeNum > 0)
872 {
873 SetCurBlock(SerializeNum);
874
876 static_assert(!bUseCompression || bUseBulkSerialization, "Compression only available when using bulk serialization");
877
878 // Serialize compression flag, which adds flexibility when de-serializing existing data even if some implementation details change.
881
882 // Determine number of blocks.
883 const bool bNumIsNotMultipleOfBlockSize = SerializeNum % BlockSize != 0;
884 const uint32 NumBlocks = SerializeNum / BlockSize + bNumIsNotMultipleOfBlockSize;
885
887 {
888 // When using compression, copy everything to/from a big single buffer and serialize the big buffer.
889 // This results in better compression ratios while at the same time accelerating compression.
890
893 Type* BufferPtr = Buffer.GetData();
895
896 if (!Ar.IsLoading())
897 {
898 for (uint32 Index = 0; Index < NumBlocks; ++Index)
899 {
900 const SIZE_T NumCopy = FMath::Min<SIZE_T>(NumCopyRemaining, static_cast<SIZE_T>(BlockSize));
901 FMemory::Memcpy(BufferPtr, &Blocks[Index]->Elements[0], NumCopy * sizeof(Type));
902 BufferPtr += BlockSize;
903 NumCopyRemaining -= BlockSize;
904 }
905 }
906
907 Ar.SerializeCompressedNew(Buffer.GetData(), SerializeNum * sizeof(Type), NAME_Oodle, NAME_Oodle, COMPRESS_NoFlags, false, nullptr);
908
909 if (Ar.IsLoading())
910 {
911 Empty(NumBlocks);
912 for (uint32 Index = 0; Index < NumBlocks; ++Index)
913 {
914 TBlock *const NewBlock = new TBlock;
915 const SIZE_T NumCopy = FMath::Min<SIZE_T>(NumCopyRemaining, static_cast<SIZE_T>(BlockSize));
916 FMemory::Memcpy(&NewBlock->Elements[0], BufferPtr, NumCopy * sizeof(Type));
917 Blocks.Add(NewBlock);
918 BufferPtr += BlockSize;
919 NumCopyRemaining -= BlockSize;
920 }
921 }
922 }
923 else
924 {
925 const auto SerializeBlock = [&Ar, bUseBulkSerialization](TBlock* Block, uint32 NumElements)
926 {
928 {
929 Ar.Serialize(&Block->Elements[0], NumElements * sizeof(Type));
930 }
931 else
932 {
933 for (uint32 Index = 0; Index < NumElements; ++Index)
934 {
935 Ar << Block->Elements[Index];
936 }
937 }
938 };
939
940 if (Ar.IsLoading())
941 {
942 Empty(NumBlocks);
943 for (uint32 BlockIndex = 0; BlockIndex < NumBlocks; ++BlockIndex)
944 {
945 TBlock *const NewBlock = new TBlock;
946 SerializeBlock(NewBlock, FMath::Min<uint32>(SerializeNum, BlockSize));
947 Blocks.Add(NewBlock);
948 SerializeNum -= BlockSize;
949 }
950 }
951 else
952 {
953 for (uint32 BlockIndex = 0; BlockIndex < NumBlocks; ++BlockIndex)
954 {
955 SerializeBlock(Blocks[BlockIndex], FMath::Min<uint32>(SerializeNum, BlockSize));
956 SerializeNum -= BlockSize;
957 }
958 }
959 }
960 }
961 }
962
963 if (Ar.IsLoading() && Blocks.Num() == 0)
964 {
965 AddAllocatedBlock();
966 }
967}
968
969} // end namespace UE::Geometry
970} // end namespace UE
EAllowShrinking
Definition AllowShrinking.h:10
#define FORCENOINLINE
Definition AndroidPlatform.h:142
#define checkSlow(expr)
Definition AssertionMacros.h:332
#define check(expr)
Definition AssertionMacros.h:314
@ COMPRESS_NoFlags
Definition CompressionFlags.h:28
FPlatformTypes::SIZE_T SIZE_T
An unsigned integer the same size as a pointer, the same as UPTRINT.
Definition Platform.h:1150
FPlatformTypes::int64 int64
A 64-bit signed integer.
Definition Platform.h:1127
FPlatformTypes::int32 int32
A 32-bit signed integer.
Definition Platform.h:1125
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
@ Num
Definition MetalRHIPrivate.h:234
#define MAX_uint32
Definition NumericLimits.h:21
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
int BlockIndex
Definition binka_ue_decode_test.cpp:38
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
virtual CORE_API void UsingCustomVersion(const struct FGuid &Guid)
Definition Archive.cpp:590
UE_FORCEINLINE_HINT bool IsLoading() const
Definition Archive.h:236
CORE_API int32 CustomVer(const struct FGuid &Key) const
Definition Archive.cpp:602
CORE_API void SerializeCompressedNew(void *V, int64 Length, FName CompressionFormatToEncode, FName CompressionFormatToDecodeOldV1Files, ECompressionFlags Flags=COMPRESS_NoFlags, bool bTreatBufferAsFileReader=false, int64 *OutPartialReadLength=nullptr)
Definition Archive.cpp:740
virtual void CountBytes(SIZE_T InNum, SIZE_T InMax)
Definition Archive.h:125
UE_FORCEINLINE_HINT FPackageFileVersion UEVer() const
Definition Archive.h:204
Definition ArrayView.h:139
Definition Array.h:670
UE_REWRITE SizeType Num() const
Definition Array.h:1144
void RemoveAt(SizeType Index, EAllowShrinking AllowShrinking=UE::Core::Private::AllowShrinkingByDefault< AllocatorType >())
Definition Array.h:2083
UE_NODEBUG UE_FORCEINLINE_HINT ElementType * GetData() UE_LIFETIMEBOUND
Definition Array.h:1027
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
void SetNumUninitialized(SizeType NewNum, EAllowShrinking AllowShrinking=UE::Core::Private::AllowShrinkingByDefault< AllocatorType >())
Definition Array.h:2369
void Empty(SizeType Slack=0)
Definition Array.h:2273
UE_FORCEINLINE_HINT void Reserve(SizeType Number)
Definition Array.h:3016
Definition DynamicVector.h:427
TVector2< Type > AsVector2(unsigned int TopIndex) const
Definition DynamicVector.h:522
size_t GetByteCount() const
Definition DynamicVector.h:463
friend class FIterator
Definition DynamicVector.h:565
int GetBlockSize() const
Definition DynamicVector.h:459
FIndex3i AsIndex3(unsigned int TopIndex) const
Definition DynamicVector.h:544
bool IsEmpty() const
Definition DynamicVector.h:451
TDynamicVectorN & operator=(TDynamicVectorN &&Moved)=default
void Fill(const Type &Value)
Definition DynamicVector.h:439
TDynamicVectorN(TDynamicVectorN &&Moved)=default
TDynamicVectorN(const TDynamicVectorN &Copy)=default
void SetVector2(unsigned int TopIndex, const TVector2< Type > &V)
Definition DynamicVector.h:507
TVector< Type > AsVector3(unsigned int TopIndex) const
Definition DynamicVector.h:529
void SetVector3(unsigned int TopIndex, const TVector< Type > &V)
Definition DynamicVector.h:514
FIndex4i AsIndex4(unsigned int TopIndex) const
Definition DynamicVector.h:552
void PopBack()
Definition DynamicVector.h:483
void InsertAt(const ElementVectorN &AddData, unsigned int Index)
Definition DynamicVector.h:491
const Type & operator()(unsigned int TopIndex, unsigned int SubIndex) const
Definition DynamicVector.h:503
TDynamicVectorN & operator=(const TDynamicVectorN &Copy)=default
Type & operator()(unsigned int TopIndex, unsigned int SubIndex)
Definition DynamicVector.h:499
void Add(const ElementVectorN &AddData)
Definition DynamicVector.h:474
void Resize(unsigned int Count)
Definition DynamicVector.h:443
FIndex2i AsIndex2(unsigned int TopIndex) const
Definition DynamicVector.h:537
size_t GetLength() const
Definition DynamicVector.h:455
void Clear()
Definition DynamicVector.h:435
void Resize(unsigned int Count, const Type &InitValue)
Definition DynamicVector.h:447
Definition DynamicVector.h:273
FConstIterator operator++(int)
Definition DynamicVector.h:284
const Type & operator*() const
Definition DynamicVector.h:275
bool operator==(const FConstIterator &Itr2) const
Definition DynamicVector.h:290
bool operator!=(const FConstIterator &Itr2) const
Definition DynamicVector.h:294
FConstIterator & operator++()
Definition DynamicVector.h:279
Definition DynamicVector.h:220
FIterator & operator++()
Definition DynamicVector.h:230
FIterator operator++(int)
Definition DynamicVector.h:235
bool operator!=(const FIterator &Itr2) const
Definition DynamicVector.h:245
bool operator==(const FIterator &Itr2) const
Definition DynamicVector.h:241
const Type & operator*() const
Definition DynamicVector.h:222
Type & operator*()
Definition DynamicVector.h:226
Definition DynamicVector.h:27
void InsertAt(const Type &Data, unsigned int Index, const Type &InitValue)
Definition DynamicVector.h:766
const Type & Front() const
Definition DynamicVector.h:161
TDynamicVector(TDynamicVector &&Moved)
Definition DynamicVector.h:67
size_t GetByteCount() const
Definition DynamicVector.h:149
void Add(const Type &Data)
Definition DynamicVector.h:662
const Type & Back() const
Definition DynamicVector.h:167
Type & ElementAt(unsigned int Index, Type InitialValue=Type{})
Definition DynamicVector.h:731
void InsertAt(const Type &Data, unsigned int Index)
Definition DynamicVector.h:747
TDynamicVector & operator=(const TDynamicVector &Copy)
Definition DynamicVector.h:77
bool SetMinimumSize(unsigned int Count, const Type &InitValue)
Resize if Num() is less than Count; returns true if resize occurred.
Definition DynamicVector.h:646
void PopBack()
Definition DynamicVector.h:717
void Add(TArrayView< const Type > Data)
Definition DynamicVector.h:705
TDynamicVector & operator=(TDynamicVector &&Moved)
Definition DynamicVector.h:93
friend FArchive & operator<<(FArchive &Ar, TDynamicVector &Vec)
Definition DynamicVector.h:201
TDynamicVector(const TArray< Type > &Array)
Definition DynamicVector.h:110
void Serialize(FArchive &Ar)
Definition DynamicVector.h:794
Type & operator[](uint32 Index)
Definition DynamicVector.h:185
size_t Num() const
Definition DynamicVector.h:147
TDynamicVector(const TDynamicVector &Copy)
Definition DynamicVector.h:55
void Clear()
Definition DynamicVector.h:578
FIterator end()
Definition DynamicVector.h:264
void Resize(unsigned int Count, const Type &InitValue)
Definition DynamicVector.h:635
friend bool operator==(const TDynamicVector &Lhs, const TDynamicVector< Type, BlockSizeRhs > &Rhs)
Definition DynamicVector.h:370
Type ElementType
Definition DynamicVector.h:48
TDynamicVector(TArrayView< const Type > Array)
Definition DynamicVector.h:121
FConstIterator begin() const
Definition DynamicVector.h:308
friend bool operator!=(const TDynamicVector &Lhs, const TDynamicVector< Type, BlockSizeRhs > &Rhs)
Definition DynamicVector.h:409
void Resize(unsigned int Count)
Definition DynamicVector.h:603
FConstIterator end() const
Definition DynamicVector.h:313
static constexpr int32 GetBlockSize()
Definition DynamicVector.h:148
void Apply(const Func &ApplyFunc)
Definition DynamicVector.h:779
FIterator begin()
Definition DynamicVector.h:259
~TDynamicVector()
Definition DynamicVector.h:132
bool IsEmpty() const
Definition DynamicVector.h:145
TDynamicVector()
Definition DynamicVector.h:50
size_t GetLength() const
Definition DynamicVector.h:146
void Fill(const Type &Value)
Definition DynamicVector.h:590
void Add(const TDynamicVector< Type, BlockSizeData > &Data)
Definition DynamicVector.h:680
void SetNum(unsigned int Count)
Definition DynamicVector.h:143
const Type & operator[](uint32 Index) const
Definition DynamicVector.h:176
void Add(const TArray< Type > &Data)
Definition DynamicVector.h:693
Type
Definition PawnAction_Move.h:11
Definition Sphere.cpp:10
Definition AdvancedWidgetsModule.cpp:13
U16 Index
Definition radfft.cpp:71
static UE_FORCEINLINE_HINT void * Memcpy(void *Dest, const void *Src, SIZE_T Count)
Definition UnrealMemory.h:160
CORE_API static const FGuid GUID
Definition UE5MainStreamObjectVersion.h:22
Definition Array.h:45
Definition IndexTypes.h:27
Definition IndexTypes.h:158
Definition IndexTypes.h:296
Definition DynamicVector.h:470
Type Data[N]
Definition DynamicVector.h:471
Definition Vector2D.h:38
T Y
Definition Vector2D.h:52
T X
Definition Vector2D.h:49
Definition Vector.h:51
T Z
Definition Vector.h:68
T Y
Definition Vector.h:65
T X
Definition Vector.h:62