diff --git a/Redcraft.Utility/Source/Public/Containers/Array.h b/Redcraft.Utility/Source/Public/Containers/Array.h index 27e1f89..77c743c 100644 --- a/Redcraft.Utility/Source/Public/Containers/Array.h +++ b/Redcraft.Utility/Source/Public/Containers/Array.h @@ -4,7 +4,9 @@ #include "Templates/Utility.h" #include "Templates/TypeHash.h" #include "Templates/Container.h" +#include "Containers/Iterator.h" #include "TypeTraits/TypeTraits.h" +#include "Miscellaneous/Compare.h" #include "Memory/MemoryOperator.h" #include "Memory/ObserverPointer.h" #include "Memory/DefaultAllocator.h" @@ -89,14 +91,16 @@ private: }; -template +template class TArrayIterator { public: + using ElementType = T; + # if DO_CHECK FORCEINLINE constexpr TArrayIterator() : Owner(nullptr) { } -# elif +# else FORCEINLINE constexpr TArrayIterator() = default; # endif @@ -104,7 +108,7 @@ public: FORCEINLINE constexpr TArrayIterator(const TArrayIterator>& InValue) requires (CConst) : Owner(InValue.Owner), Pointer(InValue.Pointer) { } -# elif +# else FORCEINLINE constexpr TArrayIterator(const TArrayIterator>& InValue) requires (CConst) : Pointer(InValue.Pointer) { } @@ -115,23 +119,27 @@ public: FORCEINLINE constexpr TArrayIterator& operator=(const TArrayIterator&) = default; FORCEINLINE constexpr TArrayIterator& operator=(TArrayIterator&&) = default; - NODISCARD friend constexpr bool operator==(const TArrayIterator& LHS, const TArrayIterator& RHS) { return LHS.Pointer == RHS.Pointer; } + NODISCARD friend FORCEINLINE constexpr bool operator==(const TArrayIterator& LHS, const TArrayIterator& RHS) { return LHS.Pointer == RHS.Pointer; } - NODISCARD friend constexpr strong_ordering operator<=>(const TArrayIterator & LHS, const TArrayIterator & RHS) { return LHS.Pointer <=> RHS.Pointer; } + NODISCARD friend FORCEINLINE constexpr strong_ordering operator<=>(const TArrayIterator & LHS, const TArrayIterator & RHS) { return LHS.Pointer <=> RHS.Pointer; } NODISCARD FORCEINLINE constexpr ElementType& operator*() const { CheckThis(true); return *Pointer; } NODISCARD FORCEINLINE constexpr ElementType* operator->() const { CheckThis(true); return Pointer; } + NODISCARD FORCEINLINE constexpr ElementType& operator[](ptrdiff Index) const { TArrayIterator Temp = *this + Index; Temp.CheckThis(); return *Temp; } + FORCEINLINE constexpr TArrayIterator& operator++() { ++Pointer; CheckThis(); return *this; } FORCEINLINE constexpr TArrayIterator& operator--() { --Pointer; CheckThis(); return *this; } - + FORCEINLINE constexpr TArrayIterator operator++(int) { TArrayIterator Temp = *this; ++Pointer; CheckThis(); return Temp; } FORCEINLINE constexpr TArrayIterator operator--(int) { TArrayIterator Temp = *this; --Pointer; CheckThis(); return Temp; } FORCEINLINE constexpr TArrayIterator& operator+=(ptrdiff Offset) { Pointer += Offset; CheckThis(); return *this; } FORCEINLINE constexpr TArrayIterator& operator-=(ptrdiff Offset) { Pointer -= Offset; CheckThis(); return *this; } - NODISCARD FORCEINLINE constexpr TArrayIterator operator+(ptrdiff Offset) const { TArrayIterator Temp = *this; Temp += Offset; Temp.CheckThis(); return Temp; } + NODISCARD friend FORCEINLINE constexpr TArrayIterator operator+(TArrayIterator Iter, ptrdiff Offset) { TArrayIterator Temp = Iter; Temp += Offset; Temp.CheckThis(); return Temp; } + NODISCARD friend FORCEINLINE constexpr TArrayIterator operator+(ptrdiff Offset, TArrayIterator Iter) { TArrayIterator Temp = Iter; Temp += Offset; Temp.CheckThis(); return Temp; } + NODISCARD FORCEINLINE constexpr TArrayIterator operator-(ptrdiff Offset) const { TArrayIterator Temp = *this; Temp -= Offset; Temp.CheckThis(); return Temp; } NODISCARD friend FORCEINLINE constexpr ptrdiff operator-(const TArrayIterator& LHS, const TArrayIterator& RHS) @@ -142,7 +150,8 @@ public: return LHS.Pointer - RHS.Pointer; } - NODISCARD FORCEINLINE constexpr ElementType& operator[](ptrdiff Index) const { TArrayIterator Temp = *this + Index; Temp.CheckThis(); return *Temp; } + NODISCARD FORCEINLINE constexpr explicit operator ElementType*() requires (!CConst) { return Pointer; } + NODISCARD FORCEINLINE constexpr explicit operator const ElementType*() const { return Pointer; } private: @@ -156,7 +165,7 @@ private: FORCEINLINE constexpr TArrayIterator(const ArrayType* InContainer, ElementType* InPointer) : Owner(InContainer), Pointer(InPointer) { } -# elif +# else FORCEINLINE constexpr TArrayIterator(const ArrayType* InContainer, ElementType* InPointer) : Pointer(InPointer) { } @@ -189,13 +198,15 @@ public: using Iterator = NAMESPACE_PRIVATE::TArrayIterator; using ConstIterator = NAMESPACE_PRIVATE::TArrayIterator; + static_assert(CContiguousIterator< Iterator>); + static_assert(CContiguousIterator); + /** Default constructor. Constructs an empty container with a default-constructed allocator. */ FORCEINLINE constexpr TArray() : TArray(0) { } /** Constructs the container with 'Count' default instances of T. */ - constexpr explicit TArray(size_t Count) - requires (CDefaultConstructible) - { + constexpr explicit TArray(size_t Count) requires (CDefaultConstructible) + { Storage.GetNum() = Count; Storage.GetMax() = Storage.GetAllocator().CalculateSlackReserve(Num()); Storage.GetPointer() = Storage.GetAllocator().Allocate(Max()); @@ -204,8 +215,7 @@ public: } /** Constructs the container with 'Count' copies of elements with 'InValue'. */ - constexpr TArray(size_t Count, const ElementType& InValue) - requires (CCopyConstructible) + constexpr TArray(size_t Count, const ElementType& InValue) requires (CCopyConstructible) { Storage.GetNum() = Count; Storage.GetMax() = Storage.GetAllocator().CalculateSlackReserve(Num()); @@ -217,9 +227,41 @@ public: } } + /** Constructs the container with the contents of the range ['First', 'Last'). */ + template S> requires (CConstructibleFrom> && CMovable) + constexpr TArray(I First, S Last) + { + if constexpr (CForwardIterator) + { + if constexpr (CRandomAccessIterator) checkf(First <= Last, TEXT("Illegal range iterator. Please check First <= Last.")); + + const size_t Count = Iteration::Distance(First, Last); + + Storage.GetNum() = Count; + Storage.GetMax() = Storage.GetAllocator().CalculateSlackReserve(Num()); + Storage.GetPointer() = Storage.GetAllocator().Allocate(Max()); + + for (size_t Index = 0; Index != Count; ++Index) + { + new (Storage.GetPointer() + Index) ElementType(*First++); + } + } + else + { + Storage.GetNum() = 0; + Storage.GetMax() = Storage.GetAllocator().CalculateSlackReserve(Num()); + Storage.GetPointer() = Storage.GetAllocator().Allocate(Max()); + + while (First != Last) + { + PushBack(*First); + ++First; + } + } + } + /** Copy constructor. Constructs the container with the copy of the contents of 'InValue'. */ - constexpr TArray(const TArray& InValue) - requires (CCopyConstructible) + constexpr TArray(const TArray& InValue) requires (CCopyConstructible) { Storage.GetNum() = InValue.Num(); Storage.GetMax() = Storage.GetAllocator().CalculateSlackReserve(Num()); @@ -229,8 +271,7 @@ public: } /** Move constructor. After the move, 'InValue' is guaranteed to be empty. */ - constexpr TArray(TArray&& InValue) - requires (CMoveConstructible) + constexpr TArray(TArray&& InValue) requires (CMoveConstructible) { Storage.GetNum() = InValue.Num(); @@ -253,15 +294,7 @@ public: } /** Constructs the container with the contents of the initializer list. */ - constexpr TArray(initializer_list IL) - requires (CCopyConstructible) - { - Storage.GetNum() = GetNum(IL); - Storage.GetMax() = Storage.GetAllocator().CalculateSlackReserve(GetNum(IL)); - Storage.GetPointer() = Storage.GetAllocator().Allocate(Max()); - - Memory::CopyConstruct(Storage.GetPointer(), NAMESPACE_REDCRAFT::GetData(IL), Num()); - } + FORCEINLINE constexpr TArray(initializer_list IL) requires (CCopyConstructible) : TArray(Iteration::Begin(IL), Iteration::End(IL)) { } /** Destructs the array. The destructors of the elements are called and the used storage is deallocated. */ constexpr ~TArray() @@ -271,8 +304,7 @@ public: } /** Copy assignment operator. Replaces the contents with a copy of the contents of 'InValue'. */ - constexpr TArray& operator=(const TArray& InValue) - requires (CCopyConstructible && CCopyAssignable) + constexpr TArray& operator=(const TArray& InValue) requires (CCopyable) { if (&InValue == this) UNLIKELY return *this; @@ -313,8 +345,7 @@ public: } /** Move assignment operator. After the move, 'InValue' is guaranteed to be empty. */ - constexpr TArray& operator=(TArray&& InValue) - requires (CMoveConstructible&& CMoveAssignable) + constexpr TArray& operator=(TArray&& InValue) requires (CMovable) { if (&InValue == this) UNLIKELY return *this; @@ -373,8 +404,7 @@ public: } /** Replaces the contents with those identified by initializer list. */ - constexpr TArray& operator=(initializer_list IL) - requires (CCopyConstructible && CCopyAssignable) + constexpr TArray& operator=(initializer_list IL) requires (CCopyable) { size_t NumToAllocate = GetNum(IL); @@ -460,8 +490,7 @@ public: } /** Inserts 'InValue' before 'Iter' in the container. */ - constexpr Iterator Insert(ConstIterator Iter, const ElementType& InValue) - requires (CCopyConstructible && CCopyAssignable && CMoveConstructible && CMoveAssignable) + constexpr Iterator Insert(ConstIterator Iter, const ElementType& InValue) requires (CCopyable) { checkf(IsValidIterator(Iter), TEXT("Read access violation. Please check IsValidIterator().")); @@ -509,8 +538,7 @@ public: } /** Inserts 'InValue' before 'Iter' in the container. */ - constexpr Iterator Insert(ConstIterator Iter, ElementType&& InValue) - requires (CMoveConstructible && CMoveAssignable) + constexpr Iterator Insert(ConstIterator Iter, ElementType&& InValue) requires (CMovable) { checkf(IsValidIterator(Iter), TEXT("Read access violation. Please check IsValidIterator().")); @@ -558,8 +586,7 @@ public: } /** Inserts 'Count' copies of the 'InValue' before 'Iter' in the container. */ - constexpr Iterator Insert(ConstIterator Iter, size_t Count, const ElementType& InValue) - requires (CCopyConstructible && CCopyAssignable && CMoveConstructible && CMoveAssignable) + constexpr Iterator Insert(ConstIterator Iter, size_t Count, const ElementType& InValue) requires (CCopyable) { checkf(IsValidIterator(Iter), TEXT("Read access violation. Please check IsValidIterator().")); @@ -630,107 +657,126 @@ public: const size_t IndexC = InsertIndex + Count; const size_t IndexB = Num() > IndexA ? (Num() < IndexC ? Num() : IndexC) : IndexA; const size_t IndexD = Num() > IndexC ? Num() : IndexC; + const size_t IndexO = Num() + Count; - size_t TargetIndex = Num() + Count - 1; - - for (; TargetIndex != IndexD - 1; --TargetIndex) + for (size_t TargetIndex = IndexO - 1; TargetIndex != IndexD - 1; --TargetIndex) { new (Storage.GetPointer() + TargetIndex) ElementType(MoveTemp(Storage.GetPointer()[TargetIndex - Count])); } - for (; TargetIndex != IndexC - 1; --TargetIndex) + for (size_t TargetIndex = IndexD - 1; TargetIndex != IndexC - 1; --TargetIndex) { Storage.GetPointer()[TargetIndex] = MoveTemp(Storage.GetPointer()[TargetIndex - Count]); } - for (; TargetIndex != IndexB - 1; --TargetIndex) - { - new (Storage.GetPointer() + TargetIndex) ElementType(InValue); - } - - for (; TargetIndex != IndexA - 1; --TargetIndex) + for (size_t TargetIndex = IndexA; TargetIndex != IndexB; ++TargetIndex) { Storage.GetPointer()[TargetIndex] = InValue; } + for (size_t TargetIndex = IndexB; TargetIndex != IndexC; ++TargetIndex) + { + new (Storage.GetPointer() + TargetIndex) ElementType(InValue); + } + Storage.GetNum() = Num() + Count; return Iterator(this, Storage.GetPointer() + InsertIndex); } - - /** Inserts elements from initializer list before 'Iter' in the container. */ - constexpr Iterator Insert(ConstIterator Iter, initializer_list IL) - requires (CCopyConstructible && CCopyAssignable && CMoveConstructible && CMoveAssignable) + + /** Inserts elements from range ['First', 'Last') before 'Iter'. */ + template S> requires (CConstructibleFrom> + && CAssignableFrom> && CMovable) + constexpr Iterator Insert(ConstIterator Iter, I First, S Last) { checkf(IsValidIterator(Iter), TEXT("Read access violation. Please check IsValidIterator().")); - const size_t InsertIndex = Iter - Begin(); - const size_t Count = GetNum(IL); - - if (Count == 0) return Iterator(this, Storage.GetPointer() + InsertIndex); - - const size_t NumToAllocate = Num() + Count > Max() ? Storage.GetAllocator().CalculateSlackGrow(Num() + Count, Max()) : Max(); - - check(NumToAllocate >= Num() + Count); - - if (NumToAllocate != Max()) + if constexpr (CForwardIterator) { - ElementType* OldAllocation = Storage.GetPointer(); - const size_t NumToDestruct = Num(); + if constexpr (CRandomAccessIterator) checkf(First <= Last, TEXT("Illegal range iterator. Please check First <= Last.")); - Storage.GetNum() = Num() + Count; - Storage.GetMax() = NumToAllocate; - Storage.GetPointer() = Storage.GetAllocator().Allocate(Max()); + const size_t InsertIndex = Iter - Begin(); + const size_t Count = Iteration::Distance(First, Last); - Memory::MoveConstruct(Storage.GetPointer(), OldAllocation, InsertIndex); + if (Count == 0) return Iterator(this, Storage.GetPointer() + InsertIndex); - for (size_t Index = InsertIndex; Index != InsertIndex + Count; ++Index) + const size_t NumToAllocate = Num() + Count > Max() ? Storage.GetAllocator().CalculateSlackGrow(Num() + Count, Max()) : Max(); + + check(NumToAllocate >= Num() + Count); + + if (NumToAllocate != Max()) { - new (Storage.GetPointer() + Index) ElementType(NAMESPACE_REDCRAFT::GetData(IL)[Index - InsertIndex]); + ElementType* OldAllocation = Storage.GetPointer(); + const size_t NumToDestruct = Num(); + + Storage.GetNum() = Num() + Count; + Storage.GetMax() = NumToAllocate; + Storage.GetPointer() = Storage.GetAllocator().Allocate(Max()); + + Memory::MoveConstruct(Storage.GetPointer(), OldAllocation, InsertIndex); + + for (size_t Index = InsertIndex; Index != InsertIndex + Count; ++Index) + { + new (Storage.GetPointer() + Index) ElementType(*First++); + } + + Memory::MoveConstruct(Storage.GetPointer() + InsertIndex + Count, OldAllocation + InsertIndex, NumToDestruct - InsertIndex); + + Memory::Destruct(OldAllocation, NumToDestruct); + Storage.GetAllocator().Deallocate(OldAllocation); + + return Iterator(this, Storage.GetPointer() + InsertIndex); } - Memory::MoveConstruct(Storage.GetPointer() + InsertIndex + Count, OldAllocation + InsertIndex, NumToDestruct - InsertIndex); + const size_t IndexA = InsertIndex; + const size_t IndexC = InsertIndex + Count; + const size_t IndexB = Num() > IndexA ? (Num() < IndexC ? Num() : IndexC) : IndexA; + const size_t IndexD = Num() > IndexC ? Num() : IndexC; + const size_t IndexO = Num() + Count; - Memory::Destruct(OldAllocation, NumToDestruct); - Storage.GetAllocator().Deallocate(OldAllocation); + size_t TargetIndex = Num() + Count - 1; + + for (size_t TargetIndex = IndexO - 1; TargetIndex != IndexD - 1; --TargetIndex) + { + new (Storage.GetPointer() + TargetIndex) ElementType(MoveTemp(Storage.GetPointer()[TargetIndex - Count])); + } + + for (size_t TargetIndex = IndexD - 1; TargetIndex != IndexC - 1; --TargetIndex) + { + Storage.GetPointer()[TargetIndex] = MoveTemp(Storage.GetPointer()[TargetIndex - Count]); + } + + for (size_t TargetIndex = IndexA; TargetIndex != IndexB; ++TargetIndex) + { + Storage.GetPointer()[TargetIndex] = *First++; + } + + for (size_t TargetIndex = IndexB; TargetIndex != IndexC; ++TargetIndex) + { + new (Storage.GetPointer() + TargetIndex) ElementType(*First++); + } + + check(First == Last); + + Storage.GetNum() = Num() + Count; return Iterator(this, Storage.GetPointer() + InsertIndex); } - - const size_t IndexA = InsertIndex; - const size_t IndexC = InsertIndex + Count; - const size_t IndexB = Num() > IndexA ? (Num() < IndexC ? Num() : IndexC) : IndexA; - const size_t IndexD = Num() > IndexC ? Num() : IndexC; - - size_t TargetIndex = Num() + Count - 1; - - for (; TargetIndex != IndexD - 1; --TargetIndex) + else { - new (Storage.GetPointer() + TargetIndex) ElementType(MoveTemp(Storage.GetPointer()[TargetIndex - Count])); + TArray Temp(MoveTemp(First), MoveTemp(Last)); + return Insert(Iter, Temp.Begin(), Temp.End()); // FIXME: Fix to MoveIterator. } + } - for (; TargetIndex != IndexC - 1; --TargetIndex) - { - Storage.GetPointer()[TargetIndex] = MoveTemp(Storage.GetPointer()[TargetIndex - Count]); - } - - for (; TargetIndex != IndexB - 1; --TargetIndex) - { - new (Storage.GetPointer() + TargetIndex) ElementType(NAMESPACE_REDCRAFT::GetData(IL)[TargetIndex - InsertIndex]); - } - - for (; TargetIndex != IndexA - 1; --TargetIndex) - { - Storage.GetPointer()[TargetIndex] = NAMESPACE_REDCRAFT::GetData(IL)[TargetIndex - InsertIndex]; - } - - Storage.GetNum() = Num() + Count; - - return Iterator(this, Storage.GetPointer() + InsertIndex); + /** Inserts elements from initializer list before 'Iter' in the container. */ + FORCEINLINE constexpr Iterator Insert(ConstIterator Iter, initializer_list IL) requires (CCopyable) + { + return Insert(Iter, Iteration::Begin(IL), Iteration::End(IL)); } /** Inserts a new element into the container directly before 'Iter'. */ - template requires (CConstructibleFrom && CMoveConstructible && CMoveAssignable) + template requires (CConstructibleFrom && CMovable) constexpr Iterator Emplace(ConstIterator Iter, Ts&&... Args) { checkf(IsValidIterator(Iter), TEXT("Read access violation. Please check IsValidIterator().")); @@ -779,22 +825,20 @@ public: } /** Removes the element at 'Iter' in the container. Without changing the order of elements. */ - FORCEINLINE constexpr Iterator StableErase(ConstIterator Iter, bool bAllowShrinking = true) - requires (CMoveConstructible && CMoveAssignable) + FORCEINLINE constexpr Iterator StableErase(ConstIterator Iter, bool bAllowShrinking = true) requires (CMovable) { checkf(IsValidIterator(Iter) && Iter != End(), TEXT("Read access violation. Please check IsValidIterator().")); return StableErase(Iter, Iter + 1, bAllowShrinking); } - /** Removes the elements in the range ['FirstIter', 'LastIter') in the container. Without changing the order of elements. */ - constexpr Iterator StableErase(ConstIterator FirstIter, ConstIterator LastIter, bool bAllowShrinking = true) - requires (CMoveConstructible && CMoveAssignable) + /** Removes the elements in the range ['First', 'Last') in the container. Without changing the order of elements. */ + constexpr Iterator StableErase(ConstIterator First, ConstIterator Last, bool bAllowShrinking = true) requires (CMovable) { - checkf(IsValidIterator(FirstIter) && IsValidIterator(LastIter) && FirstIter <= LastIter, TEXT("Read access violation. Please check IsValidIterator().")); + checkf(IsValidIterator(First) && IsValidIterator(Last) && First <= Last, TEXT("Read access violation. Please check IsValidIterator().")); - const size_t EraseIndex = FirstIter - Begin(); - const size_t EraseCount = LastIter - FirstIter; + const size_t EraseIndex = First - Begin(); + const size_t EraseCount = Last - First; if (EraseCount == 0) return Iterator(this, Storage.GetPointer() + EraseIndex); @@ -831,22 +875,20 @@ public: } /** Removes the element at 'Iter' in the container. But it may change the order of elements. */ - FORCEINLINE constexpr Iterator Erase(ConstIterator Iter, bool bAllowShrinking = true) - requires (CMoveConstructible && CMoveAssignable) + FORCEINLINE constexpr Iterator Erase(ConstIterator Iter, bool bAllowShrinking = true) requires (CMovable) { checkf(IsValidIterator(Iter) && Iter != End(), TEXT("Read access violation. Please check IsValidIterator().")); return Erase(Iter, Iter + 1, bAllowShrinking); } - /** Removes the elements in the range ['FirstIter', 'LastIter') in the container. But it may change the order of elements. */ - constexpr Iterator Erase(ConstIterator FirstIter, ConstIterator LastIter, bool bAllowShrinking = true) - requires (CMoveConstructible && CMoveAssignable) + /** Removes the elements in the range ['First', 'Last') in the container. But it may change the order of elements. */ + constexpr Iterator Erase(ConstIterator First, ConstIterator Last, bool bAllowShrinking = true) requires (CMovable) { - checkf(IsValidIterator(FirstIter) && IsValidIterator(LastIter) && FirstIter <= LastIter, TEXT("Read access violation. Please check IsValidIterator().")); + checkf(IsValidIterator(First) && IsValidIterator(Last) && First <= Last, TEXT("Read access violation. Please check IsValidIterator().")); - const size_t EraseIndex = FirstIter - Begin(); - const size_t EraseCount = LastIter - FirstIter; + const size_t EraseIndex = First - Begin(); + const size_t EraseCount = Last - First; if (EraseCount == 0) return Iterator(this, Storage.GetPointer() + EraseIndex); @@ -885,21 +927,19 @@ public: } /** Appends the given element value to the end of the container. */ - FORCEINLINE constexpr void PushBack(const ElementType& InValue) - requires (CCopyConstructible && CCopyAssignable && CMoveConstructible && CMoveAssignable) + FORCEINLINE constexpr void PushBack(const ElementType& InValue) requires (CCopyable) { EmplaceBack(InValue); } /** Appends the given element value to the end of the container. */ - FORCEINLINE constexpr void PushBack(ElementType&& InValue) - requires (CMoveConstructible && CMoveAssignable) + FORCEINLINE constexpr void PushBack(ElementType&& InValue) requires (CMovable) { EmplaceBack(MoveTemp(InValue)); } /** Appends a new element to the end of the container. */ - template requires (CConstructibleFrom && CMoveConstructible && CMoveAssignable) + template requires (CConstructibleFrom && CMovable) constexpr ElementType& EmplaceBack(Ts&&... Args) { const size_t NumToAllocate = Num() + 1 > Max() ? Storage.GetAllocator().CalculateSlackGrow(Num() + 1, Max()) : Max(); @@ -932,15 +972,13 @@ public: } /** Removes the last element of the container. The array cannot be empty. */ - FORCEINLINE constexpr void PopBack(bool bAllowShrinking = true) - requires (CMoveConstructible && CMoveAssignable) + FORCEINLINE constexpr void PopBack(bool bAllowShrinking = true) requires (CMovable) { Erase(End() - 1, bAllowShrinking); } /** Resizes the container to contain 'Count' elements. Additional default elements are appended. */ - constexpr void SetNum(size_t Count, bool bAllowShrinking = true) - requires (CDefaultConstructible && CMoveConstructible && CMoveAssignable) + constexpr void SetNum(size_t Count, bool bAllowShrinking = true) requires (CDefaultConstructible && CMovable) { size_t NumToAllocate = Count; @@ -986,8 +1024,7 @@ public: } /** Resizes the container to contain 'Count' elements. Additional copies of 'InValue' are appended. */ - constexpr void SetNum(size_t Count, const ElementType& InValue, bool bAllowShrinking = true) - requires (CCopyConstructible && CMoveConstructible && CMoveAssignable) + constexpr void SetNum(size_t Count, const ElementType& InValue, bool bAllowShrinking = true) requires (CCopyConstructible && CMovable) { size_t NumToAllocate = Count; @@ -1040,8 +1077,7 @@ public: } /** Increase the max capacity of the array to a value that's greater or equal to 'Count'. */ - constexpr void Reserve(size_t Count) - requires (CMoveConstructible && CMoveAssignable) + constexpr void Reserve(size_t Count) requires (CMovable) { if (Count <= Max()) return; @@ -1112,11 +1148,11 @@ public: NODISCARD FORCEINLINE constexpr const ElementType& Back() const { return *(End() - 1); } /** Erases all elements from the container. After this call, Num() returns zero. */ - constexpr void Reset() + constexpr void Reset(bool bAllowShrinking = true) { const size_t NumToAllocate = Storage.GetAllocator().CalculateSlackReserve(0); - if (NumToAllocate != Max()) + if (bAllowShrinking && NumToAllocate != Max()) { Memory::Destruct(Storage.GetPointer(), Num()); Storage.GetAllocator().Deallocate(Storage.GetPointer()); @@ -1146,8 +1182,7 @@ public: } /** Overloads the Swap algorithm for TArray. */ - friend constexpr void Swap(TArray& A, TArray& B) - requires (CSwappable && CMoveConstructible && CMoveAssignable) + friend constexpr void Swap(TArray& A, TArray& B) requires (CMovable) { const bool bIsTransferable = A.Storage.GetAllocator().IsTransferable(A.Storage.GetPointer()) && diff --git a/Redcraft.Utility/Source/Public/Containers/Containers.h b/Redcraft.Utility/Source/Public/Containers/Containers.h index 04c86f8..9b7b3ff 100644 --- a/Redcraft.Utility/Source/Public/Containers/Containers.h +++ b/Redcraft.Utility/Source/Public/Containers/Containers.h @@ -1,4 +1,5 @@ #pragma once #include "CoreTypes.h" +#include "Containers/Iterator.h" #include "Containers/Array.h" diff --git a/Redcraft.Utility/Source/Public/Containers/Iterator.h b/Redcraft.Utility/Source/Public/Containers/Iterator.h new file mode 100644 index 0000000..ff96b5a --- /dev/null +++ b/Redcraft.Utility/Source/Public/Containers/Iterator.h @@ -0,0 +1,229 @@ +#pragma once + +#include "CoreTypes.h" +#include "Templates/Utility.h" +#include "TypeTraits/TypeTraits.h" +#include "Miscellaneous/Compare.h" +#include "Miscellaneous/AssertionMacros.h" + +NAMESPACE_REDCRAFT_BEGIN +NAMESPACE_MODULE_BEGIN(Redcraft) +NAMESPACE_MODULE_BEGIN(Utility) + +NAMESPACE_PRIVATE_BEGIN + +template using WithReference = T&; + +template +struct TIteratorElementType +{ + using Type = typename I::ElementType; +}; + +template +struct TIteratorElementType +{ + using Type = T; +}; + +NAMESPACE_PRIVATE_END + +template +concept CReferenceable = requires { typename NAMESPACE_PRIVATE::WithReference; }; + +template +concept CDereferenceable = requires(T& A) { { *A } -> CReferenceable; }; + +template +using TIteratorElementType = typename NAMESPACE_PRIVATE::TIteratorElementType::Type; + +template +using TIteratorReferenceType = decltype(*DeclVal()); + +template requires (requires(T& Iter) { { MoveTemp(*Iter) } -> CReferenceable; }) +using TIteratorRValueReferenceType = decltype(MoveTemp(*DeclVal())); + +template +concept CIndirectlyReadable = + requires(const I Iter) + { + typename TIteratorElementType; + typename TIteratorReferenceType; + typename TIteratorRValueReferenceType; + { *Iter } -> CSameAs>; + { MoveTemp(*Iter) } -> CSameAs>; + } + && CCommonReference&&, TIteratorElementType&> + && CCommonReference&&, TIteratorRValueReferenceType&&> + && CCommonReference&&, const TIteratorElementType&>; + +template +concept CIndirectlyWritable = + requires(I && Iter, T && A) + { + *Iter = Forward(A); + *Forward(Iter) = Forward(A); + const_cast&&>(*Iter) = Forward(A); + const_cast&&>(*Forward(Iter)) = Forward(A); + }; + +template +concept CWeaklyIncrementable = CDefaultConstructible && CMovable + && requires(I Iter) { { ++Iter } -> CSameAs; Iter++; }; + +template +concept CIncrementable = CRegular && CWeaklyIncrementable + && requires(I Iter) { { Iter++ } -> CSameAs; }; + +template +concept CInputOrOutputIterator = CWeaklyIncrementable + && requires(I Iter) { { *Iter } -> CReferenceable; }; + +template +concept CSentinelFor = CSemiregular && CInputOrOutputIterator && CWeaklyEqualityComparable; + +template +inline constexpr bool bDisableSizedSentinelFor = false; + +template +concept CSizedSentinelFor = CSentinelFor && !bDisableSizedSentinelFor, TRemoveCV> + && requires(const I& Iter, const S& Sentinel) { Sentinel - Iter; Iter - Sentinel; }; + +template +concept CInputIterator = CInputOrOutputIterator && CIndirectlyReadable; + +template +concept COutputIterator = CInputOrOutputIterator && CIndirectlyWritable + && requires(I Iter, T&& A) { *Iter++ = Forward(A); }; + +template +concept CForwardIterator = CInputIterator && CIncrementable && CSentinelFor; + +template +concept CBidirectionalIterator = CForwardIterator + && requires(I Iter) { + { --Iter } -> CSameAs; + { Iter-- } -> CSameAs; + }; + +template +concept CRandomAccessIterator = CBidirectionalIterator && CTotallyOrdered && CSizedSentinelFor + && requires(I Iter, const I Jter, const ptrdiff N) { + { Iter += N } -> CSameAs; + { Jter + N } -> CSameAs; + { N + Jter } -> CSameAs; + { Iter -= N } -> CSameAs; + { Jter - N } -> CSameAs; + { Jter[N] } -> CSameAs>; + }; + +template +concept CContiguousIterator = CRandomAccessIterator && CLValueReference> + && CSameAs, TRemoveReference>> + && requires(I& Iter) + { + static_cast>>(Iter); + { AddressOf(*Iter) } -> CSameAs>>; + }; + +static_assert(CContiguousIterator); + +NAMESPACE_BEGIN(Iteration) + +/** Increments given iterator 'Iter' by 'N' elements. */ +template +FORCEINLINE constexpr void Advance(I& Iter, ptrdiff N) +{ + if constexpr (CRandomAccessIterator) + { + Iter += N; + } + else if constexpr (CBidirectionalIterator) + { + for (; N > 0; --N) ++Iter; + for (; N < 0; ++N) --Iter; + } + else + { + checkf(N >= 0, TEXT("The iterator must satisfy the CBidirectionalIterator in order to be decremented.")); + for (; N > 0; --N) ++Iter; + } +} + +/** @return The number of hops from 'First' to 'Last'. */ +template S> +FORCEINLINE constexpr ptrdiff Distance(I First, S Last) +{ + if constexpr (CSizedSentinelFor) + { + return Last - First; + } + else + { + ptrdiff Result = 0; + for (; First != Last; ++First) ++Result; + return Result; + } +} + +/** @return The 'N'-th successor of iterator 'Iter'. */ +template +FORCEINLINE constexpr I Next(I Iter, TMakeUnsigned N = 1) +{ + Advance(Iter, N); + return Iter; +} + +/** @return The 'N'-th predecessor of iterator 'Iter'. */ +template +FORCEINLINE constexpr I Prev(I Iter, TMakeUnsigned N = 1) +{ + Advance(Iter, -N); + return Iter; +} + +/** @return The iterator to the beginning of a container. */ +template requires (requires(T&& Container) { { Container.Begin() } -> CForwardIterator; }) +FORCEINLINE constexpr decltype(auto) Begin(T&& Container) +{ + return Container.Begin(); +} + +/** Overloads the Begin algorithm for arrays. */ +template FORCEINLINE constexpr T* Begin( T(& Container)[N]) { return Container; } +template FORCEINLINE constexpr T* Begin( T(&& Container)[N]) { return Container; } +template FORCEINLINE constexpr const T* Begin(const T(& Container)[N]) { return Container; } +template FORCEINLINE constexpr const T* Begin(const T(&& Container)[N]) { return Container; } + +/** Overloads the Begin algorithm for T::begin(). */ +template requires (requires(T&& Container) { { Container.begin() } -> CForwardIterator; }) +FORCEINLINE constexpr decltype(auto) Begin(T&& Container) +{ + return Container.begin(); +} + +/** @return The iterator to the end of a container. */ +template requires (requires(T&& Container) { { Container.End() } -> CForwardIterator; }) +FORCEINLINE constexpr decltype(auto) End(T&& Container) +{ + return Container.End(); +} + +/** Overloads the End algorithm for arrays. */ +template FORCEINLINE constexpr T* End( T(& Container)[N]) { return Container + N; } +template FORCEINLINE constexpr T* End( T(&& Container)[N]) { return Container + N; } +template FORCEINLINE constexpr const T* End(const T(& Container)[N]) { return Container + N; } +template FORCEINLINE constexpr const T* End(const T(&& Container)[N]) { return Container + N; } + +/** Overloads the End algorithm for T::end(). */ +template requires (requires(T&& Container) { { Container.end() } -> CForwardIterator; }) +FORCEINLINE constexpr decltype(auto) End(T&& Container) +{ + return Container.end(); +} + +NAMESPACE_END(Iteration) + +NAMESPACE_MODULE_END(Utility) +NAMESPACE_MODULE_END(Redcraft) +NAMESPACE_REDCRAFT_END