Compare commits

...

2 Commits

4 changed files with 404 additions and 137 deletions

View File

@ -127,6 +127,8 @@ void* Realloc(void* Ptr, size_t Count, size_t Alignment)
void Free(void* Ptr)
{
if (Ptr == nullptr) return;
# if PLATFORM_WINDOWS
{
_aligned_free(Ptr);
@ -137,7 +139,7 @@ void Free(void* Ptr)
}
# endif
check_code({ if (Ptr != nullptr) MemoryLeakChecker.ReleaseMemoryAllocationCount(); });
check_code({ MemoryLeakChecker.ReleaseMemoryAllocationCount(); });
}
size_t QuantizeSize(size_t Count, size_t Alignment)

View File

@ -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 <typename ArrayType, typename ElementType>
template <typename ArrayType, typename T>
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<ArrayType, TRemoveConst<ElementType>>& InValue) requires (CConst<ElementType>)
: Owner(InValue.Owner), Pointer(InValue.Pointer)
{ }
# elif
# else
FORCEINLINE constexpr TArrayIterator(const TArrayIterator<ArrayType, TRemoveConst<ElementType>>& InValue) requires (CConst<ElementType>)
: 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<ElementType>) { 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<TArray, 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. */
FORCEINLINE constexpr TArray() : TArray(0) { }
/** Constructs the container with 'Count' default instances of T. */
constexpr explicit TArray(size_t Count)
requires (CDefaultConstructible<ElementType>)
{
constexpr explicit TArray(size_t Count) requires (CDefaultConstructible<ElementType>)
{
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<ElementType>)
constexpr TArray(size_t Count, const ElementType& InValue) requires (CCopyConstructible<ElementType>)
{
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 <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'. */
constexpr TArray(const TArray& InValue)
requires (CCopyConstructible<ElementType>)
constexpr TArray(const TArray& InValue) requires (CCopyConstructible<ElementType>)
{
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<ElementType>)
constexpr TArray(TArray&& InValue) requires (CMoveConstructible<ElementType>)
{
Storage.GetNum() = InValue.Num();
@ -253,15 +294,7 @@ public:
}
/** Constructs the container with the contents of the initializer list. */
constexpr TArray(initializer_list<ElementType> 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());
}
FORCEINLINE constexpr TArray(initializer_list<ElementType> IL) requires (CCopyConstructible<ElementType>) : 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<ElementType> && CCopyAssignable<ElementType>)
constexpr TArray& operator=(const TArray& InValue) requires (CCopyable<ElementType>)
{
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<ElementType>&& CMoveAssignable<ElementType>)
constexpr TArray& operator=(TArray&& InValue) requires (CMovable<ElementType>)
{
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<ElementType> IL)
requires (CCopyConstructible<ElementType> && CCopyAssignable<ElementType>)
constexpr TArray& operator=(initializer_list<ElementType> IL) requires (CCopyable<ElementType>)
{
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<ElementType> && CCopyAssignable<ElementType> && CMoveConstructible<ElementType> && CMoveAssignable<ElementType>)
constexpr Iterator Insert(ConstIterator Iter, const ElementType& InValue) requires (CCopyable<ElementType>)
{
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<ElementType> && CMoveAssignable<ElementType>)
constexpr Iterator Insert(ConstIterator Iter, ElementType&& InValue) requires (CMovable<ElementType>)
{
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<ElementType> && CCopyAssignable<ElementType> && CMoveConstructible<ElementType> && CMoveAssignable<ElementType>)
constexpr Iterator Insert(ConstIterator Iter, size_t Count, const ElementType& InValue) requires (CCopyable<ElementType>)
{
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<ElementType> IL)
requires (CCopyConstructible<ElementType> && CCopyAssignable<ElementType> && CMoveConstructible<ElementType> && CMoveAssignable<ElementType>)
/** Inserts elements from range ['First', 'Last') before 'Iter'. */
template <CInputIterator I, CSentinelFor<I> S> requires (CConstructibleFrom<ElementType, TIteratorReferenceType<I>>
&& 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()."));
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<I>)
{
ElementType* OldAllocation = Storage.GetPointer();
const size_t NumToDestruct = Num();
if constexpr (CRandomAccessIterator<I>) 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<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);
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<ElementType> IL) requires (CCopyable<ElementType>)
{
return Insert(Iter, Iteration::Begin(IL), Iteration::End(IL));
}
/** 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)
{
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<ElementType> && CMoveAssignable<ElementType>)
FORCEINLINE constexpr Iterator StableErase(ConstIterator Iter, bool bAllowShrinking = true) requires (CMovable<ElementType>)
{
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<ElementType> && CMoveAssignable<ElementType>)
/** 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<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 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<ElementType> && CMoveAssignable<ElementType>)
FORCEINLINE constexpr Iterator Erase(ConstIterator Iter, bool bAllowShrinking = true) requires (CMovable<ElementType>)
{
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<ElementType> && CMoveAssignable<ElementType>)
/** 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<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 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<ElementType> && CCopyAssignable<ElementType> && CMoveConstructible<ElementType> && CMoveAssignable<ElementType>)
FORCEINLINE constexpr void PushBack(const ElementType& InValue) requires (CCopyable<ElementType>)
{
EmplaceBack(InValue);
}
/** Appends the given element value to the end of the container. */
FORCEINLINE constexpr void PushBack(ElementType&& InValue)
requires (CMoveConstructible<ElementType> && CMoveAssignable<ElementType>)
FORCEINLINE constexpr void PushBack(ElementType&& InValue) requires (CMovable<ElementType>)
{
EmplaceBack(MoveTemp(InValue));
}
/** 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)
{
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<ElementType> && CMoveAssignable<ElementType>)
FORCEINLINE constexpr void PopBack(bool bAllowShrinking = true) requires (CMovable<ElementType>)
{
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<ElementType> && CMoveConstructible<ElementType> && CMoveAssignable<ElementType>)
constexpr void SetNum(size_t Count, bool bAllowShrinking = true) requires (CDefaultConstructible<ElementType> && CMovable<ElementType>)
{
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<ElementType> && CMoveConstructible<ElementType> && CMoveAssignable<ElementType>)
constexpr void SetNum(size_t Count, const ElementType& InValue, bool bAllowShrinking = true) requires (CCopyConstructible<ElementType> && CMovable<ElementType>)
{
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<ElementType> && CMoveAssignable<ElementType>)
constexpr void Reserve(size_t Count) requires (CMovable<ElementType>)
{
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<ElementType> && CMoveConstructible<ElementType> && CMoveAssignable<ElementType>)
friend constexpr void Swap(TArray& A, TArray& B) requires (CMovable<ElementType>)
{
const bool bIsTransferable =
A.Storage.GetAllocator().IsTransferable(A.Storage.GetPointer()) &&

View File

@ -1,4 +1,5 @@
#pragma once
#include "CoreTypes.h"
#include "Containers/Iterator.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