UDocumentation UE5.7 10.02.2026 (Source)
API documentation for Unreal Engine 5.7
RingBuffer.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"
11
12#include <type_traits>
13
14template< typename ContainerType, typename ElementType, typename SizeType>
16{
17public:
18 [[nodiscard]] TRingBufferIterator(ContainerType& InContainer, SizeType StartIndex = 0)
19 : Container(InContainer)
20 , Index(StartIndex)
21 {
22 }
23
26 {
27 ++Index;
28 return *this;
29 }
31 {
32 TRingBufferIterator Tmp(*this);
33 ++Index;
34 return Tmp;
35 }
36
39 {
40 --Index;
41 return *this;
42 }
44 {
45 TRingBufferIterator Tmp(*this);
46 --Index;
47 return Tmp;
48 }
49
52 {
53 Index += Offset;
54 return *this;
55 }
56
58 {
59 TRingBufferIterator Tmp(*this);
60 return Tmp += Offset;
61 }
62
64 {
65 return *this += -Offset;
66 }
67
69 {
70 TRingBufferIterator Tmp(*this);
71 return Tmp -= Offset;
72 }
73
74 [[nodiscard]] UE_FORCEINLINE_HINT ElementType& operator*() const
75 {
76 return Container[Index];
77 }
78
79 [[nodiscard]] UE_FORCEINLINE_HINT ElementType* operator->() const
80 {
81 return &Container[Index];
82 }
83
85 [[nodiscard]] UE_FORCEINLINE_HINT explicit operator bool() const
86 {
87 return Container.IsValidIndex(Index);
88 }
89
91 [[nodiscard]] SizeType GetIndex() const
92 {
93 return Index;
94 }
95
97 void Reset()
98 {
99 Index = 0;
100 }
101
103 void SetToEnd()
104 {
105 Index = Container.Num();
106 }
107
110 {
111 Container.RemoveAt(Index);
112 --Index;
113 }
114
115 [[nodiscard]] UE_FORCEINLINE_HINT bool operator==(const TRingBufferIterator& Rhs) const { return &Container == &Rhs.Container && Index == Rhs.Index; }
116 [[nodiscard]] UE_FORCEINLINE_HINT bool operator!=(const TRingBufferIterator& Rhs) const { return &Container != &Rhs.Container || Index != Rhs.Index; }
117
118private:
119
120 ContainerType& Container;
121 SizeType Index;
122};
123
133template<typename T, typename AllocatorT = FDefaultAllocator>
135{
136public:
138 typedef T ElementType;
139 /* The Allocator type being used */
141 using ElementAllocatorType = std::conditional_t<
142 Allocator::NeedsElementType,
143 typename Allocator::template ForElementType<ElementType>,
144 typename Allocator::ForAnyElementType
145 >;
147 typedef std::make_signed_t<typename Allocator::SizeType> IndexType;
149 typedef std::make_unsigned_t<typename Allocator::SizeType> SizeType;
153private:
160 typedef std::make_unsigned_t<typename Allocator::SizeType> StorageModuloType;
161public:
162
165 : IndexMask(static_cast<StorageModuloType>(-1))
166 , Front(0u)
167 , AfterBack(0u)
168 {
169 }
170
172 [[nodiscard]] explicit TRingBuffer(SizeType InitialCapacity)
173 : TRingBuffer()
174 {
175 Reserve(InitialCapacity);
176 }
177
179 [[nodiscard]] TRingBuffer(std::initializer_list<ElementType> InitList)
181 {
182 for (const ElementType& Element : InitList)
183 {
184 Add(Element);
185 }
186 }
187
189 : TRingBuffer()
190 {
191 *this = MoveTemp(Other);
192 }
193
195 {
196 if (this == &Other)
197 {
198 return *this;
199 }
200 Empty();
201 AllocatorInstance.MoveToEmpty(Other.AllocatorInstance);
202 Swap(IndexMask, Other.IndexMask);
203 Swap(Front, Other.Front);
204 Swap(AfterBack, Other.AfterBack);
205 return *this;
206 }
207
209 :TRingBuffer()
210 {
211 *this = Other;
212 }
213
215 {
216 Empty(Other.Max());
217 for (const ElementType& Element : Other)
218 {
219 Add(Element);
220 }
221 return *this;
222 }
223
225 {
226 Empty();
227 }
228
230 [[nodiscard]] bool IsEmpty() const
231 {
232 return AfterBack == Front;
233 }
234
237 {
238 return AfterBack - Front;
239 }
240
243 {
244 return static_cast<SizeType>(IndexMask + 1);
245 }
246
249 {
250 SizeType NewCapacity = NormalizeCapacity(RequiredCapacity);
251 if (NewCapacity <= static_cast<SizeType>(Max()))
252 {
253 return;
254 }
255 Reallocate(NewCapacity);
256 }
257
259 void Trim()
260 {
261 SizeType NewCapacity = NormalizeCapacity(Num());
262 Reallocate(NewCapacity);
263 }
264
266 void Reset()
267 {
269 AfterBack = 0;
270 Front = 0;
271 }
272
274 void Empty(SizeType Capacity = 0)
275 {
276 Reset();
277 SizeType NewCapacity = NormalizeCapacity(Capacity);
278 Reallocate(NewCapacity);
279 }
280
283 {
284 IndexType ResultIndex = AddUninitialized();
285 ElementType& Result = GetAtIndexNoCheck(ResultIndex);
286 ::new ((void*)&Result) ElementType(MoveTempIfPossible(Element));
287 return ResultIndex;
288 }
289
292 {
294 ::new ((void*)&Result) ElementType(MoveTempIfPossible(Element));
295 return Result;
296 }
297
299 IndexType Add(const ElementType& Element)
300 {
301 IndexType ResultIndex = AddUninitialized();
302 ElementType& Result = GetAtIndexNoCheck(ResultIndex);
303 ::new ((void*)&Result) ElementType(Element);
304 return ResultIndex;
305 }
306
309 {
310 IndexType ResultIndex = AddUninitialized();
311 ElementType& Result = GetAtIndexNoCheck(ResultIndex);
312 ::new ((void*)&Result) ElementType(Element);
313 return Result;
314 }
315
317 template <typename... ArgsType>
319 {
320 IndexType ResultIndex = AddUninitialized();
321 ElementType& Result = GetAtIndexNoCheck(ResultIndex);
322 ::new ((void*)&Result) ElementType(Forward<ArgsType>(Args)...);
323 return ResultIndex;
324 }
325
327 template <typename... ArgsType>
329 {
331 ::new ((void*)&Result) ElementType(Forward<ArgsType>(Args)...);
332 return Result;
333 }
334
337 {
338 ConditionalIncrementCapacity();
339 // Note this increment may overflow and set AfterBack = 0. This overflow is legal;
340 // the constraint ((AfterBack - Front) == Num()) will still be true despite Front and AfterBack being
341 // on opposite sides of 0.
342 IndexType Result = static_cast<IndexType>(AfterBack++ - Front);
343 SlackTrackerNumChanged();
344 return Result;
345 }
346
352
358 {
359 if (OtherNum == 0)
360 {
361 return;
362 }
364 const SizeType OldNum = static_cast<SizeType>(Num());
365 const SizeType NewNum = OldNum + OtherNum;
366 checkf(NewNum > OldNum, TEXT("Overflow: Num() == %d, OtherNum == %d, NewNum == %d"), OldNum, OtherNum, NewNum);
368 const SizeType LocalIndexMask = IndexMask;
369
370 const SizeType MoveRangeStart = AfterBack;
371 const SizeType MoveRangeEnd = AfterBack + OtherNum;
372 const StorageModuloType MaskedMoveRangeStart = MoveRangeStart & LocalIndexMask;
373 const StorageModuloType MaskedMoveRangeEnd = MoveRangeEnd & LocalIndexMask;
374 ElementType* const Data = GetStorage();
376 {
377 // We should not be reaching capacity and overwriting front
382 }
383 else
384 {
385 // We should not be reaching capacity and overwriting front
388 }
389 AfterBack += OtherNum;
390 SlackTrackerNumChanged();
391 }
392
395 {
396 IndexType ResultIndex = AddFrontUninitialized();
397 ElementType& Result = GetAtIndexNoCheck(ResultIndex);
398 ::new ((void*)&Result) ElementType(MoveTempIfPossible(Element));
399 return ResultIndex;
400 }
401
404 {
406 ::new ((void*)&Result) ElementType(MoveTempIfPossible(Element));
407 return Result;
408 }
409
412 {
413 IndexType ResultIndex = AddFrontUninitialized();
414 ElementType& Result = GetAtIndexNoCheck(ResultIndex);
415 ::new ((void*)&Result) ElementType(Element);
416 return ResultIndex;
417 }
418
421 {
422 IndexType ResultIndex = AddFrontUninitialized();
423 ElementType& Result = GetAtIndexNoCheck(ResultIndex);
424 ::new ((void*)&Result) ElementType(Element);
425 return Result;
426 }
427
429 template <typename... ArgsType>
431 {
432 IndexType ResultIndex = AddFrontUninitialized();
433 ElementType& Result = GetAtIndexNoCheck(ResultIndex);
434 ::new ((void*)&Result) ElementType(Forward<ArgsType>(Args)...);
435 return ResultIndex;
436 }
437
439 template <typename... ArgsType>
441 {
443 ::new ((void*)&Result) ElementType(Forward<ArgsType>(Args)...);
444 return Result;
445 }
446
449 {
450 ConditionalIncrementCapacity();
451 // Note this decrement may underflow and set Front = 0xffffffff. This underflow is legal;
452 // the constraint ((AfterBack - Front) == Num()) will still be true despite Front and AfterBack being on
453 // opposite sides of 0.
454 --Front;
455 SlackTrackerNumChanged();
456 return 0;
457 }
458
464
467 {
468 return (*this)[0];
469 }
470
472 [[nodiscard]] const ElementType& First() const
473 {
474 return (*this)[0];
475 }
476
479 {
480 return (*this)[Num() - 1];
481 }
482
484 [[nodiscard]] const ElementType& Last() const
485 {
486 return (*this)[Num() - 1];
487 }
488
491 {
492 PopRangeCheck(PopCount);
494 }
495
498 {
499 DestructRange(Front, Front + PopCount);
500 // Note this increment may overflow (wrapping around to 0xffffffff) if AfterBack has already underflowed; this is valid.
501 Front += PopCount;
502 SlackTrackerNumChanged();
503 }
504
505 /* Pop one element from the front pointer of the RingBuffer and return the popped value. Invalid to call when the RingBuffer is empty. */
507 {
508 PopRangeCheck(1);
509 ElementType Result(MoveTemp(First()));
511 return Result;
512 }
513
516 {
517 PopRangeCheck(PopCount);
519 }
520
523 {
524 DestructRange(AfterBack - PopCount, AfterBack);
525 // Note this decrement may underflow (wrapping around to 0xffffffff) if Front has already underflowed; this is valid.
526 AfterBack -= PopCount;
527 SlackTrackerNumChanged();
528 }
529
530 /* Pop one element from the back pointer of the RingBuffer and return the popped value. Invalid to call when the RingBuffer is empty. */
532 {
533 PopRangeCheck(1);
534 ElementType Result(MoveTemp(Last()));
535 PopNoCheck(1);
536 return Result;
537 }
538
541 {
542 RangeCheck(Index);
543 if (Index == 0)
544 {
545 return;
546 }
547
548 ShiftLastToFirst(Front, Front + Index, -1);
549 }
550
553 {
555 RangeCheck(Index);
556 if (Index == LocalNum - 1)
557 {
558 return;
559 }
560
561 ShiftLastToFirst(AfterBack - 1, Front + Index, 1); // Note 0 <= AfterBack - 1 - (Front + Index) is <= (Num()-1) because AfterBack - Front - 1 == Num()-1 and 0 <= Index <= Num()-1
562 }
563
566 {
567 return TIterator(*this);
568 }
569
572 {
573 return TConstIterator(*this);
574 }
575
578 {
579 return TIterator(*this, Num());
580 }
581
584 {
585 return TConstIterator(*this, Num());
586 }
587
590 {
591 return Index >= 0 && Index < Num();
592 }
593
596 {
597 RangeCheck(Index);
598 return GetAtIndexNoCheck(Index);
599 }
600
603 {
604 RangeCheck(Index);
605 return GetAtIndexNoCheck(Index);
606 }
607
610 {
611 return GetStorage()[(Front + Index) & IndexMask];
612 }
613
616 {
617 return GetStorage()[(Front + Index) & IndexMask];
618 }
619
622 {
623 const ElementType* const Data = GetStorage();
624 const ElementType* const DataEnd = Data + Max();
625 const ElementType* const FrontPtr = Data + (Front & IndexMask);
627 if (Ptr >= FrontPtr)
628 {
629 if (Ptr >= DataEnd)
630 {
631 return INDEX_NONE;
632 }
633 Index = static_cast<IndexType>(Ptr - FrontPtr);
634 }
635 else
636 {
637 if (Ptr < Data)
638 {
639 return INDEX_NONE;
640 }
641 Index = static_cast<IndexType>(Ptr - Data) + static_cast<IndexType>(DataEnd - FrontPtr);
642 }
643 if (Index >= Num())
644 {
645 return INDEX_NONE;
646 }
647 return Index;
648 }
649
652 {
653 RangeCheck(Index);
654 const IndexType Capacity = Max();
655 const StorageModuloType MaskedFront = Front & IndexMask;
656 const StorageModuloType MaskedIndex = (Front + Index) & IndexMask;
657 const StorageModuloType MaskedAfterBack = AfterBack & IndexMask;
658 StorageModuloType OrderedIndex = MaskedIndex >= MaskedFront ? MaskedIndex : MaskedIndex + Capacity;
661 {
663 PopFront();
664 }
665 else
666 {
668 Pop();
669 }
670 }
671
679 {
680 return RemoveAll([&Item](const ElementType& ExistingItem) { return ExistingItem == Item; });
681 }
682
689 template <typename PredicateType>
691 {
692 if (AfterBack == Front)
693 {
694 return 0;
695 }
696
697 StorageModuloType FirstRemoval;
698 ElementType* Data = GetStorage();
699 for (FirstRemoval = Front; FirstRemoval != AfterBack; ++FirstRemoval)
700 {
701 if (Predicate(Data[FirstRemoval & IndexMask]))
702 {
703 break;
704 }
705 }
706 if (FirstRemoval == AfterBack)
707 {
708 return 0;
709 }
710
711 StorageModuloType WriteIndex = FirstRemoval;
712 StorageModuloType ReadIndex = FirstRemoval + 1;
713 while (ReadIndex != AfterBack)
714 {
715 if (!Predicate(Data[ReadIndex & IndexMask]))
716 {
717 if (NeedsDestructElements())
718 {
719 DestructItem(&Data[WriteIndex & IndexMask]);
720 }
721 ::new ((void*)&Data[WriteIndex & IndexMask]) ElementType(MoveTemp(Data[ReadIndex & IndexMask]));
722 ++WriteIndex;
723 }
724 ++ReadIndex;
725 }
726 AfterBack = WriteIndex;
727
728 SizeType NumDeleted = static_cast<SizeType>(ReadIndex - WriteIndex);
729 if (NeedsDestructElements())
730 {
731 while (WriteIndex != ReadIndex)
732 {
733 DestructItem(&Data[WriteIndex & IndexMask]);
734 ++WriteIndex;
735 }
736 }
737 SlackTrackerNumChanged();
738 return NumDeleted;
739 }
740
741 template <typename OtherAllocator>
743 {
744 const IndexType LocalNum = Num();
745 if (Other.Num() != LocalNum)
746 {
747 return false;
748 }
749 for (IndexType Index = 0; Index < LocalNum; ++Index)
750 {
751 if (!(GetAtIndexNoCheck(Index) == Other.GetAtIndexNoCheck(Index)))
752 {
753 return false;
754 }
755 }
756 return true;
757 }
758
759 template <typename OtherAllocator>
761 {
762 return !(*this == Other);
763 }
764
770 {
771 StorageModuloType MaskedFront = Front & IndexMask;
772 const StorageModuloType MaskedAfterBack = AfterBack & IndexMask;
773 if ((MaskedFront > MaskedAfterBack) | // Non-empty, non-full RingBuffer, and back pointer wraps around to be before front
774 ((MaskedFront == MaskedAfterBack) & (AfterBack != Front) & (MaskedFront != 0))) // Full, non-empty RingBuffer, and front is not at the beginning of the storage
775 {
776 Reallocate(Max());
777 MaskedFront = Front & IndexMask;
778 }
779 return TArrayView<T>(GetStorage() + MaskedFront, Num());
780 }
781
790 {
791 return Max() * sizeof(ElementType);
792 }
793
794private:
795 [[nodiscard]] static constexpr bool NeedsDestructElements()
796 {
797 return !std::is_trivially_destructible_v<T>;
798 }
799
801 void Reallocate(SizeType NewCapacity)
802 {
803 ElementType* SrcData = GetStorage();
804 const SizeType SrcCapacity = static_cast<SizeType>(Max());
805 const SizeType SrcNum = static_cast<SizeType>(Num());
806
807 check(NormalizeCapacity(NewCapacity) == NewCapacity);
809
810 StorageModuloType NewIndexMask;
811 if (NewCapacity > 0 && SrcNum > 0)
812 {
813 // Allocate SwapStorage
815 AllocatorResizeAllocation(SwapStorageBuffer, 0, NewCapacity);
817
818 // Move data to swap storage
819 const StorageModuloType MaskedFront = Front & IndexMask;
820 const StorageModuloType MaskedAfterBack = AfterBack & IndexMask;
821
822 // MaskedFront equal to MaskedAfterBack will occur if the queue's Num equals Capacity or if the Num == 0. We checked Num == 0 above, so here it means Num == Capacity.
824 {
825 StorageModuloType WriteIndex = 0;
826 for (StorageModuloType ReadIndex = MaskedFront; ReadIndex < SrcCapacity; ++ReadIndex)
827 {
828 ::new ((void*)&SwapStorage[WriteIndex++]) ElementType(MoveTemp(SrcData[ReadIndex]));
829 }
830 DestructRange(MaskedFront, SrcCapacity);
831 for (StorageModuloType ReadIndex = 0; ReadIndex < MaskedAfterBack; ++ReadIndex)
832 {
833 ::new ((void*)&SwapStorage[WriteIndex++]) ElementType(MoveTemp(SrcData[ReadIndex]));
834 }
835 DestructRange(0, MaskedAfterBack);
836 }
837 else
838 {
839 StorageModuloType WriteIndex = 0;
840 for (StorageModuloType ReadIndex = MaskedFront; ReadIndex < MaskedAfterBack; ++ReadIndex)
841 {
842 ::new((void*)&SwapStorage[WriteIndex++]) ElementType(MoveTemp(SrcData[ReadIndex]));
843 }
844 DestructRange(MaskedFront, MaskedAfterBack);
845 }
846 // Move the swap storage into this->AllocatorInstance. "Empty" in MoveToEmpty means the elements have been
847 // destructed, but the array memory might still be allocated; MoveToEmpty reallocates or frees it.
848 AllocatorInstance.MoveToEmpty(SwapStorageBuffer);
850 }
851 else
852 {
853 AllocatorResizeAllocation(AllocatorInstance, 0, NewCapacity);
854 NewIndexMask = static_cast<StorageModuloType>(NewCapacity - 1);
855 }
856
857 IndexMask = NewIndexMask;
858 Front = 0u;
859 AfterBack = SrcNum;
860 }
861
862 void AllocatorResizeAllocation(ElementAllocatorType& InAllocatorInstance, SizeType CurrentNum, SizeType NewArrayMax)
863 {
865 {
866 InAllocatorInstance.ResizeAllocation(CurrentNum, NewArrayMax, sizeof(ElementType), alignof(ElementType));
867 }
868 else
869 {
870 InAllocatorInstance.ResizeAllocation(CurrentNum, NewArrayMax, sizeof(ElementType));
871 }
872 }
873
874 void SlackTrackerNumChanged()
875 {
876#if UE_ENABLE_ARRAY_SLACK_TRACKING
878 {
879 AllocatorInstance.SlackTrackerLogNum(Num());
880 }
881#endif
882 }
883
890 void DestructRange(StorageModuloType RangeStart, StorageModuloType RangeEnd)
891 {
892 const IndexType Capacity = Max();
893 if (RangeEnd - RangeStart > static_cast<StorageModuloType>(Capacity))
894 {
895 check(false);
896 return;
897 }
898 const StorageModuloType DestructCount = RangeEnd - RangeStart;
899 if (NeedsDestructElements() && DestructCount > 0)
900 {
901 ElementType* Data = GetStorage();
902 const StorageModuloType MaskedRangeStart = RangeStart & IndexMask;
903 const StorageModuloType MaskedRangeEnd = RangeEnd & IndexMask;
905 {
906 const SizeType FirstDestructCount = (Capacity - MaskedRangeStart);
909 }
910 else
911 {
913 }
914 }
915 }
916
918 SizeType NormalizeCapacity(SizeType InCapacity)
919 {
920 // 0 -> 0
921 // All other positive integers -> RoundUpPowerOf2
922
923 SizeType ResultCapacity = (InCapacity != 0)*FMath::RoundUpToPowerOfTwo(InCapacity);
924 // Make sure we won't overflow
925 // The largest value computed for a StorageModuloType is Capacity - 1 + Capacity, so we need 2*Capacity - 1 < TNumericLimits::Max, which we simplify to 2*Capacity < TNumericLimits::Max
926 // We may also have overflowed InCapacity when we rounded it up, so check that InCapacity is less than ResultCapacity
927 checkf(((static_cast<StorageModuloType>(ResultCapacity) <= (TNumericLimits<StorageModuloType>::Max() >> 1)) & (InCapacity <= ResultCapacity)), TEXT("Integer overflow in TRingBuffer capacity"));
928 return ResultCapacity;
929 }
930
932 void ConditionalIncrementCapacity()
933 {
934 Reserve(Num() + 1);
935 }
936
944 void ShiftLastToFirst(StorageModuloType RangeFirst, StorageModuloType RangeLast, int RangeDirection)
945 {
946 // This check for Range constraint is made complicated by needing to handle overflow; only subtractions of x - y can be verified, we can't use x > y because they might be on opposite sides of unsigned 0.
947 // We also want to avoid doing a branch. TODO: Is there a FMath::Select function that does this branch-less style select?
948 check((RangeLast - RangeFirst) * (RangeDirection == 1) + (RangeFirst - RangeLast) * (RangeDirection != -1) <= static_cast<StorageModuloType>(Max()));
949
950 ElementType* Data = GetStorage();
951 ElementType Copy(MoveTemp(Data[RangeLast & IndexMask]));
952 if (NeedsDestructElements())
953 {
954 for (StorageModuloType Index = RangeLast; Index != RangeFirst; Index += RangeDirection)
955 {
956 StorageModuloType OldValueIndex = Index & IndexMask;
957 StorageModuloType NewValueIndex = (Index + RangeDirection) & IndexMask;
958 DestructItems(Data + OldValueIndex, 1);
959 ::new ((void*)(Data + OldValueIndex)) ElementType(MoveTemp(Data[NewValueIndex]));
960 }
961 StorageModuloType OldValueIndex = RangeFirst & IndexMask;
962 DestructItems(Data + OldValueIndex, 1);
963 ::new ((void*)(Data + OldValueIndex)) ElementType(MoveTemp(Copy));
964 }
965 else
966 {
967 for (StorageModuloType Index = RangeLast; Index != RangeFirst; Index += RangeDirection)
968 {
969 StorageModuloType OldValueIndex = Index & IndexMask;
970 StorageModuloType NewValueIndex = (Index + RangeDirection) & IndexMask;
971 ::new ((void*)(Data + OldValueIndex)) ElementType(MoveTemp(Data[NewValueIndex]));
972 }
973 StorageModuloType OldValueIndex = RangeFirst & IndexMask;
974 ::new ((void*)(Data + OldValueIndex)) ElementType(MoveTemp(Copy));
975 }
976 }
977
979 [[nodiscard]] UE_FORCEINLINE_HINT const ElementType* GetStorage() const
980 {
981 return const_cast<TRingBuffer*>(this)->GetStorage();
982 }
983
985 [[nodiscard]] ElementType* GetStorage()
986 {
987 return (ElementType*)AllocatorInstance.GetAllocation();
988 }
989
990 /* Check and return whether the given Index is within range. */
991 void RangeCheck(IndexType Index) const
992 {
993 if (Allocator::RequireRangeCheck) // Template property, branch will be optimized out
994 {
995 checkf((Index >= 0) & (Index < Num()), TEXT("RingBuffer index out of bounds: %i from a RingBuffer of size %i"), Index, Num());
996 }
997 }
998
999 /* Check whether the given PopSize is within range. */
1000 void PopRangeCheck(SizeType PopCount) const
1001 {
1002 if (Allocator::RequireRangeCheck) // Template property, branch will be optimized out
1003 {
1004 checkf(PopCount <= static_cast<SizeType>(Num()), TEXT("RingBuffer PopCount out of bounds: %i from a RingBuffer of size %i"), PopCount, Num());
1005 }
1006 }
1007
1008 friend class FRingBufferTest;
1009
1015 ElementAllocatorType AllocatorInstance;
1021 StorageModuloType IndexMask;
1027 StorageModuloType Front;
1036 StorageModuloType AfterBack;
1037};
1038
1039#if UE_ENABLE_INCLUDE_ORDER_DEPRECATED_IN_5_4
1041#include "Templates/MakeSigned.h"
1042#include "Templates/MakeUnsigned.h"
1043#endif
#define check(expr)
Definition AssertionMacros.h:314
#define checkf(expr, format,...)
Definition AssertionMacros.h:315
@ INDEX_NONE
Definition CoreMiscDefines.h:150
#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_FORCEINLINE_HINT
Definition Platform.h:723
FORCEINLINE constexpr void DestructItem(ElementType *Element)
Definition MemoryOps.h:56
FORCEINLINE constexpr void DestructItems(ElementType *Element, SizeType Count)
Definition MemoryOps.h:81
FORCEINLINE void MoveConstructItems(void *Dest, const ElementType *Source, SizeType Count)
Definition MemoryOps.h:242
UE_FORCEINLINE_HINT TSharedRef< CastToType, Mode > StaticCastSharedRef(TSharedRef< CastFromType, Mode > const &InSharedRef)
Definition SharedPointer.h:127
const bool
Definition NetworkReplayStreaming.h:178
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
Definition ArrayView.h:139
Definition RingBuffer.h:16
void SetToEnd()
Definition RingBuffer.h:103
TRingBufferIterator & operator--()
Definition RingBuffer.h:38
SizeType GetIndex() const
Definition RingBuffer.h:91
TRingBufferIterator operator--(int)
Definition RingBuffer.h:43
TRingBufferIterator & operator-=(SizeType Offset)
Definition RingBuffer.h:63
void Reset()
Definition RingBuffer.h:97
UE_FORCEINLINE_HINT bool operator==(const TRingBufferIterator &Rhs) const
Definition RingBuffer.h:115
TRingBufferIterator operator-(SizeType Offset) const
Definition RingBuffer.h:68
TRingBufferIterator operator+(SizeType Offset) const
Definition RingBuffer.h:57
void RemoveCurrent()
Definition RingBuffer.h:109
UE_FORCEINLINE_HINT ElementType * operator->() const
Definition RingBuffer.h:79
TRingBufferIterator & operator++()
Definition RingBuffer.h:25
TRingBufferIterator operator++(int)
Definition RingBuffer.h:30
TRingBufferIterator & operator+=(SizeType Offset)
Definition RingBuffer.h:51
UE_FORCEINLINE_HINT bool operator!=(const TRingBufferIterator &Rhs) const
Definition RingBuffer.h:116
UE_FORCEINLINE_HINT ElementType & operator*() const
Definition RingBuffer.h:74
TRingBufferIterator(ContainerType &InContainer, SizeType StartIndex=0)
Definition RingBuffer.h:18
Definition RingBuffer.h:135
void PopFrontNoCheck(SizeType PopCount=1)
Definition RingBuffer.h:497
TIterator end()
Definition RingBuffer.h:577
TIterator begin()
Definition RingBuffer.h:565
friend class FRingBufferTest
Definition RingBuffer.h:1008
SizeType RemoveAll(PredicateType Predicate)
Definition RingBuffer.h:690
void Trim()
Definition RingBuffer.h:259
ElementType & First()
Definition RingBuffer.h:466
TRingBufferIterator< const TRingBuffer, const ElementType, typename Allocator::SizeType > TConstIterator
Definition RingBuffer.h:152
SIZE_T GetAllocatedSize(void) const
Definition RingBuffer.h:789
ElementType PopFrontValue()
Definition RingBuffer.h:506
void PopFront(SizeType PopCount=1)
Definition RingBuffer.h:490
const ElementType & Last() const
Definition RingBuffer.h:484
TRingBuffer & operator=(const TRingBuffer &Other)
Definition RingBuffer.h:214
void Pop(SizeType PopCount=1)
Definition RingBuffer.h:515
ElementType & Last()
Definition RingBuffer.h:478
T ElementType
Definition RingBuffer.h:138
TConstIterator end() const
Definition RingBuffer.h:583
TArrayView< T > Compact()
Definition RingBuffer.h:769
std::make_unsigned_t< typename Allocator::SizeType > SizeType
Definition RingBuffer.h:149
TRingBufferIterator< TRingBuffer, ElementType, typename Allocator::SizeType > TIterator
Definition RingBuffer.h:151
void Empty()
Definition RingBuffer.h:184
void Reset()
Definition RingBuffer.h:266
IndexType Num() const
Definition RingBuffer.h:236
ElementType & Add_GetRef(const ElementType &Element)
Definition RingBuffer.h:308
IndexType AddUninitialized()
Definition RingBuffer.h:336
TRingBuffer(SizeType InitialCapacity)
Definition RingBuffer.h:172
void MoveAppendRange(ElementType *OtherData, SizeType OtherNum)
Definition RingBuffer.h:357
void ShiftIndexToBack(IndexType Index)
Definition RingBuffer.h:552
IndexType AddFrontUninitialized()
Definition RingBuffer.h:448
IndexType AddFront(const ElementType &Element)
Definition RingBuffer.h:411
bool operator!=(const TRingBuffer< ElementType, OtherAllocator > &Other) const
Definition RingBuffer.h:760
IndexType Max() const
Definition RingBuffer.h:242
TRingBuffer & operator=(TRingBuffer &&Other)
Definition RingBuffer.h:194
ElementType PopValue()
Definition RingBuffer.h:531
IndexType EmplaceFront(ArgsType &&... Args)
Definition RingBuffer.h:430
TRingBuffer()
Definition RingBuffer.h:164
void ShiftIndexToFront(IndexType Index)
Definition RingBuffer.h:540
bool IsEmpty() const
Definition RingBuffer.h:230
AllocatorT Allocator
Definition RingBuffer.h:140
void PopNoCheck(SizeType PopCount=1)
Definition RingBuffer.h:522
ElementType & Add_GetRef(ElementType &&Element)
Definition RingBuffer.h:291
bool IsValidIndex(IndexType Index) const
Definition RingBuffer.h:589
ElementType & Emplace_GetRef(ArgsType &&... Args)
Definition RingBuffer.h:328
const ElementType & operator[](IndexType Index) const
Definition RingBuffer.h:602
ElementType & AddFront_GetRef(const ElementType &Element)
Definition RingBuffer.h:420
~TRingBuffer()
Definition RingBuffer.h:224
bool operator==(const TRingBuffer< ElementType, OtherAllocator > &Other) const
Definition RingBuffer.h:742
TConstIterator begin() const
Definition RingBuffer.h:571
TRingBuffer(std::initializer_list< ElementType > InitList)
Definition RingBuffer.h:179
TRingBuffer(TRingBuffer &&Other)
Definition RingBuffer.h:188
SizeType Remove(const ElementType &Item)
Definition RingBuffer.h:678
ElementType & GetAtIndexNoCheck(IndexType Index)
Definition RingBuffer.h:609
ElementType & AddUninitialized_GetRef()
Definition RingBuffer.h:348
ElementType & EmplaceFront_GetRef(ArgsType &&... Args)
Definition RingBuffer.h:440
void Reserve(SizeType RequiredCapacity)
Definition RingBuffer.h:248
void RemoveAt(IndexType Index)
Definition RingBuffer.h:651
ElementType & operator[](IndexType Index)
Definition RingBuffer.h:595
const ElementType & GetAtIndexNoCheck(IndexType Index) const
Definition RingBuffer.h:615
IndexType ConvertPointerToIndex(const ElementType *Ptr) const
Definition RingBuffer.h:621
std::conditional_t< Allocator::NeedsElementType, typename Allocator::template ForElementType< ElementType >, typename Allocator::ForAnyElementType > ElementAllocatorType
Definition RingBuffer.h:145
ElementType & AddFrontUninitialized_GetRef()
Definition RingBuffer.h:460
void Empty(SizeType Capacity=0)
Definition RingBuffer.h:274
IndexType Emplace(ArgsType &&... Args)
Definition RingBuffer.h:318
TRingBuffer(const TRingBuffer &Other)
Definition RingBuffer.h:208
std::make_signed_t< typename Allocator::SizeType > IndexType
Definition RingBuffer.h:147
IndexType Add(const ElementType &Element)
Definition RingBuffer.h:299
const ElementType & First() const
Definition RingBuffer.h:472
IndexType Add(ElementType &&Element)
Definition RingBuffer.h:282
ElementType & AddFront_GetRef(ElementType &&Element)
Definition RingBuffer.h:403
IndexType AddFront(ElementType &&Element)
Definition RingBuffer.h:394
U16 Index
Definition radfft.cpp:71
Definition ContainerAllocationPolicies.h:256
Definition NumericLimits.h:41