feat(containers): add iterator concepts and operations support

This commit is contained in:
_Redstone_c_ 2023-02-12 23:46:30 +08:00
parent 3efabc342f
commit 4ab63da977
3 changed files with 401 additions and 136 deletions

View File

@ -4,7 +4,9 @@
#include "Templates/Utility.h" #include "Templates/Utility.h"
#include "Templates/TypeHash.h" #include "Templates/TypeHash.h"
#include "Templates/Container.h" #include "Templates/Container.h"
#include "Containers/Iterator.h"
#include "TypeTraits/TypeTraits.h" #include "TypeTraits/TypeTraits.h"
#include "Miscellaneous/Compare.h"
#include "Memory/MemoryOperator.h" #include "Memory/MemoryOperator.h"
#include "Memory/ObserverPointer.h" #include "Memory/ObserverPointer.h"
#include "Memory/DefaultAllocator.h" #include "Memory/DefaultAllocator.h"
@ -89,14 +91,16 @@ private:
}; };
template <typename ArrayType, typename ElementType> template <typename ArrayType, typename T>
class TArrayIterator class TArrayIterator
{ {
public: public:
using ElementType = T;
# if DO_CHECK # if DO_CHECK
FORCEINLINE constexpr TArrayIterator() : Owner(nullptr) { } FORCEINLINE constexpr TArrayIterator() : Owner(nullptr) { }
# elif # else
FORCEINLINE constexpr TArrayIterator() = default; FORCEINLINE constexpr TArrayIterator() = default;
# endif # endif
@ -104,7 +108,7 @@ public:
FORCEINLINE constexpr TArrayIterator(const TArrayIterator<ArrayType, TRemoveConst<ElementType>>& InValue) requires (CConst<ElementType>) FORCEINLINE constexpr TArrayIterator(const TArrayIterator<ArrayType, TRemoveConst<ElementType>>& InValue) requires (CConst<ElementType>)
: Owner(InValue.Owner), Pointer(InValue.Pointer) : Owner(InValue.Owner), Pointer(InValue.Pointer)
{ } { }
# elif # else
FORCEINLINE constexpr TArrayIterator(const TArrayIterator<ArrayType, TRemoveConst<ElementType>>& InValue) requires (CConst<ElementType>) FORCEINLINE constexpr TArrayIterator(const TArrayIterator<ArrayType, TRemoveConst<ElementType>>& InValue) requires (CConst<ElementType>)
: Pointer(InValue.Pointer) : Pointer(InValue.Pointer)
{ } { }
@ -115,23 +119,27 @@ public:
FORCEINLINE constexpr TArrayIterator& operator=(const TArrayIterator&) = default; FORCEINLINE constexpr TArrayIterator& operator=(const TArrayIterator&) = default;
FORCEINLINE constexpr TArrayIterator& operator=(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->() 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--() { --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--(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; }
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 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) NODISCARD friend FORCEINLINE constexpr ptrdiff operator-(const TArrayIterator& LHS, const TArrayIterator& RHS)
@ -142,7 +150,8 @@ public:
return LHS.Pointer - RHS.Pointer; 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<ElementType>) { return Pointer; }
NODISCARD FORCEINLINE constexpr explicit operator const ElementType*() const { return Pointer; }
private: private:
@ -156,7 +165,7 @@ private:
FORCEINLINE constexpr TArrayIterator(const ArrayType* InContainer, ElementType* InPointer) FORCEINLINE constexpr TArrayIterator(const ArrayType* InContainer, ElementType* InPointer)
: Owner(InContainer), Pointer(InPointer) : Owner(InContainer), Pointer(InPointer)
{ } { }
# elif # else
FORCEINLINE constexpr TArrayIterator(const ArrayType* InContainer, ElementType* InPointer) FORCEINLINE constexpr TArrayIterator(const ArrayType* InContainer, ElementType* InPointer)
: Pointer(InPointer) : Pointer(InPointer)
{ } { }
@ -189,13 +198,15 @@ public:
using Iterator = NAMESPACE_PRIVATE::TArrayIterator<TArray, ElementType>; using Iterator = NAMESPACE_PRIVATE::TArrayIterator<TArray, ElementType>;
using ConstIterator = NAMESPACE_PRIVATE::TArrayIterator<TArray, const ElementType>; using ConstIterator = NAMESPACE_PRIVATE::TArrayIterator<TArray, const ElementType>;
static_assert(CContiguousIterator< Iterator>);
static_assert(CContiguousIterator<ConstIterator>);
/** Default constructor. Constructs an empty container with a default-constructed allocator. */ /** Default constructor. Constructs an empty container with a default-constructed allocator. */
FORCEINLINE constexpr TArray() : TArray(0) { } FORCEINLINE constexpr TArray() : TArray(0) { }
/** Constructs the container with 'Count' default instances of T. */ /** Constructs the container with 'Count' default instances of T. */
constexpr explicit TArray(size_t Count) constexpr explicit TArray(size_t Count) requires (CDefaultConstructible<ElementType>)
requires (CDefaultConstructible<ElementType>) {
{
Storage.GetNum() = Count; Storage.GetNum() = Count;
Storage.GetMax() = Storage.GetAllocator().CalculateSlackReserve(Num()); Storage.GetMax() = Storage.GetAllocator().CalculateSlackReserve(Num());
Storage.GetPointer() = Storage.GetAllocator().Allocate(Max()); Storage.GetPointer() = Storage.GetAllocator().Allocate(Max());
@ -204,8 +215,7 @@ public:
} }
/** Constructs the container with 'Count' copies of elements with 'InValue'. */ /** Constructs the container with 'Count' copies of elements with 'InValue'. */
constexpr TArray(size_t Count, const ElementType& InValue) constexpr TArray(size_t Count, const ElementType& InValue) requires (CCopyConstructible<ElementType>)
requires (CCopyConstructible<ElementType>)
{ {
Storage.GetNum() = Count; Storage.GetNum() = Count;
Storage.GetMax() = Storage.GetAllocator().CalculateSlackReserve(Num()); Storage.GetMax() = Storage.GetAllocator().CalculateSlackReserve(Num());
@ -217,9 +227,41 @@ public:
} }
} }
/** Constructs the container with the contents of the range ['First', 'Last'). */
template <CInputIterator I, CSentinelFor<I> S> requires (CConstructibleFrom<ElementType, TIteratorReferenceType<I>> && CMovable<ElementType>)
constexpr TArray(I First, S Last)
{
if constexpr (CForwardIterator<I>)
{
if constexpr (CRandomAccessIterator<I>) 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'. */ /** Copy constructor. Constructs the container with the copy of the contents of 'InValue'. */
constexpr TArray(const TArray& InValue) constexpr TArray(const TArray& InValue) requires (CCopyConstructible<ElementType>)
requires (CCopyConstructible<ElementType>)
{ {
Storage.GetNum() = InValue.Num(); Storage.GetNum() = InValue.Num();
Storage.GetMax() = Storage.GetAllocator().CalculateSlackReserve(Num()); Storage.GetMax() = Storage.GetAllocator().CalculateSlackReserve(Num());
@ -229,8 +271,7 @@ public:
} }
/** Move constructor. After the move, 'InValue' is guaranteed to be empty. */ /** Move constructor. After the move, 'InValue' is guaranteed to be empty. */
constexpr TArray(TArray&& InValue) constexpr TArray(TArray&& InValue) requires (CMoveConstructible<ElementType>)
requires (CMoveConstructible<ElementType>)
{ {
Storage.GetNum() = InValue.Num(); Storage.GetNum() = InValue.Num();
@ -253,15 +294,7 @@ public:
} }
/** Constructs the container with the contents of the initializer list. */ /** Constructs the container with the contents of the initializer list. */
constexpr TArray(initializer_list<ElementType> IL) FORCEINLINE constexpr TArray(initializer_list<ElementType> IL) requires (CCopyConstructible<ElementType>) : TArray(Iteration::Begin(IL), Iteration::End(IL)) { }
requires (CCopyConstructible<ElementType>)
{
Storage.GetNum() = GetNum(IL);
Storage.GetMax() = Storage.GetAllocator().CalculateSlackReserve(GetNum(IL));
Storage.GetPointer() = Storage.GetAllocator().Allocate(Max());
Memory::CopyConstruct<ElementType>(Storage.GetPointer(), NAMESPACE_REDCRAFT::GetData(IL), Num());
}
/** Destructs the array. The destructors of the elements are called and the used storage is deallocated. */ /** Destructs the array. The destructors of the elements are called and the used storage is deallocated. */
constexpr ~TArray() constexpr ~TArray()
@ -271,8 +304,7 @@ public:
} }
/** Copy assignment operator. Replaces the contents with a copy of the contents of 'InValue'. */ /** Copy assignment operator. Replaces the contents with a copy of the contents of 'InValue'. */
constexpr TArray& operator=(const TArray& InValue) constexpr TArray& operator=(const TArray& InValue) requires (CCopyable<ElementType>)
requires (CCopyConstructible<ElementType> && CCopyAssignable<ElementType>)
{ {
if (&InValue == this) UNLIKELY return *this; if (&InValue == this) UNLIKELY return *this;
@ -313,8 +345,7 @@ public:
} }
/** Move assignment operator. After the move, 'InValue' is guaranteed to be empty. */ /** Move assignment operator. After the move, 'InValue' is guaranteed to be empty. */
constexpr TArray& operator=(TArray&& InValue) constexpr TArray& operator=(TArray&& InValue) requires (CMovable<ElementType>)
requires (CMoveConstructible<ElementType>&& CMoveAssignable<ElementType>)
{ {
if (&InValue == this) UNLIKELY return *this; if (&InValue == this) UNLIKELY return *this;
@ -373,8 +404,7 @@ public:
} }
/** Replaces the contents with those identified by initializer list. */ /** Replaces the contents with those identified by initializer list. */
constexpr TArray& operator=(initializer_list<ElementType> IL) constexpr TArray& operator=(initializer_list<ElementType> IL) requires (CCopyable<ElementType>)
requires (CCopyConstructible<ElementType> && CCopyAssignable<ElementType>)
{ {
size_t NumToAllocate = GetNum(IL); size_t NumToAllocate = GetNum(IL);
@ -460,8 +490,7 @@ public:
} }
/** Inserts 'InValue' before 'Iter' in the container. */ /** Inserts 'InValue' before 'Iter' in the container. */
constexpr Iterator Insert(ConstIterator Iter, const ElementType& InValue) constexpr Iterator Insert(ConstIterator Iter, const ElementType& InValue) requires (CCopyable<ElementType>)
requires (CCopyConstructible<ElementType> && CCopyAssignable<ElementType> && CMoveConstructible<ElementType> && CMoveAssignable<ElementType>)
{ {
checkf(IsValidIterator(Iter), TEXT("Read access violation. Please check IsValidIterator().")); checkf(IsValidIterator(Iter), TEXT("Read access violation. Please check IsValidIterator()."));
@ -509,8 +538,7 @@ public:
} }
/** Inserts 'InValue' before 'Iter' in the container. */ /** Inserts 'InValue' before 'Iter' in the container. */
constexpr Iterator Insert(ConstIterator Iter, ElementType&& InValue) constexpr Iterator Insert(ConstIterator Iter, ElementType&& InValue) requires (CMovable<ElementType>)
requires (CMoveConstructible<ElementType> && CMoveAssignable<ElementType>)
{ {
checkf(IsValidIterator(Iter), TEXT("Read access violation. Please check IsValidIterator().")); 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. */ /** Inserts 'Count' copies of the 'InValue' before 'Iter' in the container. */
constexpr Iterator Insert(ConstIterator Iter, size_t Count, const ElementType& InValue) constexpr Iterator Insert(ConstIterator Iter, size_t Count, const ElementType& InValue) requires (CCopyable<ElementType>)
requires (CCopyConstructible<ElementType> && CCopyAssignable<ElementType> && CMoveConstructible<ElementType> && CMoveAssignable<ElementType>)
{ {
checkf(IsValidIterator(Iter), TEXT("Read access violation. Please check IsValidIterator().")); checkf(IsValidIterator(Iter), TEXT("Read access violation. Please check IsValidIterator()."));
@ -630,107 +657,126 @@ public:
const size_t IndexC = InsertIndex + Count; const size_t IndexC = InsertIndex + Count;
const size_t IndexB = Num() > IndexA ? (Num() < IndexC ? Num() : IndexC) : IndexA; const size_t IndexB = Num() > IndexA ? (Num() < IndexC ? Num() : IndexC) : IndexA;
const size_t IndexD = Num() > IndexC ? Num() : IndexC; const size_t IndexD = Num() > IndexC ? Num() : IndexC;
const size_t IndexO = Num() + Count;
size_t TargetIndex = Num() + Count - 1; for (size_t TargetIndex = IndexO - 1; TargetIndex != IndexD - 1; --TargetIndex)
for (; TargetIndex != IndexD - 1; --TargetIndex)
{ {
new (Storage.GetPointer() + TargetIndex) ElementType(MoveTemp(Storage.GetPointer()[TargetIndex - Count])); 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]); Storage.GetPointer()[TargetIndex] = MoveTemp(Storage.GetPointer()[TargetIndex - Count]);
} }
for (; TargetIndex != IndexB - 1; --TargetIndex) for (size_t TargetIndex = IndexA; TargetIndex != IndexB; ++TargetIndex)
{
new (Storage.GetPointer() + TargetIndex) ElementType(InValue);
}
for (; TargetIndex != IndexA - 1; --TargetIndex)
{ {
Storage.GetPointer()[TargetIndex] = InValue; Storage.GetPointer()[TargetIndex] = InValue;
} }
for (size_t TargetIndex = IndexB; TargetIndex != IndexC; ++TargetIndex)
{
new (Storage.GetPointer() + TargetIndex) ElementType(InValue);
}
Storage.GetNum() = Num() + Count; Storage.GetNum() = Num() + Count;
return Iterator(this, Storage.GetPointer() + InsertIndex); return Iterator(this, Storage.GetPointer() + InsertIndex);
} }
/** Inserts elements from initializer list before 'Iter' in the container. */ /** Inserts elements from range ['First', 'Last') before 'Iter'. */
constexpr Iterator Insert(ConstIterator Iter, initializer_list<ElementType> IL) template <CInputIterator I, CSentinelFor<I> S> requires (CConstructibleFrom<ElementType, TIteratorReferenceType<I>>
requires (CCopyConstructible<ElementType> && CCopyAssignable<ElementType> && CMoveConstructible<ElementType> && CMoveAssignable<ElementType>) && CAssignableFrom<ElementType&, TIteratorReferenceType<I>> && CMovable<ElementType>)
constexpr Iterator Insert(ConstIterator Iter, I First, S Last)
{ {
checkf(IsValidIterator(Iter), TEXT("Read access violation. Please check IsValidIterator().")); checkf(IsValidIterator(Iter), TEXT("Read access violation. Please check IsValidIterator()."));
const size_t InsertIndex = Iter - Begin(); if constexpr (CForwardIterator<I>)
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())
{ {
ElementType* OldAllocation = Storage.GetPointer(); if constexpr (CRandomAccessIterator<I>) checkf(First <= Last, TEXT("Illegal range iterator. Please check First <= Last."));
const size_t NumToDestruct = Num();
Storage.GetNum() = Num() + Count; const size_t InsertIndex = Iter - Begin();
Storage.GetMax() = NumToAllocate; const size_t Count = Iteration::Distance(First, Last);
Storage.GetPointer() = Storage.GetAllocator().Allocate(Max());
Memory::MoveConstruct<ElementType>(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<ElementType>(Storage.GetPointer(), OldAllocation, InsertIndex);
for (size_t Index = InsertIndex; Index != InsertIndex + Count; ++Index)
{
new (Storage.GetPointer() + Index) ElementType(*First++);
}
Memory::MoveConstruct<ElementType>(Storage.GetPointer() + InsertIndex + Count, OldAllocation + InsertIndex, NumToDestruct - InsertIndex);
Memory::Destruct(OldAllocation, NumToDestruct);
Storage.GetAllocator().Deallocate(OldAllocation);
return Iterator(this, Storage.GetPointer() + InsertIndex);
} }
Memory::MoveConstruct<ElementType>(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); size_t TargetIndex = Num() + Count - 1;
Storage.GetAllocator().Deallocate(OldAllocation);
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); return Iterator(this, Storage.GetPointer() + InsertIndex);
} }
else
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)
{ {
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) /** Inserts elements from initializer list before 'Iter' in the container. */
{ FORCEINLINE constexpr Iterator Insert(ConstIterator Iter, initializer_list<ElementType> IL) requires (CCopyable<ElementType>)
Storage.GetPointer()[TargetIndex] = MoveTemp(Storage.GetPointer()[TargetIndex - Count]); {
} return Insert(Iter, Iteration::Begin(IL), Iteration::End(IL));
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 a new element into the container directly before 'Iter'. */ /** Inserts a new element into the container directly before 'Iter'. */
template <typename... Ts> requires (CConstructibleFrom<ElementType, Ts...> && CMoveConstructible<ElementType> && CMoveAssignable<ElementType>) template <typename... Ts> requires (CConstructibleFrom<ElementType, Ts...> && CMovable<ElementType>)
constexpr Iterator Emplace(ConstIterator Iter, Ts&&... Args) constexpr Iterator Emplace(ConstIterator Iter, Ts&&... Args)
{ {
checkf(IsValidIterator(Iter), TEXT("Read access violation. Please check IsValidIterator().")); 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. */ /** Removes the element at 'Iter' in the container. Without changing the order of elements. */
FORCEINLINE constexpr Iterator StableErase(ConstIterator Iter, bool bAllowShrinking = true) FORCEINLINE constexpr Iterator StableErase(ConstIterator Iter, bool bAllowShrinking = true) requires (CMovable<ElementType>)
requires (CMoveConstructible<ElementType> && CMoveAssignable<ElementType>)
{ {
checkf(IsValidIterator(Iter) && Iter != End(), TEXT("Read access violation. Please check IsValidIterator().")); checkf(IsValidIterator(Iter) && Iter != End(), TEXT("Read access violation. Please check IsValidIterator()."));
return StableErase(Iter, Iter + 1, bAllowShrinking); return StableErase(Iter, Iter + 1, bAllowShrinking);
} }
/** Removes the elements in the range ['FirstIter', 'LastIter') in the container. Without changing the order of elements. */ /** Removes the elements in the range ['First', 'Last') in the container. Without changing the order of elements. */
constexpr Iterator StableErase(ConstIterator FirstIter, ConstIterator LastIter, bool bAllowShrinking = true) constexpr Iterator StableErase(ConstIterator First, ConstIterator Last, bool bAllowShrinking = true) requires (CMovable<ElementType>)
requires (CMoveConstructible<ElementType> && CMoveAssignable<ElementType>)
{ {
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 EraseIndex = First - Begin();
const size_t EraseCount = LastIter - FirstIter; const size_t EraseCount = Last - First;
if (EraseCount == 0) return Iterator(this, Storage.GetPointer() + EraseIndex); 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. */ /** 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) FORCEINLINE constexpr Iterator Erase(ConstIterator Iter, bool bAllowShrinking = true) requires (CMovable<ElementType>)
requires (CMoveConstructible<ElementType> && CMoveAssignable<ElementType>)
{ {
checkf(IsValidIterator(Iter) && Iter != End(), TEXT("Read access violation. Please check IsValidIterator().")); checkf(IsValidIterator(Iter) && Iter != End(), TEXT("Read access violation. Please check IsValidIterator()."));
return Erase(Iter, Iter + 1, bAllowShrinking); 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. */ /** Removes the elements in the range ['First', 'Last') in the container. But it may change the order of elements. */
constexpr Iterator Erase(ConstIterator FirstIter, ConstIterator LastIter, bool bAllowShrinking = true) constexpr Iterator Erase(ConstIterator First, ConstIterator Last, bool bAllowShrinking = true) requires (CMovable<ElementType>)
requires (CMoveConstructible<ElementType> && CMoveAssignable<ElementType>)
{ {
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 EraseIndex = First - Begin();
const size_t EraseCount = LastIter - FirstIter; const size_t EraseCount = Last - First;
if (EraseCount == 0) return Iterator(this, Storage.GetPointer() + EraseIndex); 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. */ /** Appends the given element value to the end of the container. */
FORCEINLINE constexpr void PushBack(const ElementType& InValue) FORCEINLINE constexpr void PushBack(const ElementType& InValue) requires (CCopyable<ElementType>)
requires (CCopyConstructible<ElementType> && CCopyAssignable<ElementType> && CMoveConstructible<ElementType> && CMoveAssignable<ElementType>)
{ {
EmplaceBack(InValue); EmplaceBack(InValue);
} }
/** Appends the given element value to the end of the container. */ /** Appends the given element value to the end of the container. */
FORCEINLINE constexpr void PushBack(ElementType&& InValue) FORCEINLINE constexpr void PushBack(ElementType&& InValue) requires (CMovable<ElementType>)
requires (CMoveConstructible<ElementType> && CMoveAssignable<ElementType>)
{ {
EmplaceBack(MoveTemp(InValue)); EmplaceBack(MoveTemp(InValue));
} }
/** Appends a new element to the end of the container. */ /** Appends a new element to the end of the container. */
template <typename... Ts> requires (CConstructibleFrom<ElementType, Ts...> && CMoveConstructible<ElementType> && CMoveAssignable<ElementType>) template <typename... Ts> requires (CConstructibleFrom<ElementType, Ts...> && CMovable<ElementType>)
constexpr ElementType& EmplaceBack(Ts&&... Args) constexpr ElementType& EmplaceBack(Ts&&... Args)
{ {
const size_t NumToAllocate = Num() + 1 > Max() ? Storage.GetAllocator().CalculateSlackGrow(Num() + 1, Max()) : Max(); 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. */ /** Removes the last element of the container. The array cannot be empty. */
FORCEINLINE constexpr void PopBack(bool bAllowShrinking = true) FORCEINLINE constexpr void PopBack(bool bAllowShrinking = true) requires (CMovable<ElementType>)
requires (CMoveConstructible<ElementType> && CMoveAssignable<ElementType>)
{ {
Erase(End() - 1, bAllowShrinking); Erase(End() - 1, bAllowShrinking);
} }
/** Resizes the container to contain 'Count' elements. Additional default elements are appended. */ /** Resizes the container to contain 'Count' elements. Additional default elements are appended. */
constexpr void SetNum(size_t Count, bool bAllowShrinking = true) constexpr void SetNum(size_t Count, bool bAllowShrinking = true) requires (CDefaultConstructible<ElementType> && CMovable<ElementType>)
requires (CDefaultConstructible<ElementType> && CMoveConstructible<ElementType> && CMoveAssignable<ElementType>)
{ {
size_t NumToAllocate = Count; size_t NumToAllocate = Count;
@ -986,8 +1024,7 @@ public:
} }
/** Resizes the container to contain 'Count' elements. Additional copies of 'InValue' are appended. */ /** 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) constexpr void SetNum(size_t Count, const ElementType& InValue, bool bAllowShrinking = true) requires (CCopyConstructible<ElementType> && CMovable<ElementType>)
requires (CCopyConstructible<ElementType> && CMoveConstructible<ElementType> && CMoveAssignable<ElementType>)
{ {
size_t NumToAllocate = Count; 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'. */ /** Increase the max capacity of the array to a value that's greater or equal to 'Count'. */
constexpr void Reserve(size_t Count) constexpr void Reserve(size_t Count) requires (CMovable<ElementType>)
requires (CMoveConstructible<ElementType> && CMoveAssignable<ElementType>)
{ {
if (Count <= Max()) return; if (Count <= Max()) return;
@ -1112,11 +1148,11 @@ public:
NODISCARD FORCEINLINE constexpr const ElementType& Back() const { return *(End() - 1); } NODISCARD FORCEINLINE constexpr const ElementType& Back() const { return *(End() - 1); }
/** Erases all elements from the container. After this call, Num() returns zero. */ /** 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); const size_t NumToAllocate = Storage.GetAllocator().CalculateSlackReserve(0);
if (NumToAllocate != Max()) if (bAllowShrinking && NumToAllocate != Max())
{ {
Memory::Destruct(Storage.GetPointer(), Num()); Memory::Destruct(Storage.GetPointer(), Num());
Storage.GetAllocator().Deallocate(Storage.GetPointer()); Storage.GetAllocator().Deallocate(Storage.GetPointer());
@ -1146,8 +1182,7 @@ public:
} }
/** Overloads the Swap algorithm for TArray. */ /** Overloads the Swap algorithm for TArray. */
friend constexpr void Swap(TArray& A, TArray& B) friend constexpr void Swap(TArray& A, TArray& B) requires (CMovable<ElementType>)
requires (CSwappable<ElementType> && CMoveConstructible<ElementType> && CMoveAssignable<ElementType>)
{ {
const bool bIsTransferable = const bool bIsTransferable =
A.Storage.GetAllocator().IsTransferable(A.Storage.GetPointer()) && A.Storage.GetAllocator().IsTransferable(A.Storage.GetPointer()) &&

View File

@ -1,4 +1,5 @@
#pragma once #pragma once
#include "CoreTypes.h" #include "CoreTypes.h"
#include "Containers/Iterator.h"
#include "Containers/Array.h" #include "Containers/Array.h"

View File

@ -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 <typename T> using WithReference = T&;
template <typename I>
struct TIteratorElementType
{
using Type = typename I::ElementType;
};
template <typename T>
struct TIteratorElementType<T*>
{
using Type = T;
};
NAMESPACE_PRIVATE_END
template <typename T>
concept CReferenceable = requires { typename NAMESPACE_PRIVATE::WithReference<T>; };
template <typename T>
concept CDereferenceable = requires(T& A) { { *A } -> CReferenceable; };
template <typename I>
using TIteratorElementType = typename NAMESPACE_PRIVATE::TIteratorElementType<I>::Type;
template <CReferenceable I>
using TIteratorReferenceType = decltype(*DeclVal<I&>());
template <CReferenceable T> requires (requires(T& Iter) { { MoveTemp(*Iter) } -> CReferenceable; })
using TIteratorRValueReferenceType = decltype(MoveTemp(*DeclVal<T&>()));
template <typename I>
concept CIndirectlyReadable =
requires(const I Iter)
{
typename TIteratorElementType<I>;
typename TIteratorReferenceType<I>;
typename TIteratorRValueReferenceType<I>;
{ *Iter } -> CSameAs<TIteratorReferenceType<I>>;
{ MoveTemp(*Iter) } -> CSameAs<TIteratorRValueReferenceType<I>>;
}
&& CCommonReference<TIteratorReferenceType<I>&&, TIteratorElementType<I>&>
&& CCommonReference<TIteratorReferenceType<I>&&, TIteratorRValueReferenceType<I>&&>
&& CCommonReference<TIteratorRValueReferenceType<I>&&, const TIteratorElementType<I>&>;
template <typename I, typename T>
concept CIndirectlyWritable =
requires(I && Iter, T && A)
{
*Iter = Forward<T>(A);
*Forward<I>(Iter) = Forward<T>(A);
const_cast<const TIteratorElementType<I>&&>(*Iter) = Forward<T>(A);
const_cast<const TIteratorElementType<I>&&>(*Forward<I>(Iter)) = Forward<T>(A);
};
template <typename I>
concept CWeaklyIncrementable = CDefaultConstructible<I> && CMovable<I>
&& requires(I Iter) { { ++Iter } -> CSameAs<I&>; Iter++; };
template <typename I>
concept CIncrementable = CRegular<I> && CWeaklyIncrementable<I>
&& requires(I Iter) { { Iter++ } -> CSameAs<I>; };
template <typename I>
concept CInputOrOutputIterator = CWeaklyIncrementable<I>
&& requires(I Iter) { { *Iter } -> CReferenceable; };
template <typename S, typename I>
concept CSentinelFor = CSemiregular<S> && CInputOrOutputIterator<I> && CWeaklyEqualityComparable<S, I>;
template <typename S, typename I>
inline constexpr bool bDisableSizedSentinelFor = false;
template <typename S, typename I>
concept CSizedSentinelFor = CSentinelFor<S, I> && !bDisableSizedSentinelFor<TRemoveCV<S>, TRemoveCV<I>>
&& requires(const I& Iter, const S& Sentinel) { Sentinel - Iter; Iter - Sentinel; };
template <typename I>
concept CInputIterator = CInputOrOutputIterator<I> && CIndirectlyReadable<I>;
template <typename I, typename T>
concept COutputIterator = CInputOrOutputIterator<I> && CIndirectlyWritable<I, T>
&& requires(I Iter, T&& A) { *Iter++ = Forward<T>(A); };
template <typename I>
concept CForwardIterator = CInputIterator<I> && CIncrementable<I> && CSentinelFor<I, I>;
template <typename I>
concept CBidirectionalIterator = CForwardIterator<I>
&& requires(I Iter) {
{ --Iter } -> CSameAs<I&>;
{ Iter-- } -> CSameAs<I >;
};
template <typename I>
concept CRandomAccessIterator = CBidirectionalIterator<I> && CTotallyOrdered<I> && CSizedSentinelFor<I, I>
&& requires(I Iter, const I Jter, const ptrdiff N) {
{ Iter += N } -> CSameAs<I&>;
{ Jter + N } -> CSameAs<I >;
{ N + Jter } -> CSameAs<I >;
{ Iter -= N } -> CSameAs<I&>;
{ Jter - N } -> CSameAs<I >;
{ Jter[N] } -> CSameAs<TIteratorReferenceType<I>>;
};
template <typename I>
concept CContiguousIterator = CRandomAccessIterator<I> && CLValueReference<TIteratorReferenceType<I>>
&& CSameAs<TIteratorElementType<I>, TRemoveReference<TIteratorReferenceType<I>>>
&& requires(I& Iter)
{
static_cast<TAddPointer<TIteratorReferenceType<I>>>(Iter);
{ AddressOf(*Iter) } -> CSameAs<TAddPointer<TIteratorReferenceType<I>>>;
};
static_assert(CContiguousIterator<int32*>);
NAMESPACE_BEGIN(Iteration)
/** Increments given iterator 'Iter' by 'N' elements. */
template <CInputIterator I>
FORCEINLINE constexpr void Advance(I& Iter, ptrdiff N)
{
if constexpr (CRandomAccessIterator<I>)
{
Iter += N;
}
else if constexpr (CBidirectionalIterator<I>)
{
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 <CInputIterator I, CSentinelFor<I> S>
FORCEINLINE constexpr ptrdiff Distance(I First, S Last)
{
if constexpr (CSizedSentinelFor<I, S>)
{
return Last - First;
}
else
{
ptrdiff Result = 0;
for (; First != Last; ++First) ++Result;
return Result;
}
}
/** @return The 'N'-th successor of iterator 'Iter'. */
template <CInputIterator I>
FORCEINLINE constexpr I Next(I Iter, TMakeUnsigned<ptrdiff> N = 1)
{
Advance(Iter, N);
return Iter;
}
/** @return The 'N'-th predecessor of iterator 'Iter'. */
template <CBidirectionalIterator I>
FORCEINLINE constexpr I Prev(I Iter, TMakeUnsigned<ptrdiff> N = 1)
{
Advance(Iter, -N);
return Iter;
}
/** @return The iterator to the beginning of a container. */
template <typename T> requires (requires(T&& Container) { { Container.Begin() } -> CForwardIterator; })
FORCEINLINE constexpr decltype(auto) Begin(T&& Container)
{
return Container.Begin();
}
/** Overloads the Begin algorithm for arrays. */
template <typename T, size_t N> FORCEINLINE constexpr T* Begin( T(& Container)[N]) { return Container; }
template <typename T, size_t N> FORCEINLINE constexpr T* Begin( T(&& Container)[N]) { return Container; }
template <typename T, size_t N> FORCEINLINE constexpr const T* Begin(const T(& Container)[N]) { return Container; }
template <typename T, size_t N> FORCEINLINE constexpr const T* Begin(const T(&& Container)[N]) { return Container; }
/** Overloads the Begin algorithm for T::begin(). */
template <typename T> 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 <typename T> requires (requires(T&& Container) { { Container.End() } -> CForwardIterator; })
FORCEINLINE constexpr decltype(auto) End(T&& Container)
{
return Container.End();
}
/** Overloads the End algorithm for arrays. */
template <typename T, size_t N> FORCEINLINE constexpr T* End( T(& Container)[N]) { return Container + N; }
template <typename T, size_t N> FORCEINLINE constexpr T* End( T(&& Container)[N]) { return Container + N; }
template <typename T, size_t N> FORCEINLINE constexpr const T* End(const T(& Container)[N]) { return Container + N; }
template <typename T, size_t N> FORCEINLINE constexpr const T* End(const T(&& Container)[N]) { return Container + N; }
/** Overloads the End algorithm for T::end(). */
template <typename T> 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