Compare commits
6 Commits
ea625bb916
...
a3509295ff
Author | SHA1 | Date | |
---|---|---|---|
a3509295ff | |||
cd7adbfd46 | |||
a55f03fea0 | |||
c73fc7620d | |||
5cfde63dd4 | |||
24dd4347d1 |
@ -0,0 +1,67 @@
|
||||
#pragma once
|
||||
|
||||
#include "CoreTypes.h"
|
||||
#include "Iterator/Utility.h"
|
||||
#include "Iterator/Sentinel.h"
|
||||
#include "Iterator/ForwardIterator.h"
|
||||
#include "TypeTraits/TypeTraits.h"
|
||||
|
||||
NAMESPACE_REDCRAFT_BEGIN
|
||||
NAMESPACE_MODULE_BEGIN(Redcraft)
|
||||
NAMESPACE_MODULE_BEGIN(Utility)
|
||||
|
||||
#if PLATFORM_COMPILER_GCC
|
||||
# pragma GCC diagnostic push
|
||||
# pragma GCC diagnostic ignored "-Wnon-template-friend"
|
||||
#endif
|
||||
|
||||
/** A concept specifies a type is a bidirectional iterator. Add the decrement operator to the forward iterator. */
|
||||
template <typename I>
|
||||
concept CBidirectionalIterator = CForwardIterator<I>
|
||||
&& requires(I Iter) {
|
||||
{ --Iter } -> CSameAs<I&>;
|
||||
{ Iter-- } -> CSameAs<I >;
|
||||
};
|
||||
|
||||
/**
|
||||
* This is an example of a bidirectional iterator, indicate the traits that define a bidirectional iterator.
|
||||
* Regardless of the order in which the increment and decrement operators are applied,
|
||||
* the result is always the same if both operations are performed the same number of times.
|
||||
*/
|
||||
template <CReferenceable T>
|
||||
struct IBidirectionalIterator /* : IForwardIterator<T> */
|
||||
{
|
||||
// ~Begin CForwardIterator.
|
||||
|
||||
using ElementType = TRemoveCVRef<T>;
|
||||
|
||||
IBidirectionalIterator();
|
||||
IBidirectionalIterator(const IBidirectionalIterator&);
|
||||
IBidirectionalIterator(IBidirectionalIterator&&);
|
||||
IBidirectionalIterator* operator=(const IBidirectionalIterator&);
|
||||
IBidirectionalIterator* operator=(IBidirectionalIterator&&);
|
||||
|
||||
friend bool operator==(const IBidirectionalIterator&, const IBidirectionalIterator&);
|
||||
|
||||
T operator*() const;
|
||||
|
||||
// ~End CForwardIterator.
|
||||
|
||||
IBidirectionalIterator& operator++(); // Also satisfies CForwardIterator.
|
||||
IBidirectionalIterator& operator--();
|
||||
|
||||
IBidirectionalIterator operator++(int); // Also satisfies CForwardIterator.
|
||||
IBidirectionalIterator operator--(int);
|
||||
};
|
||||
|
||||
// Use IBidirectionalIterator<int> represents a bidirectional iterator.
|
||||
static_assert(CBidirectionalIterator<IBidirectionalIterator<int&>>);
|
||||
static_assert( COutputIterator<IBidirectionalIterator<int&>, int>);
|
||||
|
||||
#if PLATFORM_COMPILER_GCC
|
||||
# pragma GCC diagnostic pop
|
||||
#endif
|
||||
|
||||
NAMESPACE_MODULE_END(Utility)
|
||||
NAMESPACE_MODULE_END(Redcraft)
|
||||
NAMESPACE_REDCRAFT_END
|
98
Redcraft.Utility/Source/Public/Iterator/ContiguousIterator.h
Normal file
98
Redcraft.Utility/Source/Public/Iterator/ContiguousIterator.h
Normal file
@ -0,0 +1,98 @@
|
||||
#pragma once
|
||||
|
||||
#include "CoreTypes.h"
|
||||
#include "Iterator/Utility.h"
|
||||
#include "Iterator/Sentinel.h"
|
||||
#include "Iterator/RandomAccessIterator.h"
|
||||
#include "TypeTraits/TypeTraits.h"
|
||||
#include "Memory/Address.h"
|
||||
|
||||
NAMESPACE_REDCRAFT_BEGIN
|
||||
NAMESPACE_MODULE_BEGIN(Redcraft)
|
||||
NAMESPACE_MODULE_BEGIN(Utility)
|
||||
|
||||
#if PLATFORM_COMPILER_GCC
|
||||
# pragma GCC diagnostic push
|
||||
# pragma GCC diagnostic ignored "-Wnon-template-friend"
|
||||
#endif
|
||||
|
||||
/**
|
||||
* A concept specifies a type is a contiguous iterator.
|
||||
* Add the operator-> to the random access iterator and requires the operator* returns a true reference type.
|
||||
*/
|
||||
template <typename I>
|
||||
concept CContiguousIterator = CRandomAccessIterator<I> && CLValueReference<TIteratorReference<I>>
|
||||
&& CSameAs<TIteratorElement<I>, TRemoveCVRef<TIteratorReference<I>>>
|
||||
&& CSameAs<TIteratorPointer<I>, TAddPointer<TIteratorReference<I>>>
|
||||
&& requires(I& Iter)
|
||||
{
|
||||
{ ToAddress(Iter) } -> CSameAs<TAddPointer<TIteratorReference<I>>>;
|
||||
};
|
||||
|
||||
/** This is an example of a contiguous iterator, indicate the traits that define a contiguous iterator. */
|
||||
template <CLValueReference T>
|
||||
struct IContiguousIterator /* : IRandomAccessIterator<T> */
|
||||
{
|
||||
// ~Begin CRandomAccessIterator.
|
||||
|
||||
using ElementType = TRemoveCVRef<T>;
|
||||
|
||||
IContiguousIterator();
|
||||
IContiguousIterator(const IContiguousIterator&);
|
||||
IContiguousIterator(IContiguousIterator&&);
|
||||
IContiguousIterator* operator=(const IContiguousIterator&);
|
||||
IContiguousIterator* operator=(IContiguousIterator&&);
|
||||
|
||||
friend bool operator==(const IContiguousIterator&, const IContiguousIterator&);
|
||||
|
||||
friend strong_ordering operator<=>(const IContiguousIterator&, const IContiguousIterator&);
|
||||
|
||||
// ~End CRandomAccessIterator.
|
||||
|
||||
/**
|
||||
* Dereference operator. See IForwardIterator.
|
||||
* Specify, the return type must be a true reference type and refer to an element of a contiguous sequence, not a proxy class.
|
||||
* Also satisfies CRandomAccessIterator.
|
||||
*/
|
||||
T operator*() const;
|
||||
|
||||
/** Indirection operator. Return the address of the element that the iterator is pointing to. */
|
||||
TAddPointer<T> operator->() const;
|
||||
|
||||
// ~Begin CRandomAccessIterator.
|
||||
|
||||
T operator[](ptrdiff) const;
|
||||
|
||||
IContiguousIterator& operator++();
|
||||
IContiguousIterator& operator--();
|
||||
|
||||
IContiguousIterator operator++(int);
|
||||
IContiguousIterator operator--(int);
|
||||
|
||||
IContiguousIterator& operator+=(ptrdiff);
|
||||
IContiguousIterator& operator-=(ptrdiff);
|
||||
|
||||
IContiguousIterator operator+(ptrdiff) const;
|
||||
IContiguousIterator operator-(ptrdiff) const;
|
||||
|
||||
friend IContiguousIterator operator+(ptrdiff, const IContiguousIterator&);
|
||||
|
||||
friend ptrdiff operator-(const IContiguousIterator&, const IContiguousIterator&);
|
||||
|
||||
// ~End CRandomAccessIterator.
|
||||
};
|
||||
|
||||
// Use IContiguousIterator<int> represents a contiguous iterator
|
||||
static_assert(CContiguousIterator<IContiguousIterator<int&>>);
|
||||
static_assert( COutputIterator<IContiguousIterator<int&>, int>);
|
||||
|
||||
// The int* is the most typical example of a contiguous iterator
|
||||
static_assert(CContiguousIterator<int*>);
|
||||
|
||||
#if PLATFORM_COMPILER_GCC
|
||||
# pragma GCC diagnostic pop
|
||||
#endif
|
||||
|
||||
NAMESPACE_MODULE_END(Utility)
|
||||
NAMESPACE_MODULE_END(Redcraft)
|
||||
NAMESPACE_REDCRAFT_END
|
152
Redcraft.Utility/Source/Public/Iterator/CountedIterator.h
Normal file
152
Redcraft.Utility/Source/Public/Iterator/CountedIterator.h
Normal file
@ -0,0 +1,152 @@
|
||||
#pragma once
|
||||
|
||||
#include "CoreTypes.h"
|
||||
#include "Iterator/Utility.h"
|
||||
#include "Iterator/Sentinel.h"
|
||||
#include "Iterator/BidirectionalIterator.h"
|
||||
#include "Iterator/RandomAccessIterator.h"
|
||||
#include "Iterator/ContiguousIterator.h"
|
||||
#include "Miscellaneous/AssertionMacros.h"
|
||||
#include "Miscellaneous/Compare.h"
|
||||
#include "TypeTraits/TypeTraits.h"
|
||||
#include "Templates/Utility.h"
|
||||
#include "Memory/Address.h"
|
||||
|
||||
NAMESPACE_REDCRAFT_BEGIN
|
||||
NAMESPACE_MODULE_BEGIN(Redcraft)
|
||||
NAMESPACE_MODULE_BEGIN(Utility)
|
||||
|
||||
NAMESPACE_PRIVATE_BEGIN
|
||||
|
||||
template <typename T> class TCountedIteratorImpl { };
|
||||
template <CIndirectlyReadable T> class TCountedIteratorImpl<T> { public: using ElementType = TIteratorElement<T>; };
|
||||
|
||||
NAMESPACE_PRIVATE_END
|
||||
|
||||
/**
|
||||
* An iterator adaptor that tracks the distance to the end of the range.
|
||||
* When based on an input or output iterator, the counted iterator satisfies at least an input or output iterator
|
||||
* up to a contiguous iterator. When based on an output iterator, the counted iterator satisfies an output iterator.
|
||||
* When based on iterator satisfies sentinel for itself, the counted iterator satisfies sized sentinel for itself.
|
||||
*/
|
||||
template <CInputOrOutputIterator I>
|
||||
class TCountedIterator final : public NAMESPACE_PRIVATE::TCountedIteratorImpl<I>
|
||||
{
|
||||
public:
|
||||
|
||||
using IteratorType = I;
|
||||
|
||||
# if DO_CHECK
|
||||
FORCEINLINE constexpr TCountedIterator() requires (CDefaultConstructible<I>) : Length(1), MaxLength(0) { }
|
||||
# else
|
||||
FORCEINLINE constexpr TCountedIterator() requires (CDefaultConstructible<I>) = default;
|
||||
# endif
|
||||
|
||||
FORCEINLINE constexpr TCountedIterator(const TCountedIterator&) = default;
|
||||
FORCEINLINE constexpr TCountedIterator(TCountedIterator&&) = default;
|
||||
FORCEINLINE constexpr TCountedIterator& operator=(const TCountedIterator&) = default;
|
||||
FORCEINLINE constexpr TCountedIterator& operator=(TCountedIterator&&) = default;
|
||||
FORCEINLINE constexpr ~TCountedIterator() = default;
|
||||
|
||||
FORCEINLINE constexpr explicit TCountedIterator(IteratorType InValue, ptrdiff N) : Current(MoveTemp(InValue)) { check_code({ MaxLength = N; }); }
|
||||
|
||||
template <CInputOrOutputIterator J> requires (!CSameAs<I, J> && CConstructibleFrom<I, const J&>)
|
||||
FORCEINLINE constexpr explicit (!CConvertibleTo<const J&, I>) TCountedIterator(const TCountedIterator<J>& InValue)
|
||||
: Current(InValue.GetBase()), Length(InValue.Num())
|
||||
{
|
||||
check_code({ MaxLength = InValue.MaxLength; });
|
||||
}
|
||||
|
||||
template <CInputOrOutputIterator J> requires (!CSameAs<I, J> && CConvertibleTo<const J&, I> && CAssignableFrom<I&, const J&>)
|
||||
FORCEINLINE constexpr TCountedIterator& operator=(const TCountedIterator<J>& InValue)
|
||||
{
|
||||
Current = InValue.GetBase();
|
||||
Length = InValue.Num();
|
||||
|
||||
check_code({ MaxLength = InValue.MaxLength; });
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <CInputOrOutputIterator J> requires (CCommonType<I, J>)
|
||||
NODISCARD friend FORCEINLINE constexpr bool operator==(const TCountedIterator& LHS, const TCountedIterator<J>& RHS) { return LHS.Length == RHS.Length; }
|
||||
|
||||
template <CInputOrOutputIterator J> requires (CCommonType<I, J>)
|
||||
NODISCARD friend FORCEINLINE constexpr strong_ordering operator<=>(const TCountedIterator& LHS, const TCountedIterator<J>& RHS) { return LHS.Length <=> RHS.Length; }
|
||||
|
||||
NODISCARD FORCEINLINE constexpr bool operator==(FDefaultSentinel) const& { return Length == static_cast<ptrdiff>(0); }
|
||||
|
||||
NODISCARD FORCEINLINE constexpr strong_ordering operator<=>(FDefaultSentinel) const& { return static_cast<ptrdiff>(0) <=> Length; }
|
||||
|
||||
NODISCARD FORCEINLINE constexpr TIteratorReference<I> operator*() { CheckThis(true); return *GetBase(); }
|
||||
NODISCARD FORCEINLINE constexpr TIteratorReference<I> operator*() const requires (CDereferenceable<const I>) { CheckThis(true); return *GetBase(); }
|
||||
|
||||
NODISCARD FORCEINLINE constexpr auto operator->() const requires (requires(const I Iter) { { ToAddress(Iter) } -> CSameAs<TIteratorPointer<I>>; }) { return ToAddress(GetBase()); }
|
||||
|
||||
NODISCARD FORCEINLINE constexpr TIteratorReference<I> operator[](ptrdiff Index) const requires (CRandomAccessIterator<I>) { TCountedIterator Temp = *this + Index; return *Temp; }
|
||||
|
||||
FORCEINLINE constexpr TCountedIterator& operator++() { ++Current; --Length; CheckThis(); return *this; }
|
||||
FORCEINLINE constexpr TCountedIterator& operator--() requires (CBidirectionalIterator<I>) { --Current; ++Length; CheckThis(); return *this; }
|
||||
|
||||
FORCEINLINE constexpr auto operator++(int) { --Length; CheckThis(); return Current++; }
|
||||
FORCEINLINE constexpr TCountedIterator operator++(int) requires (CForwardIterator<I>) { TCountedIterator Temp = *this; ++Current; --Length; CheckThis(); return Temp; }
|
||||
FORCEINLINE constexpr TCountedIterator operator--(int) requires (CBidirectionalIterator<I>) { TCountedIterator Temp = *this; --Current; ++Length; CheckThis(); return Temp; }
|
||||
|
||||
FORCEINLINE constexpr TCountedIterator& operator+=(ptrdiff Offset) requires (CRandomAccessIterator<I>) { Current += Offset; Length -= Offset; CheckThis(); return *this; }
|
||||
FORCEINLINE constexpr TCountedIterator& operator-=(ptrdiff Offset) requires (CRandomAccessIterator<I>) { Current -= Offset; Length += Offset; CheckThis(); return *this; }
|
||||
|
||||
NODISCARD FORCEINLINE constexpr TCountedIterator operator+(ptrdiff Offset) const requires (CRandomAccessIterator<I>) { TCountedIterator Temp = *this; Temp += Offset; return Temp; }
|
||||
NODISCARD FORCEINLINE constexpr TCountedIterator operator-(ptrdiff Offset) const requires (CRandomAccessIterator<I>) { TCountedIterator Temp = *this; Temp -= Offset; return Temp; }
|
||||
|
||||
NODISCARD friend FORCEINLINE constexpr TCountedIterator operator+(ptrdiff Offset, TCountedIterator Iter) requires (CRandomAccessIterator<I>) { return Iter + Offset; }
|
||||
|
||||
template <CInputOrOutputIterator J> requires (CCommonType<I, J>)
|
||||
NODISCARD friend FORCEINLINE constexpr ptrdiff operator-(const TCountedIterator& LHS, const TCountedIterator<J>& RHS) { LHS.CheckThis(); RHS.CheckThis(); return LHS.Length - RHS.Length; }
|
||||
|
||||
NODISCARD friend FORCEINLINE constexpr ptrdiff operator-(const TCountedIterator& LHS, FDefaultSentinel) { LHS.CheckThis(); return -LHS.Num(); }
|
||||
NODISCARD friend FORCEINLINE constexpr ptrdiff operator-(FDefaultSentinel, const TCountedIterator& RHS) { RHS.CheckThis(); return RHS.Num(); }
|
||||
|
||||
NODISCARD FORCEINLINE constexpr const IteratorType& GetBase() const& { CheckThis(); return Current; }
|
||||
NODISCARD FORCEINLINE constexpr IteratorType GetBase() && { CheckThis(); return MoveTemp(Current); }
|
||||
NODISCARD FORCEINLINE constexpr ptrdiff Num() const { CheckThis(); return Length; }
|
||||
|
||||
private:
|
||||
|
||||
IteratorType Current;
|
||||
ptrdiff Length;
|
||||
|
||||
# if DO_CHECK
|
||||
ptrdiff MaxLength;
|
||||
# endif
|
||||
|
||||
FORCEINLINE void CheckThis(bool bExceptEnd = false) const
|
||||
{
|
||||
checkf(static_cast<ptrdiff>(0) <= Length && Length <= MaxLength, TEXT("Read access violation. Please check Num()."));
|
||||
checkf(!(bExceptEnd && Length == static_cast<ptrdiff>(0)), TEXT("Read access violation. Please check Num()."));
|
||||
}
|
||||
|
||||
template <CInputOrOutputIterator J>
|
||||
friend class TCountedIterator;
|
||||
|
||||
};
|
||||
|
||||
static_assert( CInputIterator<TCountedIterator< IInputIterator<int&>>>);
|
||||
static_assert( CForwardIterator<TCountedIterator< IForwardIterator<int&>>>);
|
||||
static_assert(CBidirectionalIterator<TCountedIterator<IBidirectionalIterator<int&>>>);
|
||||
static_assert( CRandomAccessIterator<TCountedIterator< IRandomAccessIterator<int&>>>);
|
||||
static_assert( CContiguousIterator<TCountedIterator< IContiguousIterator<int&>>>);
|
||||
|
||||
//static_assert(COutputIterator<TCountedIterator<IOutputIterator<int&>>, int>);
|
||||
|
||||
static_assert(CSizedSentinelFor<TCountedIterator<IForwardIterator<int>>, TCountedIterator<IForwardIterator<int>>>);
|
||||
|
||||
/** Creates a TCountedIterator of type inferred from the argument. */
|
||||
template <typename I> requires (CInputOrOutputIterator<TDecay<I>> && CConstructibleFrom<TDecay<I>, I>)
|
||||
NODISCARD FORCEINLINE constexpr auto MakeCountedIterator(I&& Iter, ptrdiff N)
|
||||
{
|
||||
return TCountedIterator<TDecay<I>>(Forward<I>(Iter), N);
|
||||
}
|
||||
|
||||
NAMESPACE_MODULE_END(Utility)
|
||||
NAMESPACE_MODULE_END(Redcraft)
|
||||
NAMESPACE_REDCRAFT_END
|
64
Redcraft.Utility/Source/Public/Iterator/ForwardIterator.h
Normal file
64
Redcraft.Utility/Source/Public/Iterator/ForwardIterator.h
Normal file
@ -0,0 +1,64 @@
|
||||
#pragma once
|
||||
|
||||
#include "CoreTypes.h"
|
||||
#include "Iterator/Utility.h"
|
||||
#include "Iterator/Sentinel.h"
|
||||
#include "TypeTraits/TypeTraits.h"
|
||||
|
||||
NAMESPACE_REDCRAFT_BEGIN
|
||||
NAMESPACE_MODULE_BEGIN(Redcraft)
|
||||
NAMESPACE_MODULE_BEGIN(Utility)
|
||||
|
||||
#if PLATFORM_COMPILER_GCC
|
||||
# pragma GCC diagnostic push
|
||||
# pragma GCC diagnostic ignored "-Wnon-template-friend"
|
||||
#endif
|
||||
|
||||
/** A concept specifies a type is an input iterator. It is input iterator, incrementable, and sentinel for itself. */
|
||||
template <typename I>
|
||||
concept CForwardIterator = CInputIterator<I> && CIncrementable<I> && CSentinelFor<I, I>;
|
||||
|
||||
/** This is an example of a forward iterator, indicate the traits that define a forward iterator. */
|
||||
template <CReferenceable T>
|
||||
struct IForwardIterator /* : IInputIterator<T>, IIncrementable, ISentinelFor<IForwardIterator> */
|
||||
{
|
||||
// ~Begin CInputIterator.
|
||||
|
||||
using ElementType = TRemoveCVRef<T>;
|
||||
|
||||
// ~End CInputIterator.
|
||||
|
||||
// ~Begin CIncrementable and CSentinelFor<IForwardIterator>.
|
||||
|
||||
IForwardIterator();
|
||||
IForwardIterator(const IForwardIterator&);
|
||||
IForwardIterator(IForwardIterator&&); // Also satisfies IInputIterator.
|
||||
IForwardIterator* operator=(const IForwardIterator&);
|
||||
IForwardIterator* operator=(IForwardIterator&&); // Also satisfies IInputIterator.
|
||||
|
||||
friend bool operator==(const IForwardIterator&, const IForwardIterator&);
|
||||
|
||||
// ~End CIncrementable and CSentinelFor<IForwardIterator>.
|
||||
|
||||
// ~Begin CInputIterator.
|
||||
|
||||
T operator*() const; // Optional satisfies CIndirectlyWritable.
|
||||
|
||||
IForwardIterator& operator++(); // Also satisfies CIncrementable.
|
||||
|
||||
IForwardIterator operator++(int); // Also satisfies CIncrementable.
|
||||
|
||||
// ~End CInputIterator.
|
||||
};
|
||||
|
||||
// Use IForwardIterator<int> represents a forward iterator.
|
||||
static_assert(CForwardIterator<IForwardIterator<int&>>);
|
||||
static_assert( COutputIterator<IForwardIterator<int&>, int>);
|
||||
|
||||
#if PLATFORM_COMPILER_GCC
|
||||
# pragma GCC diagnostic pop
|
||||
#endif
|
||||
|
||||
NAMESPACE_MODULE_END(Utility)
|
||||
NAMESPACE_MODULE_END(Redcraft)
|
||||
NAMESPACE_REDCRAFT_END
|
150
Redcraft.Utility/Source/Public/Iterator/InsertIterator.h
Normal file
150
Redcraft.Utility/Source/Public/Iterator/InsertIterator.h
Normal file
@ -0,0 +1,150 @@
|
||||
#pragma once
|
||||
|
||||
#include "CoreTypes.h"
|
||||
#include "Iterator/Utility.h"
|
||||
#include "TypeTraits/TypeTraits.h"
|
||||
#include "Templates/Noncopyable.h"
|
||||
#include "Templates/Utility.h"
|
||||
|
||||
NAMESPACE_REDCRAFT_BEGIN
|
||||
NAMESPACE_MODULE_BEGIN(Redcraft)
|
||||
NAMESPACE_MODULE_BEGIN(Utility)
|
||||
|
||||
NAMESPACE_PRIVATE_BEGIN
|
||||
|
||||
template <typename F> class TInsertProxy;
|
||||
template <typename F> class TPostIncrementProxy;
|
||||
template <typename F> class TInsertIterator;
|
||||
|
||||
template <typename F>
|
||||
class TInsertProxy final : private FSingleton
|
||||
{
|
||||
public:
|
||||
|
||||
# if DO_CHECK
|
||||
FORCEINLINE ~TInsertProxy() { checkf(bIsProduced, TEXT("Exception insert, Ensures that the value is assigned to the inserter.")); }
|
||||
# endif
|
||||
|
||||
template <typename T> requires (CInvocable<F, T>)
|
||||
FORCEINLINE constexpr void operator=(T&& InValue) const
|
||||
{
|
||||
checkf(!bIsProduced, TEXT("Exception insert, Ensure that no multiple values are assigned to the inserter."));
|
||||
Invoke(Iter.Storage, Forward<T>(InValue));
|
||||
check_code({ bIsProduced = true; });
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
TInsertIterator<F>& Iter;
|
||||
|
||||
# if DO_CHECK
|
||||
mutable bool bIsProduced;
|
||||
# endif
|
||||
|
||||
FORCEINLINE constexpr TInsertProxy(TInsertIterator<F>& InIter) : Iter(InIter) { check_code({ bIsProduced = false; }); }
|
||||
|
||||
template <typename> friend class TPostIncrementProxy;
|
||||
template <typename> friend class TInsertIterator;
|
||||
};
|
||||
|
||||
static_assert(CAssignableFrom<TInsertProxy<void(*)(int)>, int>);
|
||||
|
||||
template <typename F>
|
||||
class TPostIncrementProxy : private FSingleton
|
||||
{
|
||||
public:
|
||||
|
||||
# if DO_CHECK
|
||||
FORCEINLINE ~TPostIncrementProxy() { checkf(bIsProduced, TEXT("Exception insert, Ensures that the value is assigned to the inserter.")); }
|
||||
# endif
|
||||
|
||||
NODISCARD FORCEINLINE constexpr TInsertProxy<F> operator*() const
|
||||
{
|
||||
checkf(!bIsProduced, TEXT("Exception insert, Ensure that no multiple values are assigned to the inserter."));
|
||||
check_code({ bIsProduced = true; });
|
||||
return TInsertProxy(Iter);
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
TInsertIterator<F>& Iter;
|
||||
|
||||
# if DO_CHECK
|
||||
mutable bool bIsProduced;
|
||||
# endif
|
||||
|
||||
FORCEINLINE constexpr TPostIncrementProxy(TInsertIterator<F>& InIter) : Iter(InIter) { check_code({ bIsProduced = false; }); }
|
||||
|
||||
template <typename> friend class TInsertProxy;
|
||||
template <typename> friend class TInsertIterator;
|
||||
};
|
||||
|
||||
static_assert(CIndirectlyWritable<TPostIncrementProxy<void(*)(int)>, int>);
|
||||
|
||||
template <typename F>
|
||||
class TInsertIterator final : private FNoncopyable
|
||||
{
|
||||
public:
|
||||
|
||||
FORCEINLINE constexpr TInsertIterator() requires (CDefaultConstructible<F>) = default;
|
||||
|
||||
FORCEINLINE constexpr explicit TInsertIterator(F InInserter) : Storage(MoveTemp(InInserter)) { check_code({ bIsProduced = false; }); }
|
||||
|
||||
FORCEINLINE constexpr TInsertIterator(TInsertIterator&&) = default;
|
||||
FORCEINLINE constexpr TInsertIterator& operator=(TInsertIterator&&) = default;
|
||||
|
||||
NODISCARD FORCEINLINE constexpr TInsertProxy<F> operator*()
|
||||
{
|
||||
checkf(!bIsProduced, TEXT("Exception insert, Ensure that no multiple values are assigned to the inserter."));
|
||||
check_code({ bIsProduced = true; });
|
||||
return TInsertProxy<F>(*this);
|
||||
}
|
||||
|
||||
FORCEINLINE constexpr TInsertIterator& operator++() { check_code({ bIsProduced = false; }); return *this; }
|
||||
|
||||
FORCEINLINE constexpr TPostIncrementProxy<F> operator++(int)
|
||||
{
|
||||
checkf(!bIsProduced, TEXT("Exception insert, Ensure that no multiple values are assigned to the inserter."));
|
||||
return TPostIncrementProxy<F>(*this);
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
F Storage;
|
||||
|
||||
# if DO_CHECK
|
||||
bool bIsProduced;
|
||||
# endif
|
||||
|
||||
template <typename> friend class TInsertProxy;
|
||||
template <typename> friend class TPostIncrementProxy;
|
||||
};
|
||||
|
||||
static_assert(COutputIterator<TInsertIterator<void(*)(int)>, int>);
|
||||
|
||||
NAMESPACE_PRIVATE_END
|
||||
|
||||
/** Creates an iterator adapter inserted in the front of the container. */
|
||||
template <typename C>
|
||||
NODISCARD FORCEINLINE constexpr auto MakeFrontInserter(C& Container)
|
||||
{
|
||||
return NAMESPACE_PRIVATE::TInsertIterator([&Container]<typename T>(T&& A) { Container.PushFront(Forward<T>(A)); });
|
||||
}
|
||||
|
||||
/** Creates an iterator adapter inserted in the back of the container. */
|
||||
template <typename C>
|
||||
NODISCARD FORCEINLINE constexpr auto MakeBackInserter(C& Container)
|
||||
{
|
||||
return NAMESPACE_PRIVATE::TInsertIterator([&Container]<typename T>(T&& A) { Container.PushBack(Forward<T>(A)); });
|
||||
}
|
||||
|
||||
/** Creates an iterator adapter inserted in the container. */
|
||||
template <typename C>
|
||||
NODISCARD FORCEINLINE constexpr auto MakeInserter(C& Container, const typename C::ConstIterator& InIter)
|
||||
{
|
||||
return NAMESPACE_PRIVATE::TInsertIterator([&Container, Iter = InIter]<typename T>(T&& A) mutable { Iter = Container.Insert(Iter, Forward<T>(A)); });
|
||||
}
|
||||
|
||||
NAMESPACE_MODULE_END(Utility)
|
||||
NAMESPACE_MODULE_END(Redcraft)
|
||||
NAMESPACE_REDCRAFT_END
|
13
Redcraft.Utility/Source/Public/Iterator/Iterator.h
Normal file
13
Redcraft.Utility/Source/Public/Iterator/Iterator.h
Normal file
@ -0,0 +1,13 @@
|
||||
#pragma once
|
||||
|
||||
#include "CoreTypes.h"
|
||||
#include "Iterator/Utility.h"
|
||||
#include "Iterator/Sentinel.h"
|
||||
#include "Iterator/ForwardIterator.h"
|
||||
#include "Iterator/BidirectionalIterator.h"
|
||||
#include "Iterator/RandomAccessIterator.h"
|
||||
#include "Iterator/ContiguousIterator.h"
|
||||
#include "Iterator/ReverseIterator.h"
|
||||
#include "Iterator/MoveIterator.h"
|
||||
#include "Iterator/CountedIterator.h"
|
||||
#include "Iterator/InsertIterator.h"
|
156
Redcraft.Utility/Source/Public/Iterator/MoveIterator.h
Normal file
156
Redcraft.Utility/Source/Public/Iterator/MoveIterator.h
Normal file
@ -0,0 +1,156 @@
|
||||
#pragma once
|
||||
|
||||
#include "CoreTypes.h"
|
||||
#include "Iterator/Utility.h"
|
||||
#include "Iterator/Sentinel.h"
|
||||
#include "Iterator/ForwardIterator.h"
|
||||
#include "Iterator/BidirectionalIterator.h"
|
||||
#include "Iterator/RandomAccessIterator.h"
|
||||
#include "Iterator/ContiguousIterator.h"
|
||||
#include "Miscellaneous/Compare.h"
|
||||
#include "TypeTraits/TypeTraits.h"
|
||||
#include "Templates/Utility.h"
|
||||
#include "Memory/Address.h"
|
||||
|
||||
NAMESPACE_REDCRAFT_BEGIN
|
||||
NAMESPACE_MODULE_BEGIN(Redcraft)
|
||||
NAMESPACE_MODULE_BEGIN(Utility)
|
||||
|
||||
/**
|
||||
* An iterator adaptor which dereferences to a rvalue reference.
|
||||
* When based on at least an input iterator, the move iterator satisfies at least an input iterator
|
||||
* up to a random access iterator.
|
||||
*/
|
||||
template <CInputIterator I>
|
||||
class TMoveIterator final
|
||||
{
|
||||
public:
|
||||
|
||||
using IteratorType = I;
|
||||
|
||||
using ElementType = TIteratorElement<I>;
|
||||
|
||||
FORCEINLINE constexpr TMoveIterator() = default;
|
||||
FORCEINLINE constexpr TMoveIterator(const TMoveIterator&) = default;
|
||||
FORCEINLINE constexpr TMoveIterator(TMoveIterator&&) = default;
|
||||
FORCEINLINE constexpr TMoveIterator& operator=(const TMoveIterator&) = default;
|
||||
FORCEINLINE constexpr TMoveIterator& operator=(TMoveIterator&&) = default;
|
||||
FORCEINLINE constexpr ~TMoveIterator() = default;
|
||||
|
||||
FORCEINLINE constexpr explicit TMoveIterator(IteratorType InValue) : Current(MoveTemp(InValue)) { }
|
||||
|
||||
template <CInputIterator J> requires (!CSameAs<I, J> && CConstructibleFrom<I, const J&>)
|
||||
FORCEINLINE constexpr explicit (!CConvertibleTo<const J&, I>) TMoveIterator(const TReverseIterator<J>& InValue) : Current(InValue.GetBase()) { }
|
||||
|
||||
template <CInputIterator J> requires (!CSameAs<I, J> && CConvertibleTo<const J&, I> && CAssignableFrom<I&, const J&>)
|
||||
FORCEINLINE constexpr TMoveIterator& operator=(const TMoveIterator<J>& InValue) { Current = InValue.GetBase(); return *this; }
|
||||
|
||||
template <CInputIterator J> requires (CSentinelFor<J, I>)
|
||||
NODISCARD friend FORCEINLINE constexpr bool operator==(const TMoveIterator& LHS, const TMoveIterator<J>& RHS) { return LHS.GetBase() == RHS.GetBase(); }
|
||||
|
||||
template <CInputIterator J> requires (CThreeWayComparable<I, J>)
|
||||
NODISCARD friend FORCEINLINE constexpr TCompareThreeWayResult<I, J> operator<=>(const TMoveIterator& LHS, const TMoveIterator<J>& RHS) { return RHS.GetBase() <=> LHS.GetBase(); }
|
||||
|
||||
NODISCARD FORCEINLINE constexpr TIteratorRValueReference<I> operator*() const { return MoveTemp(*GetBase()); }
|
||||
|
||||
NODISCARD FORCEINLINE constexpr TIteratorRValueReference<I> operator[](ptrdiff Index) const requires (CRandomAccessIterator<I>) { return MoveTemp(GetBase()[Index]); }
|
||||
|
||||
FORCEINLINE constexpr TMoveIterator& operator++() { ++Current; return *this; }
|
||||
FORCEINLINE constexpr TMoveIterator& operator--() requires (CBidirectionalIterator<I>) { --Current; return *this; }
|
||||
|
||||
FORCEINLINE constexpr void operator++(int) { Current++; }
|
||||
FORCEINLINE constexpr TMoveIterator operator++(int) requires (CForwardIterator<I>) { return TMoveIterator(Current++); }
|
||||
FORCEINLINE constexpr TMoveIterator operator--(int) requires (CBidirectionalIterator<I>) { return TMoveIterator(Current--); }
|
||||
|
||||
FORCEINLINE constexpr TMoveIterator& operator+=(ptrdiff Offset) requires (CRandomAccessIterator<I>) { Current += Offset; return *this; }
|
||||
FORCEINLINE constexpr TMoveIterator& operator-=(ptrdiff Offset) requires (CRandomAccessIterator<I>) { Current -= Offset; return *this; }
|
||||
|
||||
NODISCARD FORCEINLINE constexpr TMoveIterator operator+(ptrdiff Offset) const requires (CRandomAccessIterator<I>) { TMoveIterator Temp = *this; Temp += Offset; return Temp; }
|
||||
NODISCARD FORCEINLINE constexpr TMoveIterator operator-(ptrdiff Offset) const requires (CRandomAccessIterator<I>) { TMoveIterator Temp = *this; Temp -= Offset; return Temp; }
|
||||
|
||||
NODISCARD friend FORCEINLINE constexpr TMoveIterator operator+(ptrdiff Offset, const TMoveIterator& Iter) requires (CRandomAccessIterator<I>) { return Iter + Offset; }
|
||||
|
||||
NODISCARD friend FORCEINLINE constexpr ptrdiff operator-(const TMoveIterator& LHS, const TMoveIterator& RHS) requires (CRandomAccessIterator<I>) { return LHS.GetBase() - RHS.GetBase(); }
|
||||
|
||||
NODISCARD FORCEINLINE constexpr const IteratorType& GetBase() const& { return Current; }
|
||||
NODISCARD FORCEINLINE constexpr IteratorType GetBase() && { return MoveTemp(Current); }
|
||||
|
||||
private:
|
||||
|
||||
IteratorType Current;
|
||||
|
||||
};
|
||||
|
||||
template <typename I, typename J> requires (!CSizedSentinelFor<I, J>)
|
||||
inline constexpr bool bDisableSizedSentinelFor<TMoveIterator<I>, TMoveIterator<J>> = true;
|
||||
|
||||
static_assert( CInputIterator<TMoveIterator< IInputIterator<int&>>>);
|
||||
static_assert( CForwardIterator<TMoveIterator< IForwardIterator<int&>>>);
|
||||
static_assert(CBidirectionalIterator<TMoveIterator<IBidirectionalIterator<int&>>>);
|
||||
static_assert( CRandomAccessIterator<TMoveIterator< IRandomAccessIterator<int&>>>);
|
||||
static_assert( CRandomAccessIterator<TMoveIterator< IContiguousIterator<int&>>>);
|
||||
|
||||
/**
|
||||
* A sentinel adaptor for use with TMoveIterator.
|
||||
* Whether based on un-sized or sized sentinel, the move sentinel satisfies the corresponding concept.
|
||||
*/
|
||||
template <CSemiregular S>
|
||||
class TMoveSentinel
|
||||
{
|
||||
public:
|
||||
|
||||
using SentinelType = S;
|
||||
|
||||
FORCEINLINE constexpr TMoveSentinel() = default;
|
||||
FORCEINLINE constexpr TMoveSentinel(const TMoveSentinel&) = default;
|
||||
FORCEINLINE constexpr TMoveSentinel(TMoveSentinel&&) = default;
|
||||
FORCEINLINE constexpr TMoveSentinel& operator=(const TMoveSentinel&) = default;
|
||||
FORCEINLINE constexpr TMoveSentinel& operator=(TMoveSentinel&&) = default;
|
||||
FORCEINLINE constexpr ~TMoveSentinel() = default;
|
||||
|
||||
FORCEINLINE constexpr explicit TMoveSentinel(SentinelType InValue) : Last(InValue) { }
|
||||
|
||||
template <CSemiregular T> requires (!CSameAs<S, T> && CConstructibleFrom<S, const T&>)
|
||||
FORCEINLINE constexpr explicit (!CConvertibleTo<const T&, S>) TMoveSentinel(const TMoveSentinel<T>& InValue) : Last(InValue.Last) { }
|
||||
|
||||
template <CSemiregular T> requires (!CSameAs<S, T> && CConvertibleTo<const T&, S> && CAssignableFrom<S&, const T&>)
|
||||
FORCEINLINE constexpr TMoveSentinel& operator=(const TMoveSentinel<T>& InValue) { Last = InValue.GetBase(); return *this; }
|
||||
|
||||
template <CInputIterator I> requires (CSentinelFor<S, I>)
|
||||
NODISCARD FORCEINLINE constexpr bool operator==(const TMoveIterator<I>& InValue) const& { return GetBase() == InValue.GetBase(); }
|
||||
|
||||
template <CInputIterator I> requires (CSizedSentinelFor<S, I>)
|
||||
NODISCARD friend FORCEINLINE constexpr ptrdiff operator-(const TMoveSentinel& Sentinel, const TMoveIterator<I>& Iter) { return Sentinel.GetBase() - Iter.GetBase(); }
|
||||
|
||||
template <CInputIterator I> requires (CSizedSentinelFor<S, I>)
|
||||
NODISCARD friend FORCEINLINE constexpr ptrdiff operator-(const TMoveIterator<I>& Iter, const TMoveSentinel& Sentinel) { return Iter.GetBase() - Sentinel.GetBase(); }
|
||||
|
||||
NODISCARD FORCEINLINE constexpr const SentinelType& GetBase() const& { return Last; }
|
||||
NODISCARD FORCEINLINE constexpr SentinelType GetBase() && { return MoveTemp(Last); }
|
||||
|
||||
private:
|
||||
|
||||
SentinelType Last;
|
||||
|
||||
};
|
||||
|
||||
static_assert( CSentinelFor<TMoveSentinel< ISentinelFor<IInputIterator<int>>>, TMoveIterator<IInputIterator<int>>>);
|
||||
static_assert(CSizedSentinelFor<TMoveSentinel<ISizedSentinelFor<IInputIterator<int>>>, TMoveIterator<IInputIterator<int>>>);
|
||||
|
||||
/** Creates a TMoveIterator of type inferred from the argument. */
|
||||
template <typename I> requires (CInputIterator<TDecay<I>> && CConstructibleFrom<TDecay<I>, I>)
|
||||
NODISCARD FORCEINLINE constexpr auto MakeMoveIterator(I&& Iter)
|
||||
{
|
||||
return TMoveIterator<TDecay<I>>(Forward<I>(Iter));
|
||||
}
|
||||
|
||||
/** Creates a TMoveSentinel of type inferred from the argument. */
|
||||
template <typename I> requires (CSemiregular<TDecay<I>> && CConstructibleFrom<TDecay<I>, I>)
|
||||
NODISCARD FORCEINLINE constexpr auto MakeMoveSentinel(I&& Iter)
|
||||
{
|
||||
return TMoveSentinel<TDecay<I>>(Forward<I>(Iter));
|
||||
}
|
||||
|
||||
NAMESPACE_MODULE_END(Utility)
|
||||
NAMESPACE_MODULE_END(Redcraft)
|
||||
NAMESPACE_REDCRAFT_END
|
@ -0,0 +1,93 @@
|
||||
#pragma once
|
||||
|
||||
#include "CoreTypes.h"
|
||||
#include "Iterator/Utility.h"
|
||||
#include "Iterator/Sentinel.h"
|
||||
#include "Iterator/BidirectionalIterator.h"
|
||||
#include "Miscellaneous/Compare.h"
|
||||
#include "TypeTraits/TypeTraits.h"
|
||||
|
||||
NAMESPACE_REDCRAFT_BEGIN
|
||||
NAMESPACE_MODULE_BEGIN(Redcraft)
|
||||
NAMESPACE_MODULE_BEGIN(Utility)
|
||||
|
||||
#if PLATFORM_COMPILER_GCC
|
||||
# pragma GCC diagnostic push
|
||||
# pragma GCC diagnostic ignored "-Wnon-template-friend"
|
||||
#endif
|
||||
|
||||
/**
|
||||
* A concept specifies a type is a random access iterator.
|
||||
* Add the three-way comparison, addition, subtraction and subscript operators to the bidirectional iterator.
|
||||
*/
|
||||
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<TIteratorReference<I>>;
|
||||
};
|
||||
|
||||
/** This is an example of a random access iterator, indicate the traits that define a random access iterator. */
|
||||
template <CReferenceable T>
|
||||
struct IRandomAccessIterator /* : IBidirectionalIterator<T>, ISizedSentinelFor<IRandomAccessIterator> */
|
||||
{
|
||||
// ~Begin CBidirectionalIterator.
|
||||
|
||||
using ElementType = TRemoveCVRef<T>;
|
||||
|
||||
// ~End CBidirectionalIterator.
|
||||
|
||||
// ~Begin CBidirectionalIterator and CSizedSentinelFor<IRandomAccessIterator>.
|
||||
|
||||
IRandomAccessIterator();
|
||||
IRandomAccessIterator(const IRandomAccessIterator&);
|
||||
IRandomAccessIterator(IRandomAccessIterator&&);
|
||||
IRandomAccessIterator* operator=(const IRandomAccessIterator&);
|
||||
IRandomAccessIterator* operator=(IRandomAccessIterator&&);
|
||||
|
||||
friend bool operator==(const IRandomAccessIterator&, const IRandomAccessIterator&);
|
||||
|
||||
// ~End CBidirectionalIterator and CSizedSentinelFor<IRandomAccessIterator>.
|
||||
|
||||
friend strong_ordering operator<=>(const IRandomAccessIterator&, const IRandomAccessIterator&);
|
||||
|
||||
T operator*() const; // Also satisfies CBidirectionalIterator.
|
||||
|
||||
T operator[](ptrdiff) const;
|
||||
|
||||
// ~Begin CBidirectionalIterator.
|
||||
|
||||
IRandomAccessIterator& operator++();
|
||||
IRandomAccessIterator& operator--();
|
||||
|
||||
IRandomAccessIterator operator++(int);
|
||||
IRandomAccessIterator operator--(int);
|
||||
|
||||
// ~End CBidirectionalIterator.
|
||||
|
||||
IRandomAccessIterator& operator+=(ptrdiff);
|
||||
IRandomAccessIterator& operator-=(ptrdiff);
|
||||
|
||||
IRandomAccessIterator operator+(ptrdiff) const;
|
||||
IRandomAccessIterator operator-(ptrdiff) const;
|
||||
|
||||
friend IRandomAccessIterator operator+(ptrdiff, const IRandomAccessIterator&);
|
||||
|
||||
friend ptrdiff operator-(const IRandomAccessIterator&, const IRandomAccessIterator&); // Also satisfies CSizedSentinelFor<IRandomAccessIterator>.
|
||||
};
|
||||
|
||||
// Use IRandomAccessIterator<int> represents a random access iterator
|
||||
static_assert(CRandomAccessIterator<IRandomAccessIterator<int&>>);
|
||||
static_assert( COutputIterator<IRandomAccessIterator<int&>, int>);
|
||||
|
||||
#if PLATFORM_COMPILER_GCC
|
||||
# pragma GCC diagnostic pop
|
||||
#endif
|
||||
|
||||
NAMESPACE_MODULE_END(Utility)
|
||||
NAMESPACE_MODULE_END(Redcraft)
|
||||
NAMESPACE_REDCRAFT_END
|
102
Redcraft.Utility/Source/Public/Iterator/ReverseIterator.h
Normal file
102
Redcraft.Utility/Source/Public/Iterator/ReverseIterator.h
Normal file
@ -0,0 +1,102 @@
|
||||
#pragma once
|
||||
|
||||
#include "CoreTypes.h"
|
||||
#include "Iterator/Utility.h"
|
||||
#include "Iterator/Sentinel.h"
|
||||
#include "Iterator/BidirectionalIterator.h"
|
||||
#include "Iterator/RandomAccessIterator.h"
|
||||
#include "Iterator/ContiguousIterator.h"
|
||||
#include "Miscellaneous/Compare.h"
|
||||
#include "TypeTraits/TypeTraits.h"
|
||||
#include "Templates/Utility.h"
|
||||
#include "Memory/Address.h"
|
||||
|
||||
NAMESPACE_REDCRAFT_BEGIN
|
||||
NAMESPACE_MODULE_BEGIN(Redcraft)
|
||||
NAMESPACE_MODULE_BEGIN(Utility)
|
||||
|
||||
/**
|
||||
* An iterator adaptor for reverse-order traversal.
|
||||
* When based on at least a bidirectional iterator, the reverse iterator satisfies at least a bidirectional iterator
|
||||
* up to a random access iterator. When based on an output iterator, the reverse iterator satisfies an output iterator.
|
||||
*/
|
||||
template <CBidirectionalIterator I>
|
||||
class TReverseIterator final
|
||||
{
|
||||
public:
|
||||
|
||||
using IteratorType = I;
|
||||
|
||||
using ElementType = TIteratorElement<I>;
|
||||
|
||||
FORCEINLINE constexpr TReverseIterator() = default;
|
||||
FORCEINLINE constexpr TReverseIterator(const TReverseIterator&) = default;
|
||||
FORCEINLINE constexpr TReverseIterator(TReverseIterator&&) = default;
|
||||
FORCEINLINE constexpr TReverseIterator& operator=(const TReverseIterator&) = default;
|
||||
FORCEINLINE constexpr TReverseIterator& operator=(TReverseIterator&&) = default;
|
||||
FORCEINLINE constexpr ~TReverseIterator() = default;
|
||||
|
||||
FORCEINLINE constexpr explicit TReverseIterator(IteratorType InValue) : Current(InValue) { }
|
||||
|
||||
template <CBidirectionalIterator J> requires (!CSameAs<I, J> && CConstructibleFrom<I, const J&>)
|
||||
FORCEINLINE constexpr explicit (!CConvertibleTo<const J&, I>) TReverseIterator(const TReverseIterator<J>& InValue) : Current(InValue.GetBase()) { }
|
||||
|
||||
template <CBidirectionalIterator J> requires (!CSameAs<I, J> && CConvertibleTo<const J&, I> && CAssignableFrom<I&, const J&>)
|
||||
FORCEINLINE constexpr TReverseIterator& operator=(const TReverseIterator<J>& InValue) { Current = InValue.GetBase(); return *this; }
|
||||
|
||||
template <CBidirectionalIterator J> requires (CSentinelFor<J, I>)
|
||||
NODISCARD friend FORCEINLINE constexpr bool operator==(const TReverseIterator& LHS, const TReverseIterator<J>& RHS) { return LHS.GetBase() == RHS.GetBase(); }
|
||||
|
||||
template <CBidirectionalIterator J> requires (CThreeWayComparable<I, J>)
|
||||
NODISCARD friend FORCEINLINE constexpr TCompareThreeWayResult<I, J> operator<=>(const TReverseIterator& LHS, const TReverseIterator<J>& RHS) { return RHS.GetBase() <=> LHS.GetBase(); }
|
||||
|
||||
NODISCARD FORCEINLINE constexpr TIteratorReference<I> operator*() const { IteratorType Temp = GetBase(); return *--Temp; }
|
||||
|
||||
NODISCARD FORCEINLINE constexpr auto operator->() const requires (requires(const I Iter) { { ToAddress(Iter) } -> CSameAs<TIteratorPointer<I>>; }) { IteratorType Temp = GetBase(); return ToAddress(--Temp); }
|
||||
|
||||
NODISCARD FORCEINLINE constexpr TIteratorReference<I> operator[](ptrdiff Index) const requires (CRandomAccessIterator<I>) { return GetBase()[-Index - 1]; }
|
||||
|
||||
FORCEINLINE constexpr TReverseIterator& operator++() { --Current; return *this; }
|
||||
FORCEINLINE constexpr TReverseIterator& operator--() { ++Current; return *this; }
|
||||
|
||||
FORCEINLINE constexpr TReverseIterator operator++(int) { TReverseIterator Temp = *this; --Current; return Temp; }
|
||||
FORCEINLINE constexpr TReverseIterator operator--(int) { TReverseIterator Temp = *this; ++Current; return Temp; }
|
||||
|
||||
FORCEINLINE constexpr TReverseIterator& operator+=(ptrdiff Offset) requires (CRandomAccessIterator<I>) { Current -= Offset; return *this; }
|
||||
FORCEINLINE constexpr TReverseIterator& operator-=(ptrdiff Offset) requires (CRandomAccessIterator<I>) { Current += Offset; return *this; }
|
||||
|
||||
NODISCARD FORCEINLINE constexpr TReverseIterator operator+(ptrdiff Offset) const requires (CRandomAccessIterator<I>) { TReverseIterator Temp = *this; Temp -= Offset; return Temp; }
|
||||
NODISCARD FORCEINLINE constexpr TReverseIterator operator-(ptrdiff Offset) const requires (CRandomAccessIterator<I>) { TReverseIterator Temp = *this; Temp += Offset; return Temp; }
|
||||
|
||||
NODISCARD friend FORCEINLINE constexpr TReverseIterator operator+(ptrdiff Offset, const TReverseIterator& Iter) requires (CRandomAccessIterator<I>) { return Iter + Offset; }
|
||||
|
||||
NODISCARD friend FORCEINLINE constexpr ptrdiff operator-(const TReverseIterator& LHS, const TReverseIterator& RHS) requires (CRandomAccessIterator<I>) { return RHS.GetBase() - LHS.GetBase(); }
|
||||
|
||||
NODISCARD FORCEINLINE constexpr const IteratorType& GetBase() const& { return Current; }
|
||||
NODISCARD FORCEINLINE constexpr IteratorType GetBase() && { return MoveTemp(Current); }
|
||||
|
||||
private:
|
||||
|
||||
IteratorType Current;
|
||||
|
||||
};
|
||||
|
||||
template <typename I, typename J> requires (!CSizedSentinelFor<I, J>)
|
||||
inline constexpr bool bDisableSizedSentinelFor<TReverseIterator<I>, TReverseIterator<J>> = true;
|
||||
|
||||
static_assert(CBidirectionalIterator<TReverseIterator<IBidirectionalIterator<int&>>>);
|
||||
static_assert( CRandomAccessIterator<TReverseIterator< IRandomAccessIterator<int&>>>);
|
||||
static_assert( CRandomAccessIterator<TReverseIterator< IContiguousIterator<int&>>>);
|
||||
|
||||
static_assert(COutputIterator<TReverseIterator<IBidirectionalIterator<int&>>, int>);
|
||||
|
||||
/** Creates a TReverseIterator of type inferred from the argument. */
|
||||
template <typename I> requires (CBidirectionalIterator<TDecay<I>> && CConstructibleFrom<TDecay<I>, I>)
|
||||
NODISCARD FORCEINLINE constexpr auto MakeReverseIterator(I&& Iter)
|
||||
{
|
||||
return TReverseIterator<TDecay<I>>(Forward<I>(Iter));
|
||||
}
|
||||
|
||||
NAMESPACE_MODULE_END(Utility)
|
||||
NAMESPACE_MODULE_END(Redcraft)
|
||||
NAMESPACE_REDCRAFT_END
|
115
Redcraft.Utility/Source/Public/Iterator/Sentinel.h
Normal file
115
Redcraft.Utility/Source/Public/Iterator/Sentinel.h
Normal file
@ -0,0 +1,115 @@
|
||||
#pragma once
|
||||
|
||||
#include "CoreTypes.h"
|
||||
#include "Iterator/Utility.h"
|
||||
#include "TypeTraits/TypeTraits.h"
|
||||
|
||||
NAMESPACE_REDCRAFT_BEGIN
|
||||
NAMESPACE_MODULE_BEGIN(Redcraft)
|
||||
NAMESPACE_MODULE_BEGIN(Utility)
|
||||
|
||||
#if PLATFORM_COMPILER_GCC
|
||||
# pragma GCC diagnostic push
|
||||
# pragma GCC diagnostic ignored "-Wnon-template-friend"
|
||||
#endif
|
||||
|
||||
/**
|
||||
* A concept specifies a type is a sentinel for an iterator and expression 'Iter == Sentinel' is valid.
|
||||
* In addition, the type must be default constructible and copyable.
|
||||
*/
|
||||
template <typename S, typename I>
|
||||
concept CSentinelFor = CSemiregular<S> && CInputOrOutputIterator<I> && CWeaklyEqualityComparable<S, I>;
|
||||
|
||||
/** This is an example of a sentinel for an iterator, indicate the traits that define a sentinel for an iterator. */
|
||||
template <CInputOrOutputIterator I>
|
||||
struct ISentinelFor
|
||||
{
|
||||
ISentinelFor();
|
||||
ISentinelFor(const ISentinelFor&);
|
||||
ISentinelFor* operator=(const ISentinelFor&);
|
||||
|
||||
bool operator==(const I&) const&;
|
||||
};
|
||||
|
||||
// Use ISentinelFor represents a sentinel for an iterator.
|
||||
static_assert(CSentinelFor<ISentinelFor<IInputOrOutputIterator<int>>, IInputOrOutputIterator<int>>);
|
||||
|
||||
// The CSentinelFor requires this code is valid.
|
||||
static_assert(
|
||||
requires(ISentinelFor<IInputOrOutputIterator<int>> Sentinel, IInputOrOutputIterator<int> Iter)
|
||||
{
|
||||
{ Iter == Sentinel } -> CBooleanTestable;
|
||||
{ Sentinel == Iter } -> CBooleanTestable;
|
||||
}
|
||||
);
|
||||
|
||||
/** Disable the CSizedSentinelFor concept for specific types. */
|
||||
template <typename S, typename I>
|
||||
inline constexpr bool bDisableSizedSentinelFor = false;
|
||||
|
||||
/**
|
||||
* A concept specifies a type is a sized sentinel for an iterator and expressions 'Sentinel - Iter' and 'Iter - Sentinel' are valid,
|
||||
* and the 'Sentinel - Iter' is equal to negative 'Iter - Sentinel'.
|
||||
* In addition, the type must be default constructible and copyable.
|
||||
*/
|
||||
template <typename S, typename I>
|
||||
concept CSizedSentinelFor = CSentinelFor<S, I>
|
||||
&& !bDisableSizedSentinelFor<TRemoveCVRef<S>, TRemoveCVRef<I>>
|
||||
&& requires(const I& Iter, const S& Sentinel)
|
||||
{
|
||||
{ Sentinel - Iter } -> CSameAs<ptrdiff>;
|
||||
{ Iter - Sentinel } -> CSameAs<ptrdiff>;
|
||||
};
|
||||
|
||||
/** This is an example of a sized sentinel for an iterator, indicate the traits that define a sized sentinel for an iterator. */
|
||||
template <CInputOrOutputIterator I>
|
||||
struct ISizedSentinelFor /* : ISentinelFor<I> */
|
||||
{
|
||||
ISizedSentinelFor(); // Also satisfies ISentinelFor<I>.
|
||||
ISizedSentinelFor(const ISizedSentinelFor&);
|
||||
ISizedSentinelFor(ISizedSentinelFor&&); // Also satisfies ISentinelFor<I>.
|
||||
ISizedSentinelFor& operator=(const ISizedSentinelFor&);
|
||||
ISizedSentinelFor& operator=(ISizedSentinelFor&&); // Also satisfies ISentinelFor<I>.
|
||||
|
||||
bool operator==(const I&) const&; // Also satisfies ISentinelFor<I>.
|
||||
|
||||
/** Subtraction operator. The 'Sentinel - Iter' is equal to negative 'Iter - Sentinel'. */
|
||||
friend ptrdiff operator-(const I&, const ISizedSentinelFor&);
|
||||
friend ptrdiff operator-(const ISizedSentinelFor&, const I&);
|
||||
};
|
||||
|
||||
// Use ISizedSentinelFor represents a sized sentinel for an iterator.
|
||||
static_assert(CSizedSentinelFor<ISizedSentinelFor<IInputOrOutputIterator<int>>, IInputOrOutputIterator<int>>);
|
||||
|
||||
// The CSentinelFor requires this code is valid.
|
||||
static_assert(
|
||||
requires(ISizedSentinelFor<IInputOrOutputIterator<int>> Sentinel, IInputOrOutputIterator<int> Iter)
|
||||
{
|
||||
{ Iter == Sentinel } -> CBooleanTestable;
|
||||
{ Sentinel == Iter } -> CBooleanTestable;
|
||||
{ Iter - Sentinel } -> CSameAs<ptrdiff>;
|
||||
{ Sentinel - Iter } -> CSameAs<ptrdiff>;
|
||||
}
|
||||
);
|
||||
|
||||
struct FDefaultSentinel { explicit FDefaultSentinel() = default; };
|
||||
|
||||
inline constexpr FDefaultSentinel DefaultSentinel{ };
|
||||
|
||||
struct FUnreachableSentinel
|
||||
{
|
||||
explicit FUnreachableSentinel() = default;
|
||||
|
||||
template <CWeaklyIncrementable I>
|
||||
NODISCARD FORCEINLINE constexpr bool operator==(const I&) const& { return false; }
|
||||
};
|
||||
|
||||
inline constexpr FUnreachableSentinel UnreachableSentinel{ };
|
||||
|
||||
#if PLATFORM_COMPILER_GCC
|
||||
# pragma GCC diagnostic pop
|
||||
#endif
|
||||
|
||||
NAMESPACE_MODULE_END(Utility)
|
||||
NAMESPACE_MODULE_END(Redcraft)
|
||||
NAMESPACE_REDCRAFT_END
|
315
Redcraft.Utility/Source/Public/Iterator/Utility.h
Normal file
315
Redcraft.Utility/Source/Public/Iterator/Utility.h
Normal file
@ -0,0 +1,315 @@
|
||||
#pragma once
|
||||
|
||||
#include "CoreTypes.h"
|
||||
#include "Templates/Utility.h"
|
||||
#include "TypeTraits/TypeTraits.h"
|
||||
|
||||
NAMESPACE_REDCRAFT_BEGIN
|
||||
NAMESPACE_MODULE_BEGIN(Redcraft)
|
||||
NAMESPACE_MODULE_BEGIN(Utility)
|
||||
|
||||
NAMESPACE_PRIVATE_BEGIN
|
||||
|
||||
template <typename T> using TWithReference = T&;
|
||||
|
||||
template <typename I> struct TIteratorElementImpl { };
|
||||
template <typename T> struct TIteratorElementImpl<T*> { using Type = TRemoveCV<T>; };
|
||||
|
||||
template <typename I> requires (requires { typename I::ElementType; })
|
||||
struct TIteratorElementImpl<I> { using Type = typename I::ElementType; };
|
||||
|
||||
template <typename I> struct TIteratorPointerImpl { };
|
||||
template <typename T> struct TIteratorPointerImpl<T*> { using Type = T*; };
|
||||
|
||||
template <typename I> requires (requires(I& Iter) { { Iter.operator->() } -> CPointer; })
|
||||
struct TIteratorPointerImpl<I> { using Type = decltype(DeclVal<I&>().operator->()); };
|
||||
|
||||
NAMESPACE_PRIVATE_END
|
||||
|
||||
template <typename T>
|
||||
concept CReferenceable = requires { typename NAMESPACE_PRIVATE::TWithReference<T>; };
|
||||
|
||||
template <typename T>
|
||||
concept CDereferenceable = requires(T& A) { { *A } -> CReferenceable; };
|
||||
|
||||
template <typename I>
|
||||
using TIteratorElement = typename NAMESPACE_PRIVATE::TIteratorElementImpl<TRemoveCVRef<I>>::Type;
|
||||
|
||||
template <typename I>
|
||||
using TIteratorPointer = typename NAMESPACE_PRIVATE::TIteratorPointerImpl<TRemoveCVRef<I>>::Type;
|
||||
|
||||
template <CReferenceable I>
|
||||
using TIteratorReference = decltype(*DeclVal<I&>());
|
||||
|
||||
template <CReferenceable I> requires (requires(I& Iter) { { MoveTemp(*Iter) } -> CReferenceable; })
|
||||
using TIteratorRValueReference = decltype(MoveTemp(*DeclVal<I&>()));
|
||||
|
||||
NAMESPACE_PRIVATE_BEGIN
|
||||
|
||||
template <typename I>
|
||||
concept CIndirectlyReadable =
|
||||
requires(const I Iter)
|
||||
{
|
||||
typename TIteratorElement<I>;
|
||||
typename TIteratorReference<I>;
|
||||
typename TIteratorRValueReference<I>;
|
||||
{ *Iter } -> CSameAs<TIteratorReference<I>>;
|
||||
{ MoveTemp(*Iter) } -> CSameAs<TIteratorRValueReference<I>>;
|
||||
}
|
||||
&& CSameAs<TIteratorElement<I>, TRemoveCVRef<TIteratorElement<I>>>
|
||||
&& CCommonReference<TIteratorReference<I>&&, TIteratorElement<I>&>
|
||||
&& CCommonReference<TIteratorReference<I>&&, TIteratorRValueReference<I>&&>
|
||||
&& CCommonReference<TIteratorRValueReference<I>&&, const TIteratorElement<I>&>;
|
||||
|
||||
NAMESPACE_PRIVATE_END
|
||||
|
||||
/** A concept specifies a type is indirectly readable by expression '*Iter'. */
|
||||
template <typename I>
|
||||
concept CIndirectlyReadable = NAMESPACE_PRIVATE::CIndirectlyReadable<TRemoveCVRef<I>>;
|
||||
|
||||
/** This is an example of an indirectly readable type, indicate the traits that define an indirectly readable type. */
|
||||
template <CReferenceable T>
|
||||
struct IIndirectlyReadable
|
||||
{
|
||||
/**
|
||||
* The element type of the indirectly readable type.
|
||||
* It must be a non-const, non-volatile and non-reference type and can be referenced, i.e. not a void type.
|
||||
*/
|
||||
using ElementType = TRemoveCVRef<T>;
|
||||
|
||||
/**
|
||||
* Indirectly read the element from the indirectly readable type.
|
||||
* The return type may not be const ElementType&, this concept only requires that the return type
|
||||
* and ElementType has some relationship, such as copy constructible to ElementType if the type is copyable.
|
||||
* This means that returning a proxy class castable to ElementType is also valid.
|
||||
* If this is an iterator adaptor, use decltype(auto) to forward the return value.
|
||||
*/
|
||||
T operator*() const;
|
||||
};
|
||||
|
||||
// Use IIndirectlyReadable<int> represents an indirectly readable type and int is the regular element type.
|
||||
static_assert(CIndirectlyReadable<IIndirectlyReadable<int>> && CRegular<int>);
|
||||
|
||||
// The CIndirectlyReadable requires this code is valid.
|
||||
static_assert(
|
||||
requires(IIndirectlyReadable<int> Iter, int& A)
|
||||
{
|
||||
A = *Iter;
|
||||
}
|
||||
);
|
||||
|
||||
/** A concept specifies a type is indirectly writable by expression '*Iter = A'. */
|
||||
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 TIteratorReference<I>&&>(*Iter) = Forward<T>(A);
|
||||
const_cast<const TIteratorReference<I>&&>(*Forward<I>(Iter)) = Forward<T>(A);
|
||||
};
|
||||
|
||||
/** This is an example of an indirectly writable type, indicate the traits that define an indirectly writable type. */
|
||||
template <CReferenceable T>
|
||||
struct IIndirectlyWritable
|
||||
{
|
||||
/**
|
||||
* Indirectly write the element from the indirectly writable type.
|
||||
* The return type may not be T&, this concept only requires that the return type and T has some relationship,
|
||||
* such as can be assigned from T& if the type is copyable or T&& if the type is movable.
|
||||
* This means that returning a proxy class can be assigned from T is also valid.
|
||||
* If this is also an indirectly readable type, the equivalent value is read after writing.
|
||||
* If this is an iterator adaptor, use decltype(auto) to forward the return value.
|
||||
*/
|
||||
T operator*() const;
|
||||
};
|
||||
|
||||
// Use IIndirectlyWritable<int> represents an indirectly writable type and int is the regular element type.
|
||||
static_assert(CIndirectlyWritable<IIndirectlyWritable<int&>, int> && CRegular<int>);
|
||||
|
||||
// The CIndirectlyWritable requires this code is valid.
|
||||
static_assert(
|
||||
requires(IIndirectlyWritable<int&> Iter, int& A)
|
||||
{
|
||||
*Iter = A;
|
||||
}
|
||||
);
|
||||
|
||||
/** A concept specifies a type is incrementable by expression '++Iter' and the type must be movable. */
|
||||
template <typename I>
|
||||
concept CWeaklyIncrementable = CMovable<I>
|
||||
&& requires(I Iter) { { ++Iter } -> CSameAs<I&>; Iter++; };
|
||||
|
||||
/** This is an example of a weakly incrementable type, indicate the traits that define a weakly incrementable type. */
|
||||
struct IWeaklyIncrementable
|
||||
{
|
||||
IWeaklyIncrementable(IWeaklyIncrementable&&);
|
||||
IWeaklyIncrementable* operator=(IWeaklyIncrementable&&);
|
||||
|
||||
IWeaklyIncrementable& operator++();
|
||||
|
||||
/** Post-increment operator. Specify, the concept not requires the return type is any specific type, so the return type can be void. */
|
||||
void operator++(int);
|
||||
};
|
||||
|
||||
// Use IWeaklyIncrementable represents a weakly incrementable type.
|
||||
static_assert(CWeaklyIncrementable<IWeaklyIncrementable>);
|
||||
|
||||
/**
|
||||
* A concept specifies a type is incrementable by expression 'Iter++' and the expression returns the original value.
|
||||
* In addition, the type must be default constructible, copyable and weakly equality comparable.
|
||||
*/
|
||||
template <typename I>
|
||||
concept CIncrementable = CRegular<I> && CWeaklyIncrementable<I>
|
||||
&& requires(I Iter) { { Iter++ } -> CSameAs<I>; };
|
||||
|
||||
/**
|
||||
* This is an example of an incrementable type, indicate the traits that define an incrementable type.
|
||||
* The copy object of this type produced by copy constructor, copy assignment or post-increment
|
||||
* should produce the same effect as the original object when incrementing.
|
||||
*/
|
||||
struct IIncrementable /* : IWeaklyIncrementable */
|
||||
{
|
||||
IIncrementable();
|
||||
IIncrementable(const IIncrementable&);
|
||||
IIncrementable(IIncrementable&&); // Also satisfies IWeaklyIncrementable.
|
||||
IIncrementable* operator=(const IIncrementable&);
|
||||
IIncrementable* operator=(IIncrementable&&); // Also satisfies IWeaklyIncrementable.
|
||||
|
||||
friend bool operator==(const IIncrementable&, const IIncrementable&);
|
||||
|
||||
IIncrementable& operator++(); // Also satisfies IWeaklyIncrementable.
|
||||
|
||||
/** Post-increment operator. Specify, the concept requires the return value is the original value before incrementing. */
|
||||
IIncrementable operator++(int);
|
||||
};
|
||||
|
||||
// Use IIncrementable represents an incrementable type.
|
||||
static_assert(CIncrementable<IIncrementable>);
|
||||
|
||||
/**
|
||||
* A concept specifies a type is potentially an iterator. It only requires weakly incrementable and dereferenceable.
|
||||
* This concept should only be used in scenarios where the specific type of the iterator is not important, such as iterator adapters.
|
||||
*/
|
||||
template <typename I>
|
||||
concept CInputOrOutputIterator = CWeaklyIncrementable<I>
|
||||
&& requires(I Iter) { { *Iter } -> CReferenceable; };
|
||||
|
||||
/** This is an example of an input or output iterator, indicate the traits that define an input or output iterator. */
|
||||
template <CReferenceable T>
|
||||
struct IInputOrOutputIterator /* : IWeaklyIncrementable */
|
||||
{
|
||||
// ~Begin CWeklyIncrementable.
|
||||
|
||||
IInputOrOutputIterator(IInputOrOutputIterator&&);
|
||||
IInputOrOutputIterator* operator=(IInputOrOutputIterator&&);
|
||||
|
||||
IInputOrOutputIterator& operator++();
|
||||
|
||||
void operator++(int);
|
||||
|
||||
// ~End CWeklyIncrementable.
|
||||
|
||||
/** Dereference operator. It does not matter what the return type is, as long as it is referenceable. */
|
||||
T operator*() const;
|
||||
};
|
||||
|
||||
// Use IInputOrOutputIterator represents an input or output iterator.
|
||||
static_assert(CInputOrOutputIterator<IInputOrOutputIterator<int>>);
|
||||
|
||||
/** A concept specifies a type is an input iterator. */
|
||||
template <typename I>
|
||||
concept CInputIterator = CInputOrOutputIterator<I> && CIndirectlyReadable<I>;
|
||||
|
||||
/** This is an example of an input iterator, indicate the traits that define an input iterator. */
|
||||
template <CReferenceable T>
|
||||
struct IInputIterator /* : IInputOrOutputIterator, IIndirectlyReadable */
|
||||
{
|
||||
// ~Begin CIndirectlyReadable.
|
||||
|
||||
using ElementType = TRemoveCVRef<T>;
|
||||
|
||||
// ~End CIndirectlyReadable.
|
||||
|
||||
// ~Begin CInputOrOutputIterator.
|
||||
|
||||
IInputIterator(IInputIterator&&);
|
||||
IInputIterator* operator=(IInputIterator&&);
|
||||
|
||||
T operator*() const; // Also satisfies CIndirectlyReadable.
|
||||
|
||||
IInputIterator& operator++();
|
||||
|
||||
void operator++(int);
|
||||
|
||||
// ~End CInputOrOutputIterator.
|
||||
};
|
||||
|
||||
// Use IInputIterator<int> represents an input iterator and int is the regular element type.
|
||||
static_assert(CInputIterator<IInputIterator<int>> && CRegular<int>);
|
||||
|
||||
// The CInputIterator requires this code is valid.
|
||||
static_assert(
|
||||
requires(IInputIterator<int> Iter, int& A)
|
||||
{
|
||||
++Iter;
|
||||
Iter++;
|
||||
A = *++Iter;
|
||||
A = *Iter;
|
||||
}
|
||||
);
|
||||
|
||||
/** A concept specifies a type is an output iterator and expression '*Iter++ = A' is valid to write the element. */
|
||||
template <typename I, typename T>
|
||||
concept COutputIterator = CInputOrOutputIterator<I> && CIndirectlyWritable<I, T>
|
||||
&& requires(I Iter) { { Iter++ } -> CIndirectlyWritable<T>; };
|
||||
|
||||
/** This is an example of an output iterator, indicate the traits that define an output iterator. */
|
||||
template <CReferenceable T>
|
||||
struct IOutputIterator /* : IInputOrOutputIterator, IIndirectlyWritable<T> */
|
||||
{
|
||||
// ~Begin CIndirectlyWritable.
|
||||
|
||||
IOutputIterator(IOutputIterator&&);
|
||||
IOutputIterator* operator=(IOutputIterator&&);
|
||||
|
||||
T operator*() const; // Also satisfies CIndirectlyWritable.
|
||||
|
||||
IOutputIterator& operator++();
|
||||
|
||||
/**
|
||||
* Post-increment operator.
|
||||
* Specify, the concept not requires the return type is self type,
|
||||
* but requires the expression '*Iter++ = A;' is equivalent to '*Iter = A; ++Iter;'.
|
||||
* This means that returning a proxy class that satisfies CIndirectlyWritable<T> is also valid.
|
||||
* Also satisfies CIndirectlyWritable.
|
||||
*/
|
||||
IIndirectlyWritable<T> operator++(int);
|
||||
|
||||
// ~End CIndirectlyWritable.
|
||||
};
|
||||
|
||||
// Use IOutputIterator<int> represents an output iterator and int is the regular element type.
|
||||
static_assert(COutputIterator<IOutputIterator<int&>, int> && CRegular<int>);
|
||||
|
||||
// The CInputIterator requires this code is valid.
|
||||
static_assert(
|
||||
requires(IOutputIterator<int&> Iter, int& A)
|
||||
{
|
||||
++Iter;
|
||||
Iter++;
|
||||
*++Iter = A;
|
||||
*Iter++ = A;
|
||||
*Iter = A;
|
||||
}
|
||||
);
|
||||
|
||||
#define ENABLE_RANGE_BASED_FOR_LOOP_SUPPORT public: \
|
||||
NODISCARD FORCEINLINE constexpr auto begin() { return Begin(); } \
|
||||
NODISCARD FORCEINLINE constexpr auto begin() const { return Begin(); } \
|
||||
NODISCARD FORCEINLINE constexpr auto end() { return End(); } \
|
||||
NODISCARD FORCEINLINE constexpr auto end() const { return End(); }
|
||||
|
||||
NAMESPACE_MODULE_END(Utility)
|
||||
NAMESPACE_MODULE_END(Redcraft)
|
||||
NAMESPACE_REDCRAFT_END
|
@ -1,140 +1,25 @@
|
||||
#pragma once
|
||||
|
||||
#include "CoreTypes.h"
|
||||
#include "Memory/Address.h"
|
||||
#include "Templates/Invoke.h"
|
||||
#include "Templates/Utility.h"
|
||||
#include "Templates/Noncopyable.h"
|
||||
#include "Iterator/Iterator.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 = TRemoveCV<T>; };
|
||||
|
||||
template <typename I> struct TIteratorPointerType { using Type = void; };
|
||||
template <typename T> struct TIteratorPointerType<T*> { using Type = T*; };
|
||||
|
||||
template <typename I> requires (requires(I& Iter) { { Iter.operator->() } -> CPointer; })
|
||||
struct TIteratorPointerType<I> { using Type = decltype(DeclVal<I&>().operator->()); };
|
||||
|
||||
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 = TIteratorElement<I>;
|
||||
|
||||
template <typename I>
|
||||
using TIteratorElementType = typename NAMESPACE_PRIVATE::TIteratorElementType<TRemoveCVRef<I>>::Type;
|
||||
|
||||
template <typename I>
|
||||
using TIteratorPointerType = typename NAMESPACE_PRIVATE::TIteratorPointerType<TRemoveCVRef<I>>::Type;
|
||||
using TIteratorPointerType = TIteratorPointer<I>;
|
||||
|
||||
template <CReferenceable I>
|
||||
using TIteratorReferenceType = decltype(*DeclVal<I&>());
|
||||
using TIteratorReferenceType = TIteratorReference<I>;
|
||||
|
||||
template <CReferenceable I> requires (requires(I& Iter) { { MoveTemp(*Iter) } -> CReferenceable; })
|
||||
using TIteratorRValueReferenceType = decltype(MoveTemp(*DeclVal<I&>()));
|
||||
|
||||
template <typename I>
|
||||
concept CIndirectlyReadable =
|
||||
requires(const TRemoveCVRef<I> Iter)
|
||||
{
|
||||
typename TIteratorElementType<I>;
|
||||
typename TIteratorReferenceType<I>;
|
||||
typename TIteratorRValueReferenceType<I>;
|
||||
{ *Iter } -> CSameAs<TIteratorReferenceType<I>>;
|
||||
{ MoveTemp(*Iter) } -> CSameAs<TIteratorRValueReferenceType<I>>;
|
||||
}
|
||||
&& CSameAs<TIteratorElementType<I>, TRemoveCVRef<TIteratorElementType<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 TIteratorReferenceType<I>&&>(*Iter) = Forward<T>(A);
|
||||
const_cast<const TIteratorReferenceType<I>&&>(*Forward<I>(Iter)) = Forward<T>(A);
|
||||
};
|
||||
|
||||
template <typename I>
|
||||
concept CWeaklyIncrementable = 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> && CPartiallyOrdered<S, I>
|
||||
&& !bDisableSizedSentinelFor<TRemoveCV<S>, TRemoveCV<I>>
|
||||
&& requires(const I& Iter, const S& Sentinel)
|
||||
{
|
||||
{ Sentinel - Iter } -> CSameAs<ptrdiff>;
|
||||
{ Iter - Sentinel } -> CSameAs<ptrdiff>;
|
||||
};
|
||||
|
||||
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>, TRemoveCVRef<TIteratorReferenceType<I>>>
|
||||
&& requires(I& Iter)
|
||||
{
|
||||
{ ToAddress(Iter) } -> CSameAs<TAddPointer<TIteratorReferenceType<I>>>;
|
||||
};
|
||||
|
||||
static_assert(CContiguousIterator<int32*>);
|
||||
using TIteratorRValueReferenceType = TIteratorRValueReference<I>;
|
||||
|
||||
NAMESPACE_BEGIN(Iteration)
|
||||
|
||||
@ -226,491 +111,6 @@ concept CIndirectlySwappable = CIndirectlyReadable<I> && CIndirectlyReadable<J>
|
||||
IndirectlySwap(Jter, Iter);
|
||||
};
|
||||
|
||||
/** A iterator adaptor for reverse-order traversal. */
|
||||
template <CBidirectionalIterator I>
|
||||
class TReverseIterator final
|
||||
{
|
||||
public:
|
||||
|
||||
using IteratorType = I;
|
||||
|
||||
using ElementType = TIteratorElementType<I>;
|
||||
|
||||
FORCEINLINE constexpr TReverseIterator() = default;
|
||||
|
||||
FORCEINLINE constexpr TReverseIterator(const TReverseIterator&) = default;
|
||||
FORCEINLINE constexpr TReverseIterator(TReverseIterator&&) = default;
|
||||
FORCEINLINE constexpr TReverseIterator& operator=(const TReverseIterator&) = default;
|
||||
FORCEINLINE constexpr TReverseIterator& operator=(TReverseIterator&&) = default;
|
||||
|
||||
FORCEINLINE constexpr ~TReverseIterator() = default;
|
||||
|
||||
template <typename T = IteratorType> requires (!CSameAs<TReverseIterator, TRemoveCVRef<T>> && CConstructibleFrom<IteratorType, T>)
|
||||
FORCEINLINE constexpr explicit TReverseIterator(T&& InValue) : Current(Forward<T>(InValue)) { }
|
||||
|
||||
template <CBidirectionalIterator J> requires (!CSameAs<IteratorType, J> && CConstructibleFrom<IteratorType, const J&>)
|
||||
FORCEINLINE constexpr explicit (!CConvertibleTo<const J&, IteratorType>) TReverseIterator(const TReverseIterator<J>& InValue) : Current(InValue.Current) { }
|
||||
|
||||
template <CBidirectionalIterator J> requires (!CSameAs<IteratorType, J> && CConstructibleFrom<IteratorType, J>)
|
||||
FORCEINLINE constexpr explicit (!CConvertibleTo<J&&, IteratorType>) TReverseIterator(TReverseIterator<J>&& InValue) : Current(MoveTemp(InValue).Current) { }
|
||||
|
||||
template <CBidirectionalIterator J> requires (!CSameAs<IteratorType, J> && CConvertibleTo<const J&, IteratorType> && CAssignableFrom<IteratorType&, const J&>)
|
||||
FORCEINLINE constexpr TReverseIterator& operator=(const TReverseIterator<J>& InValue) { Current = InValue.Current; return *this; }
|
||||
|
||||
template <CBidirectionalIterator J> requires (!CSameAs<IteratorType, J> && CConvertibleTo<J&&, IteratorType> && CAssignableFrom<IteratorType&, J&&>)
|
||||
FORCEINLINE constexpr TReverseIterator& operator=(TReverseIterator<J>&& InValue) { Current = MoveTemp(InValue).Current; return *this; }
|
||||
|
||||
template <CBidirectionalIterator J> requires (CSentinelFor<J, IteratorType>)
|
||||
NODISCARD friend FORCEINLINE constexpr bool operator==(const TReverseIterator& LHS, const TReverseIterator<J>& RHS) { return LHS.Current == RHS.Current; }
|
||||
|
||||
template <CBidirectionalIterator J> requires (CSizedSentinelFor<J, IteratorType>)
|
||||
NODISCARD friend FORCEINLINE constexpr TCompareThreeWayResult<J, IteratorType> operator<=>(const TReverseIterator& LHS, const TReverseIterator<J>& RHS) { return RHS.Current <=> LHS.Current; }
|
||||
|
||||
NODISCARD FORCEINLINE constexpr TIteratorReferenceType<IteratorType> operator*() const { IteratorType Temp = Current; return *--Temp; }
|
||||
NODISCARD FORCEINLINE constexpr TIteratorPointerType<IteratorType> operator->() const { IteratorType Temp = Current; return ToAddress(--Temp); }
|
||||
|
||||
NODISCARD FORCEINLINE constexpr TIteratorReferenceType<IteratorType> operator[](ptrdiff Index) const requires (CRandomAccessIterator<IteratorType>) { return Current[-Index - 1]; }
|
||||
|
||||
FORCEINLINE constexpr TReverseIterator& operator++() { --Current; return *this; }
|
||||
FORCEINLINE constexpr TReverseIterator& operator--() { ++Current; return *this; }
|
||||
|
||||
FORCEINLINE constexpr TReverseIterator operator++(int) { TReverseIterator Temp = *this; --Current; return Temp; }
|
||||
FORCEINLINE constexpr TReverseIterator operator--(int) { TReverseIterator Temp = *this; ++Current; return Temp; }
|
||||
|
||||
FORCEINLINE constexpr TReverseIterator& operator+=(ptrdiff Offset) requires (CRandomAccessIterator<IteratorType>) { Current -= Offset; return *this; }
|
||||
FORCEINLINE constexpr TReverseIterator& operator-=(ptrdiff Offset) requires (CRandomAccessIterator<IteratorType>) { Current += Offset; return *this; }
|
||||
|
||||
NODISCARD friend FORCEINLINE constexpr TReverseIterator operator+(TReverseIterator Iter, ptrdiff Offset) requires (CRandomAccessIterator<IteratorType>) { TReverseIterator Temp = Iter; Temp -= Offset; return Temp; }
|
||||
NODISCARD friend FORCEINLINE constexpr TReverseIterator operator+(ptrdiff Offset, TReverseIterator Iter) requires (CRandomAccessIterator<IteratorType>) { TReverseIterator Temp = Iter; Temp -= Offset; return Temp; }
|
||||
|
||||
NODISCARD FORCEINLINE constexpr TReverseIterator operator-(ptrdiff Offset) const requires (CRandomAccessIterator<IteratorType>) { TReverseIterator Temp = *this; Temp += Offset; return Temp; }
|
||||
|
||||
NODISCARD friend FORCEINLINE constexpr ptrdiff operator-(const TReverseIterator& LHS, const TReverseIterator& RHS) { return RHS.Current - LHS.Current; }
|
||||
|
||||
NODISCARD FORCEINLINE constexpr const IteratorType& GetBase() const& { return Current; }
|
||||
NODISCARD FORCEINLINE constexpr IteratorType GetBase() && { return MoveTemp(Current); }
|
||||
|
||||
private:
|
||||
|
||||
IteratorType Current;
|
||||
|
||||
};
|
||||
|
||||
static_assert(CRandomAccessIterator<TReverseIterator<int32*>>);
|
||||
|
||||
template <typename I, typename J> requires (!CSizedSentinelFor<I, J>)
|
||||
inline constexpr bool bDisableSizedSentinelFor<TReverseIterator<I>, TReverseIterator<J>> = true;
|
||||
|
||||
/** An iterator adaptor which dereferences to a rvalue reference. */
|
||||
template <CInputIterator I>
|
||||
class TMoveIterator final
|
||||
{
|
||||
public:
|
||||
|
||||
using IteratorType = I;
|
||||
|
||||
using ElementType = TIteratorElementType<I>;
|
||||
|
||||
FORCEINLINE constexpr TMoveIterator() = default;
|
||||
|
||||
FORCEINLINE constexpr TMoveIterator(const TMoveIterator&) = default;
|
||||
FORCEINLINE constexpr TMoveIterator(TMoveIterator&&) = default;
|
||||
FORCEINLINE constexpr TMoveIterator& operator=(const TMoveIterator&) = default;
|
||||
FORCEINLINE constexpr TMoveIterator& operator=(TMoveIterator&&) = default;
|
||||
|
||||
FORCEINLINE constexpr ~TMoveIterator() = default;
|
||||
|
||||
template <typename T = IteratorType> requires (!CSameAs<TMoveIterator, TRemoveCVRef<T>> && CConstructibleFrom<IteratorType, T>)
|
||||
FORCEINLINE constexpr explicit TMoveIterator(T&& InValue) : Current(Forward<T>(InValue)) { }
|
||||
|
||||
template <CInputIterator J> requires (!CSameAs<IteratorType, J> && CConstructibleFrom<IteratorType, const J&>)
|
||||
FORCEINLINE constexpr explicit (!CConvertibleTo<const J&, IteratorType>) TMoveIterator(const TMoveIterator<J>& InValue) : Current(InValue.Current) { }
|
||||
|
||||
template <CInputIterator J> requires (!CSameAs<IteratorType, J> && CConstructibleFrom<IteratorType, J>)
|
||||
FORCEINLINE constexpr explicit (!CConvertibleTo<J&&, IteratorType>) TMoveIterator(TMoveIterator<J>&& InValue) : Current(MoveTemp(InValue).Current) { }
|
||||
|
||||
template <CInputIterator J> requires (!CSameAs<IteratorType, J> && CConvertibleTo<const J&, IteratorType> && CAssignableFrom<IteratorType&, const J&>)
|
||||
FORCEINLINE constexpr TMoveIterator& operator=(const TMoveIterator<J>& InValue) { Current = InValue.Current; return *this; }
|
||||
|
||||
template <CInputIterator J> requires (!CSameAs<IteratorType, J> && CConvertibleTo<J&&, IteratorType> && CAssignableFrom<IteratorType&, J&&>)
|
||||
FORCEINLINE constexpr TMoveIterator& operator=(TMoveIterator<J>&& InValue) { Current = MoveTemp(InValue).Current; return *this; }
|
||||
|
||||
template <CInputIterator J> requires (CSentinelFor<J, IteratorType>)
|
||||
NODISCARD friend FORCEINLINE constexpr bool operator==(const TMoveIterator& LHS, const TMoveIterator<J>& RHS) { return LHS.Current == RHS.Current; }
|
||||
|
||||
template <CInputIterator J> requires (CSizedSentinelFor<J, IteratorType>)
|
||||
NODISCARD friend FORCEINLINE constexpr TCompareThreeWayResult<J, IteratorType> operator<=>(const TMoveIterator& LHS, const TMoveIterator<J>& RHS) { return LHS.Current <=> RHS.Current; }
|
||||
|
||||
NODISCARD FORCEINLINE constexpr TIteratorRValueReferenceType<IteratorType> operator*() const { return MoveTemp(*Current); }
|
||||
NODISCARD FORCEINLINE constexpr TIteratorPointerType<IteratorType> operator->() const = delete;
|
||||
|
||||
NODISCARD FORCEINLINE constexpr TIteratorRValueReferenceType<IteratorType> operator[](ptrdiff Index) const requires (CRandomAccessIterator<IteratorType>) { return MoveTemp(Current[Index]); }
|
||||
|
||||
FORCEINLINE constexpr TMoveIterator& operator++() { ++Current; return *this; }
|
||||
FORCEINLINE constexpr TMoveIterator& operator--() requires (CBidirectionalIterator<IteratorType>) { --Current; return *this; }
|
||||
|
||||
FORCEINLINE constexpr void operator++(int) { Current++; }
|
||||
FORCEINLINE constexpr TMoveIterator operator++(int) requires (CForwardIterator<IteratorType>) { return TMoveIterator(Current++); }
|
||||
FORCEINLINE constexpr TMoveIterator operator--(int) requires (CBidirectionalIterator<IteratorType>) { return TMoveIterator(Current--); }
|
||||
|
||||
FORCEINLINE constexpr TMoveIterator& operator+=(ptrdiff Offset) requires (CRandomAccessIterator<IteratorType>) { Current += Offset; return *this; }
|
||||
FORCEINLINE constexpr TMoveIterator& operator-=(ptrdiff Offset) requires (CRandomAccessIterator<IteratorType>) { Current -= Offset; return *this; }
|
||||
|
||||
NODISCARD friend FORCEINLINE constexpr TMoveIterator operator+(TMoveIterator Iter, ptrdiff Offset) requires (CRandomAccessIterator<IteratorType>) { TMoveIterator Temp = Iter; Temp += Offset; return Temp; }
|
||||
NODISCARD friend FORCEINLINE constexpr TMoveIterator operator+(ptrdiff Offset, TMoveIterator Iter) requires (CRandomAccessIterator<IteratorType>) { TMoveIterator Temp = Iter; Temp += Offset; return Temp; }
|
||||
|
||||
NODISCARD FORCEINLINE constexpr TMoveIterator operator-(ptrdiff Offset) const requires (CRandomAccessIterator<IteratorType>) { TMoveIterator Temp = *this; Temp -= Offset; return Temp; }
|
||||
|
||||
NODISCARD friend FORCEINLINE constexpr ptrdiff operator-(const TMoveIterator& LHS, const TMoveIterator& RHS) requires (CSizedSentinelFor<I, I>) { return LHS.Current - RHS.Current; }
|
||||
|
||||
NODISCARD FORCEINLINE constexpr const IteratorType& GetBase() const& { return Current; }
|
||||
NODISCARD FORCEINLINE constexpr IteratorType GetBase() && { return MoveTemp(Current); }
|
||||
|
||||
private:
|
||||
|
||||
IteratorType Current;
|
||||
|
||||
};
|
||||
|
||||
static_assert(CRandomAccessIterator<TMoveIterator<int32*>>);
|
||||
|
||||
/** A sentinel adaptor for use with TMoveIterator. */
|
||||
template <CSemiregular S>
|
||||
class TMoveSentinel
|
||||
{
|
||||
public:
|
||||
|
||||
using SentinelType = S;
|
||||
|
||||
FORCEINLINE constexpr TMoveSentinel() = default;
|
||||
|
||||
FORCEINLINE constexpr TMoveSentinel(const TMoveSentinel&) = default;
|
||||
FORCEINLINE constexpr TMoveSentinel(TMoveSentinel&&) = default;
|
||||
FORCEINLINE constexpr TMoveSentinel& operator=(const TMoveSentinel&) = default;
|
||||
FORCEINLINE constexpr TMoveSentinel& operator=(TMoveSentinel&&) = default;
|
||||
|
||||
FORCEINLINE constexpr ~TMoveSentinel() = default;
|
||||
|
||||
template <typename T = SentinelType> requires (!CSameAs<TMoveSentinel, TRemoveCVRef<T>> && CConstructibleFrom<SentinelType, T>)
|
||||
FORCEINLINE constexpr explicit TMoveSentinel(T&& InValue) : Current(Forward<T>(InValue)) { }
|
||||
|
||||
template <CSemiregular T> requires (!CSameAs<SentinelType, T> && CConstructibleFrom<SentinelType, const T&>)
|
||||
FORCEINLINE constexpr explicit (!CConvertibleTo<const T&, SentinelType>) TMoveSentinel(const TMoveSentinel<T>& InValue) : Current(InValue.Current) { }
|
||||
|
||||
template <CSemiregular T> requires (!CSameAs<SentinelType, T> && CConstructibleFrom<SentinelType, T>)
|
||||
FORCEINLINE constexpr explicit (!CConvertibleTo<T&&, SentinelType>) TMoveSentinel(TMoveSentinel<T>&& InValue) : Current(MoveTemp(InValue).Current) { }
|
||||
|
||||
template <CSemiregular T> requires (!CSameAs<SentinelType, T> && CConvertibleTo<const T&, SentinelType> && CAssignableFrom<SentinelType&, const T&>)
|
||||
FORCEINLINE constexpr TMoveSentinel& operator=(const TMoveSentinel<T>& InValue) { Current = InValue.Current; return *this; }
|
||||
|
||||
template <CSemiregular T> requires (!CSameAs<SentinelType, T> && CConvertibleTo<T&&, SentinelType> && CAssignableFrom<SentinelType&, T&&>)
|
||||
FORCEINLINE constexpr TMoveSentinel& operator=(TMoveSentinel<T>&& InValue) { Current = MoveTemp(InValue).Current; return *this; }
|
||||
|
||||
template <CInputIterator I> requires (CSentinelFor<SentinelType, I>)
|
||||
NODISCARD FORCEINLINE constexpr bool operator==(const TMoveIterator<I>& InValue) const& { return Current == InValue.Current; }
|
||||
|
||||
template <CInputIterator I> requires (CSizedSentinelFor<SentinelType, I>)
|
||||
NODISCARD FORCEINLINE constexpr TCompareThreeWayResult<SentinelType, I> operator<=>(const TMoveIterator<I>& InValue) const& { return Current <=> InValue.Current; }
|
||||
|
||||
template <CInputIterator I> requires (CSizedSentinelFor<SentinelType, I>)
|
||||
NODISCARD friend FORCEINLINE constexpr ptrdiff operator-(const TMoveSentinel& Sentinel, const TMoveIterator<I>& Iter) { return Sentinel.Current - Iter.Current; }
|
||||
|
||||
template <CInputIterator I> requires (CSizedSentinelFor<SentinelType, I>)
|
||||
NODISCARD friend FORCEINLINE constexpr ptrdiff operator-(const TMoveIterator<I>& Iter, const TMoveSentinel& Sentinel) { return Iter.Current - Sentinel.Current; }
|
||||
|
||||
NODISCARD FORCEINLINE constexpr const SentinelType& GetBase() const& { return Current; }
|
||||
NODISCARD FORCEINLINE constexpr SentinelType GetBase() && { return MoveTemp(Current); }
|
||||
|
||||
private:
|
||||
|
||||
SentinelType Current;
|
||||
|
||||
};
|
||||
|
||||
static_assert(CSizedSentinelFor<TMoveSentinel<int32*>, TMoveIterator<int32*>>);
|
||||
|
||||
struct FDefaultSentinel { explicit FDefaultSentinel() = default; };
|
||||
|
||||
inline constexpr FDefaultSentinel DefaultSentinel{ };
|
||||
|
||||
struct FUnreachableSentinel
|
||||
{
|
||||
explicit FUnreachableSentinel() = default;
|
||||
|
||||
template <CWeaklyIncrementable I>
|
||||
NODISCARD FORCEINLINE constexpr bool operator==(const I&) const& { return false; }
|
||||
};
|
||||
|
||||
inline constexpr FUnreachableSentinel UnreachableSentinel{ };
|
||||
|
||||
/** An iterator adaptor that tracks the distance to the end of the range. */
|
||||
template <CInputOrOutputIterator I>
|
||||
class TCountedIterator final
|
||||
{
|
||||
public:
|
||||
|
||||
using IteratorType = I;
|
||||
|
||||
using ElementType = TIteratorElementType<I>;
|
||||
|
||||
# if DO_CHECK
|
||||
FORCEINLINE constexpr TCountedIterator() requires (CDefaultConstructible<IteratorType>) : Length(1), MaxLength(0) { }
|
||||
# else
|
||||
FORCEINLINE constexpr TCountedIterator() requires (CDefaultConstructible<IteratorType>) = default;
|
||||
# endif
|
||||
|
||||
FORCEINLINE constexpr TCountedIterator(const TCountedIterator&) = default;
|
||||
FORCEINLINE constexpr TCountedIterator(TCountedIterator&&) = default;
|
||||
FORCEINLINE constexpr TCountedIterator& operator=(const TCountedIterator&) = default;
|
||||
FORCEINLINE constexpr TCountedIterator& operator=(TCountedIterator&&) = default;
|
||||
|
||||
FORCEINLINE constexpr ~TCountedIterator() = default;
|
||||
|
||||
template <typename T = IteratorType> requires (!CSameAs<TCountedIterator, TRemoveCVRef<T>> && CConstructibleFrom<IteratorType, T>)
|
||||
FORCEINLINE constexpr explicit TCountedIterator(T&& InValue, ptrdiff N) : Current(Forward<T>(InValue)), Length(N) { check_code({ MaxLength = N; }); }
|
||||
|
||||
template <CInputOrOutputIterator J> requires (!CSameAs<IteratorType, J> && CConstructibleFrom<IteratorType, const J&>)
|
||||
FORCEINLINE constexpr explicit (!CConvertibleTo<const J&, IteratorType>) TCountedIterator(const TCountedIterator<J>& InValue) : Current(InValue.Current), Length(InValue.Num()) { check_code({ MaxLength = InValue.MaxLength; }); }
|
||||
|
||||
template <CInputOrOutputIterator J> requires (!CSameAs<IteratorType, J> && CConstructibleFrom<IteratorType, J>)
|
||||
FORCEINLINE constexpr explicit (!CConvertibleTo<J&&, IteratorType>) TCountedIterator(TCountedIterator<J>&& InValue) : Current(MoveTemp(InValue).Current), Length(InValue.Num()) { check_code({ MaxLength = InValue.MaxLength; }); }
|
||||
|
||||
template <CInputOrOutputIterator J> requires (!CSameAs<IteratorType, J> && CConvertibleTo<const J&, IteratorType> && CAssignableFrom<IteratorType&, const J&>)
|
||||
FORCEINLINE constexpr TCountedIterator& operator=(const TCountedIterator<J>& InValue) { Current = InValue.Current; Length = InValue.Num(); check_code({ MaxLength = InValue.MaxLength; }); return *this; }
|
||||
|
||||
template <CInputOrOutputIterator J> requires (!CSameAs<IteratorType, J> && CConvertibleTo<J&&, IteratorType> && CAssignableFrom<IteratorType&, J&&>)
|
||||
FORCEINLINE constexpr TCountedIterator& operator=(TCountedIterator<J>&& InValue) { Current = MoveTemp(InValue).Current; Length = InValue.Num(); check_code({ MaxLength = InValue.MaxLength; }); return *this; }
|
||||
|
||||
template <CCommonType<IteratorType> J>
|
||||
NODISCARD friend FORCEINLINE constexpr bool operator==(const TCountedIterator& LHS, const TCountedIterator<J>& RHS) { return LHS.Length == RHS.Length; }
|
||||
|
||||
template <CCommonType<IteratorType> J>
|
||||
NODISCARD friend FORCEINLINE constexpr strong_ordering operator<=>(const TCountedIterator& LHS, const TCountedIterator<J>& RHS) { return LHS.Length <=> RHS.Length; }
|
||||
|
||||
NODISCARD FORCEINLINE constexpr bool operator==(FDefaultSentinel) const& { return Length == static_cast<ptrdiff>(0); }
|
||||
|
||||
NODISCARD FORCEINLINE constexpr strong_ordering operator<=>(FDefaultSentinel) const& { return static_cast<ptrdiff>(0) <=> Length; }
|
||||
|
||||
NODISCARD FORCEINLINE constexpr TIteratorReferenceType<IteratorType> operator*() { CheckThis(true); return *Current; }
|
||||
|
||||
NODISCARD FORCEINLINE constexpr TIteratorReferenceType<IteratorType> operator*() const requires (CDereferenceable<const IteratorType>) { CheckThis(true); return *Current; }
|
||||
|
||||
NODISCARD FORCEINLINE constexpr TIteratorPointerType<IteratorType> operator->() const requires (CContiguousIterator<IteratorType>) { CheckThis(false); return ToAddress(Current); }
|
||||
|
||||
NODISCARD FORCEINLINE constexpr TIteratorReferenceType<IteratorType> operator[](ptrdiff Index) const requires (CRandomAccessIterator<IteratorType>) { TCountedIterator Temp = *this + Index; return *Temp; }
|
||||
|
||||
FORCEINLINE constexpr TCountedIterator& operator++() { ++Current; --Length; CheckThis(); return *this; }
|
||||
FORCEINLINE constexpr TCountedIterator& operator--() requires (CBidirectionalIterator<IteratorType>) { --Current; ++Length; CheckThis(); return *this; }
|
||||
|
||||
FORCEINLINE constexpr auto operator++(int) { --Length; CheckThis(); return Current++; }
|
||||
FORCEINLINE constexpr TCountedIterator operator++(int) requires (CForwardIterator<IteratorType>) { TCountedIterator Temp = *this; ++Current; --Length; CheckThis(); return Temp; }
|
||||
FORCEINLINE constexpr TCountedIterator operator--(int) requires (CBidirectionalIterator<IteratorType>) { TCountedIterator Temp = *this; --Current; ++Length; CheckThis(); return Temp; }
|
||||
|
||||
FORCEINLINE constexpr TCountedIterator& operator+=(ptrdiff Offset) requires (CRandomAccessIterator<IteratorType>) { Current += Offset; Length -= Offset; CheckThis(); return *this; }
|
||||
FORCEINLINE constexpr TCountedIterator& operator-=(ptrdiff Offset) requires (CRandomAccessIterator<IteratorType>) { Current -= Offset; Length += Offset; CheckThis(); return *this; }
|
||||
|
||||
NODISCARD friend FORCEINLINE constexpr TCountedIterator operator+(TCountedIterator Iter, ptrdiff Offset) requires (CRandomAccessIterator<IteratorType>) { TCountedIterator Temp = Iter; Temp += Offset; return Temp; }
|
||||
NODISCARD friend FORCEINLINE constexpr TCountedIterator operator+(ptrdiff Offset, TCountedIterator Iter) requires (CRandomAccessIterator<IteratorType>) { TCountedIterator Temp = Iter; Temp += Offset; return Temp; }
|
||||
|
||||
NODISCARD FORCEINLINE constexpr TCountedIterator operator-(ptrdiff Offset) const requires (CRandomAccessIterator<IteratorType>) { TCountedIterator Temp = *this; Temp -= Offset; return Temp; }
|
||||
|
||||
template <CCommonType<IteratorType> J>
|
||||
NODISCARD friend FORCEINLINE constexpr ptrdiff operator-(const TCountedIterator& LHS, const TCountedIterator<J>& RHS) { LHS.CheckThis(); RHS.CheckThis(); return LHS.Length - RHS.Length; }
|
||||
|
||||
NODISCARD friend FORCEINLINE constexpr ptrdiff operator-(const TCountedIterator& LHS, FDefaultSentinel) { LHS.CheckThis(); return -LHS.Num(); }
|
||||
NODISCARD friend FORCEINLINE constexpr ptrdiff operator-(FDefaultSentinel, const TCountedIterator& RHS) { RHS.CheckThis(); return RHS.Num(); }
|
||||
|
||||
NODISCARD FORCEINLINE constexpr const IteratorType& GetBase() const& { CheckThis(); return Current; }
|
||||
NODISCARD FORCEINLINE constexpr IteratorType GetBase() && { CheckThis(); return MoveTemp(Current); }
|
||||
NODISCARD FORCEINLINE constexpr ptrdiff Num() const { CheckThis(); return Length; }
|
||||
|
||||
private:
|
||||
|
||||
IteratorType Current;
|
||||
ptrdiff Length;
|
||||
|
||||
# if DO_CHECK
|
||||
ptrdiff MaxLength;
|
||||
# endif
|
||||
|
||||
FORCEINLINE void CheckThis(bool bExceptEnd = false) const
|
||||
{
|
||||
checkf(static_cast<ptrdiff>(0) <= Length && Length <= MaxLength, TEXT("Read access violation. Please check Num()."));
|
||||
checkf(!(bExceptEnd && Length == static_cast<ptrdiff>(0)), TEXT("Read access violation. Please check Num()."));
|
||||
}
|
||||
|
||||
template <CInputOrOutputIterator J>
|
||||
friend class TCountedIterator;
|
||||
|
||||
};
|
||||
|
||||
static_assert(CContiguousIterator<TCountedIterator<int32*>>);
|
||||
static_assert(CSizedSentinelFor<FDefaultSentinel, TCountedIterator<int32*>>);
|
||||
|
||||
NAMESPACE_PRIVATE_BEGIN
|
||||
|
||||
/** An output iterator adapter that wraps a callable object. */
|
||||
template <CMoveConstructible F>
|
||||
class TOutputIterator final : private FNoncopyable
|
||||
{
|
||||
public:
|
||||
|
||||
using Outputer = F;
|
||||
|
||||
private:
|
||||
|
||||
class FIndirectionProxy : private FSingleton
|
||||
{
|
||||
public:
|
||||
|
||||
FORCEINLINE constexpr FIndirectionProxy(TOutputIterator& InIter) : Iter(InIter) { check_code({ bIsProduced = false; }); }
|
||||
|
||||
# if DO_CHECK
|
||||
FORCEINLINE ~FIndirectionProxy()
|
||||
{
|
||||
checkf(bIsProduced, TEXT("Exception output, Ensures that the value is assigned to the output iterator."));
|
||||
}
|
||||
# endif
|
||||
|
||||
template <typename T> requires (CInvocable<Outputer, T>)
|
||||
FORCEINLINE constexpr void operator=(T&& InValue) const
|
||||
{
|
||||
checkf(!bIsProduced, TEXT("Exception output, Ensure that no multiple values are assigned to the output iterator."));
|
||||
Invoke(Iter.Storage, Forward<T>(InValue));
|
||||
check_code({ bIsProduced = true; });
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
TOutputIterator& Iter;
|
||||
|
||||
# if DO_CHECK
|
||||
mutable bool bIsProduced;
|
||||
# endif
|
||||
|
||||
};
|
||||
|
||||
class FPostIncrementProxy : private FSingleton
|
||||
{
|
||||
public:
|
||||
|
||||
FORCEINLINE constexpr FPostIncrementProxy(TOutputIterator& InIter) : Iter(InIter) { check_code({ bIsProduced = false; }); }
|
||||
|
||||
# if DO_CHECK
|
||||
FORCEINLINE ~FPostIncrementProxy()
|
||||
{
|
||||
checkf(bIsProduced, TEXT("Exception output, Ensures that the value is assigned to the output iterator."));
|
||||
}
|
||||
# endif
|
||||
|
||||
NODISCARD FORCEINLINE constexpr FIndirectionProxy operator*() const
|
||||
{
|
||||
checkf(!bIsProduced, TEXT("Exception output, Ensure that no multiple values are assigned to the output iterator."));
|
||||
check_code({ bIsProduced = true; });
|
||||
return FIndirectionProxy(Iter);
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
TOutputIterator& Iter;
|
||||
|
||||
# if DO_CHECK
|
||||
mutable bool bIsProduced;
|
||||
# endif
|
||||
|
||||
};
|
||||
|
||||
public:
|
||||
|
||||
FORCEINLINE constexpr TOutputIterator() requires (CDefaultConstructible<Outputer>) { check_code({ bIsProduced = false; }); }
|
||||
|
||||
template <typename T> requires (!CSameAs<TOutputIterator, TRemoveCVRef<T>> && CConstructibleFrom<Outputer, T>)
|
||||
FORCEINLINE constexpr explicit TOutputIterator(T&& InOutputer) : Storage(Forward<T>(InOutputer)) { check_code({ bIsProduced = false; }); }
|
||||
|
||||
NODISCARD FORCEINLINE constexpr FIndirectionProxy operator*()
|
||||
{
|
||||
checkf(!bIsProduced, TEXT("Exception output, Ensure that no multiple values are assigned to the output iterator."));
|
||||
check_code({ bIsProduced = true; });
|
||||
return FIndirectionProxy(*this);
|
||||
}
|
||||
|
||||
FORCEINLINE constexpr TOutputIterator& operator++() { check_code({ bIsProduced = false; }); return *this; }
|
||||
|
||||
FORCEINLINE constexpr FPostIncrementProxy operator++(int)
|
||||
{
|
||||
checkf(!bIsProduced, TEXT("Exception output, Ensure that no multiple values are assigned to the output iterator."));
|
||||
return FPostIncrementProxy(*this);
|
||||
}
|
||||
|
||||
NODISCARD FORCEINLINE constexpr const Outputer& GetOutputer() const& { return Storage; }
|
||||
NODISCARD FORCEINLINE constexpr Outputer GetOutputer() && { return Storage; }
|
||||
|
||||
private:
|
||||
|
||||
Outputer Storage;
|
||||
|
||||
# if DO_CHECK
|
||||
bool bIsProduced;
|
||||
# endif
|
||||
|
||||
};
|
||||
|
||||
static_assert(COutputIterator<TOutputIterator<void(*)(int32)>, int32>);
|
||||
|
||||
template <typename F>
|
||||
TOutputIterator(F) -> TOutputIterator<F>;
|
||||
|
||||
NAMESPACE_PRIVATE_END
|
||||
|
||||
/** Creates a TReverseIterator of type inferred from the argument. */
|
||||
template <typename I> requires (CBidirectionalIterator<TDecay<I>> && CConstructibleFrom<TDecay<I>, I>)
|
||||
NODISCARD FORCEINLINE constexpr auto MakeReverseIterator(I&& Iter)
|
||||
{
|
||||
return TReverseIterator<TDecay<I>>(Forward<I>(Iter));
|
||||
}
|
||||
|
||||
/** Creates a TMoveIterator of type inferred from the argument. */
|
||||
template <typename I> requires (CInputIterator<TDecay<I>> && CConstructibleFrom<TDecay<I>, I>)
|
||||
NODISCARD FORCEINLINE constexpr auto MakeMoveIterator(I&& Iter)
|
||||
{
|
||||
return TMoveIterator<TDecay<I>>(Forward<I>(Iter));
|
||||
}
|
||||
|
||||
/** Creates a TMoveSentinel of type inferred from the argument. */
|
||||
template <typename I> requires (CSemiregular<TDecay<I>> && CConstructibleFrom<TDecay<I>, I>)
|
||||
NODISCARD FORCEINLINE constexpr auto MakeMoveSentinel(I&& Iter)
|
||||
{
|
||||
return TMoveSentinel<TDecay<I>>(Forward<I>(Iter));
|
||||
}
|
||||
|
||||
/** Creates a TCountedIterator of type inferred from the argument. */
|
||||
template <typename I> requires (CInputOrOutputIterator<TDecay<I>> && CConstructibleFrom<TDecay<I>, I>)
|
||||
NODISCARD FORCEINLINE constexpr auto MakeCountedIterator(I&& Iter, ptrdiff N)
|
||||
{
|
||||
return TCountedIterator<TDecay<I>>(Forward<I>(Iter), N);
|
||||
}
|
||||
|
||||
/** Creates an iterator adapter inserted in the front of the container. */
|
||||
template <typename C>
|
||||
NODISCARD FORCEINLINE constexpr auto MakeFrontInserter(C& Container)
|
||||
{
|
||||
return NAMESPACE_PRIVATE::TOutputIterator([&Container]<typename T>(T&& A) { Container.PushFront(Forward<T>(A)); });
|
||||
}
|
||||
|
||||
/** Creates an iterator adapter inserted in the back of the container. */
|
||||
template <typename C>
|
||||
NODISCARD FORCEINLINE constexpr auto MakeBackInserter(C& Container)
|
||||
{
|
||||
return NAMESPACE_PRIVATE::TOutputIterator([&Container]<typename T>(T&& A) { Container.PushBack(Forward<T>(A)); });
|
||||
}
|
||||
|
||||
/** Creates an iterator adapter inserted in the container. */
|
||||
template <typename C>
|
||||
NODISCARD FORCEINLINE constexpr auto MakeInserter(C& Container, const typename C::ConstIterator& InIter)
|
||||
{
|
||||
return NAMESPACE_PRIVATE::TOutputIterator([&Container, Iter = InIter]<typename T>(T&& A) mutable { Iter = Container.Insert(Iter, Forward<T>(A)); });
|
||||
}
|
||||
|
||||
NAMESPACE_BEGIN(Iteration)
|
||||
|
||||
/** @return The iterator to the beginning of a container. */
|
||||
@ -795,12 +195,6 @@ FORCEINLINE constexpr auto REnd(initializer_list<T> Container)
|
||||
|
||||
NAMESPACE_END(Iteration)
|
||||
|
||||
#define ENABLE_RANGE_BASED_FOR_LOOP_SUPPORT public: \
|
||||
NODISCARD FORCEINLINE constexpr auto begin() { return Begin(); } \
|
||||
NODISCARD FORCEINLINE constexpr auto begin() const { return Begin(); } \
|
||||
NODISCARD FORCEINLINE constexpr auto end() { return End(); } \
|
||||
NODISCARD FORCEINLINE constexpr auto end() const { return End(); }
|
||||
|
||||
NAMESPACE_MODULE_END(Utility)
|
||||
NAMESPACE_MODULE_END(Redcraft)
|
||||
NAMESPACE_REDCRAFT_END
|
||||
|
@ -1,7 +1,9 @@
|
||||
#pragma once
|
||||
|
||||
#include "CoreTypes.h"
|
||||
#include "Range/Range.h"
|
||||
#include "Memory/Address.h"
|
||||
#include "Numeric/Numeric.h"
|
||||
#include "Templates/Invoke.h"
|
||||
#include "Templates/Utility.h"
|
||||
#include "TypeTraits/TypeTraits.h"
|
||||
@ -11,252 +13,20 @@ NAMESPACE_REDCRAFT_BEGIN
|
||||
NAMESPACE_MODULE_BEGIN(Redcraft)
|
||||
NAMESPACE_MODULE_BEGIN(Utility)
|
||||
|
||||
// NOTE: The range that holds the object is called a container, and the range that only references the object is called a view.
|
||||
template <typename R>
|
||||
using TRangeIteratorType = TRangeIterator<R>;
|
||||
|
||||
template <typename R>
|
||||
inline constexpr bool bEnableBorrowedRange = false;
|
||||
|
||||
NAMESPACE_BEGIN(Range)
|
||||
|
||||
/** @return The iterator to the beginning of a container. */
|
||||
template <typename T> requires ((CLValueReference<T> || bEnableBorrowedRange<TRemoveCVRef<T>>)
|
||||
&& requires(T&& Container) { { Container.Begin() } -> CInputOrOutputIterator; })
|
||||
NODISCARD FORCEINLINE constexpr auto Begin(T&& Container)
|
||||
{
|
||||
return Container.Begin();
|
||||
}
|
||||
|
||||
/** Overloads the Begin algorithm for arrays. */
|
||||
template <typename T> requires ((CLValueReference<T> || bEnableBorrowedRange<TRemoveCVRef<T>>)
|
||||
&& CArray<TRemoveReference<T>>)
|
||||
NODISCARD FORCEINLINE constexpr auto Begin(T&& Container)
|
||||
{
|
||||
return Container + 0;
|
||||
}
|
||||
|
||||
/** Overloads the Begin algorithm for initializer_list. */
|
||||
template <typename T>
|
||||
NODISCARD FORCEINLINE constexpr auto Begin(initializer_list<T>& Container)
|
||||
{
|
||||
return Container.begin();
|
||||
}
|
||||
|
||||
NAMESPACE_END(Range)
|
||||
using TRangeSentinelType = TRangeSentinel<R>;
|
||||
|
||||
template <typename R>
|
||||
using TRangeIteratorType = decltype(Range::Begin(DeclVal<R&>()));
|
||||
|
||||
NAMESPACE_BEGIN(Range)
|
||||
|
||||
/** @return The iterator to the end of a container. */
|
||||
template <typename T> requires ((CLValueReference<T> || bEnableBorrowedRange<TRemoveCVRef<T>>)
|
||||
&& requires(T&& Container) { { Container.End() } -> CSentinelFor<TRangeIteratorType<T>>; })
|
||||
NODISCARD FORCEINLINE constexpr auto End(T&& Container)
|
||||
{
|
||||
return Container.End();
|
||||
}
|
||||
|
||||
/** Overloads the End algorithm for arrays. */
|
||||
template <typename T> requires ((CLValueReference<T> || bEnableBorrowedRange<TRemoveCVRef<T>>)
|
||||
&& CBoundedArray<TRemoveReference<T>>)
|
||||
NODISCARD FORCEINLINE constexpr auto End(T&& Container)
|
||||
{
|
||||
return Container + TExtent<TRemoveReference<T>>;
|
||||
}
|
||||
|
||||
/** Overloads the End algorithm for initializer_list. */
|
||||
template <typename T>
|
||||
NODISCARD FORCEINLINE constexpr auto End(initializer_list<T>& Container)
|
||||
{
|
||||
return Container.end();
|
||||
}
|
||||
|
||||
NAMESPACE_END(Range)
|
||||
using TRangeElementType = TRangeElement<R>;
|
||||
|
||||
template <typename R>
|
||||
using TRangeSentinelType = decltype(Range::End(DeclVal<R&>()));
|
||||
|
||||
NAMESPACE_BEGIN(Range)
|
||||
|
||||
/** @return The reverse iterator to the beginning of a container. */
|
||||
template <typename T> requires ((CLValueReference<T> || bEnableBorrowedRange<TRemoveCVRef<T>>)
|
||||
&& requires(T&& Container) { { Container.RBegin() } -> CInputOrOutputIterator; })
|
||||
NODISCARD FORCEINLINE constexpr auto RBegin(T&& Container)
|
||||
{
|
||||
return Container.RBegin();
|
||||
}
|
||||
|
||||
/** Overloads the RBegin algorithm for synthesized. */
|
||||
template <typename T> requires ((CLValueReference<T> || bEnableBorrowedRange<TRemoveCVRef<T>>)
|
||||
&& !requires(T&& Container) { { Container.RBegin() } -> CInputOrOutputIterator; }
|
||||
&& (CSameAs<TRangeIteratorType<T>, TRangeSentinelType<T>> && CBidirectionalIterator<TRangeIteratorType<T>>))
|
||||
NODISCARD FORCEINLINE constexpr auto RBegin(T&& Container)
|
||||
{
|
||||
return MakeReverseIterator(Range::End(Forward<T>(Container)));
|
||||
}
|
||||
|
||||
/** @return The reverse iterator to the end of a container. */
|
||||
template <typename T> requires ((CLValueReference<T> || bEnableBorrowedRange<TRemoveCVRef<T>>)
|
||||
&& requires(T&& Container) { { Container.REnd() } -> CSentinelFor<decltype(Range::RBegin(DeclVal<T&>()))>; })
|
||||
NODISCARD FORCEINLINE constexpr auto REnd(T&& Container)
|
||||
{
|
||||
return Container.REnd();
|
||||
}
|
||||
|
||||
/** Overloads the REnd algorithm for synthesized. */
|
||||
template <typename T> requires ((CLValueReference<T> || bEnableBorrowedRange<TRemoveCVRef<T>>)
|
||||
&& !requires(T&& Container) { { Container.REnd() } -> CSentinelFor<decltype(Range::RBegin(DeclVal<T&>()))>; }
|
||||
&& (CSameAs<TRangeIteratorType<T>, TRangeSentinelType<T>> && CBidirectionalIterator<TRangeIteratorType<T>>))
|
||||
NODISCARD FORCEINLINE constexpr auto REnd(T&& Container)
|
||||
{
|
||||
return MakeReverseIterator(Range::Begin(Forward<T>(Container)));
|
||||
}
|
||||
|
||||
NAMESPACE_END(Range)
|
||||
|
||||
NAMESPACE_PRIVATE_BEGIN
|
||||
|
||||
template <typename R> struct TRangeElementType { using Type = typename R::ElementType; };
|
||||
template <typename T> struct TRangeElementType<T[ ]> { using Type = T; };
|
||||
template <typename T, size_t N> struct TRangeElementType<T[N]> { using Type = T; };
|
||||
|
||||
NAMESPACE_PRIVATE_END
|
||||
using TRangeReferenceType = TRangeReference<R>;
|
||||
|
||||
template <typename R>
|
||||
using TRangeElementType = typename NAMESPACE_PRIVATE::TRangeElementType<TRemoveCVRef<R>>::Type;
|
||||
|
||||
template <typename R>
|
||||
using TRangeReferenceType = TIteratorReferenceType<TRangeIteratorType<R>>;
|
||||
|
||||
template <typename R>
|
||||
using TRangeRValueReferenceType = TIteratorRValueReferenceType<TRangeIteratorType<R>>;
|
||||
|
||||
NAMESPACE_BEGIN(Range)
|
||||
|
||||
/** @return The pointer to the container element storage. */
|
||||
template <typename T> requires ((CLValueReference<T> || bEnableBorrowedRange<TRemoveCVRef<T>>)
|
||||
&& requires(T&& Container) { { Container.GetData() } -> CSameAs<TAddPointer<TRangeReferenceType<T>>>; })
|
||||
NODISCARD FORCEINLINE constexpr auto GetData(T&& Container)
|
||||
{
|
||||
return Container.GetData();
|
||||
}
|
||||
|
||||
/** Overloads the GetData algorithm for synthesized. */
|
||||
template <typename T> requires ((CLValueReference<T> || bEnableBorrowedRange<TRemoveCVRef<T>>)
|
||||
&& !requires(T&& Container) { { Container.GetData() } -> CSameAs<TAddPointer<TRangeReferenceType<T>>>; }
|
||||
&& requires(T&& Container) { { Range::Begin(Forward<T>(Container)) } -> CContiguousIterator; })
|
||||
NODISCARD FORCEINLINE constexpr auto GetData(T&& Container)
|
||||
{
|
||||
return ToAddress(Range::Begin(Forward<T>(Container)));
|
||||
}
|
||||
|
||||
NAMESPACE_END(Range)
|
||||
|
||||
template <typename R>
|
||||
inline constexpr bool bDisableSizedRange = false;
|
||||
|
||||
NAMESPACE_BEGIN(Range)
|
||||
|
||||
/** @return The number of elements in the container. */
|
||||
template <typename T> requires (!bDisableSizedRange<TRemoveCVRef<T>>
|
||||
&& requires(T&& Container) { { Container.Num() } -> CSameAs<size_t>; })
|
||||
NODISCARD FORCEINLINE constexpr size_t Num(T&& Container)
|
||||
{
|
||||
return Container.Num();
|
||||
}
|
||||
|
||||
/** Overloads the Num algorithm for arrays. */
|
||||
template <typename T> requires (!bDisableSizedRange<TRemoveCVRef<T>>
|
||||
&& CBoundedArray<TRemoveReference<T>>)
|
||||
NODISCARD FORCEINLINE constexpr size_t Num(T&& Container)
|
||||
{
|
||||
return TExtent<TRemoveReference<T>>;
|
||||
}
|
||||
|
||||
/** Overloads the Num algorithm for synthesized. */
|
||||
template <typename T> requires (!bDisableSizedRange<TRemoveCVRef<T>>
|
||||
&& !requires(T&& Container) { { Container.Num() } -> CSameAs<size_t>; } && !CBoundedArray<TRemoveReference<T>>
|
||||
&& CSizedSentinelFor<TRangeIteratorType<T>, TRangeSentinelType<T>> && CForwardIterator<TRangeIteratorType<T>>)
|
||||
NODISCARD FORCEINLINE constexpr size_t Num(T&& Container)
|
||||
{
|
||||
return Range::End(Forward<T>(Container)) - Range::Begin(Forward<T>(Container));
|
||||
}
|
||||
|
||||
/** @return true if the container is empty, false otherwise. */
|
||||
template <typename T> requires (requires(T&& Container) { { Container.IsEmpty() } -> CBooleanTestable; })
|
||||
NODISCARD FORCEINLINE constexpr bool IsEmpty(T&& Container)
|
||||
{
|
||||
return Container.IsEmpty();
|
||||
}
|
||||
|
||||
/** Overloads the IsEmpty algorithm for synthesized. */
|
||||
template <typename T> requires ((CBoundedArray<TRemoveReference<T>>
|
||||
|| requires(T&& Container) { { Container.Num() } -> CSameAs<size_t>; })
|
||||
&& !requires(T&& Container) { { Container.IsEmpty() } -> CBooleanTestable; })
|
||||
NODISCARD FORCEINLINE constexpr bool IsEmpty(T&& Container)
|
||||
{
|
||||
return Range::Num(Forward<T>(Container)) == 0;
|
||||
}
|
||||
|
||||
/** Overloads the IsEmpty algorithm for synthesized. */
|
||||
template <typename T> requires (!CBoundedArray<TRemoveReference<T>>
|
||||
&& !requires(T&& Container) { { Container.Num() } -> CSameAs<size_t>; }
|
||||
&& !requires(T&& Container) { { Container.IsEmpty() } -> CBooleanTestable; }
|
||||
&& CForwardIterator<TRangeIteratorType<T>>)
|
||||
NODISCARD FORCEINLINE constexpr bool IsEmpty(T&& Container)
|
||||
{
|
||||
return Range::End(Forward<T>(Container)) == Range::Begin(Forward<T>(Container));
|
||||
}
|
||||
|
||||
NAMESPACE_END(Range)
|
||||
|
||||
template <typename R>
|
||||
concept CRange =
|
||||
requires(R Range)
|
||||
{
|
||||
typename TRangeIteratorType<R>;
|
||||
typename TRangeSentinelType<R>;
|
||||
}
|
||||
&& CInputOrOutputIterator<TRangeIteratorType<R>>
|
||||
&& CSentinelFor<TRangeSentinelType<R>, TRangeIteratorType<R>>;
|
||||
|
||||
template <typename R>
|
||||
concept CBorrowedRange = CRange<R> && (CLValueReference<R> || bEnableBorrowedRange<TRemoveCVRef<R>>);
|
||||
|
||||
template <typename R>
|
||||
concept CSizedRange = CRange<R>
|
||||
&& requires(R Range)
|
||||
{
|
||||
{ Range::Num(Range) } -> CConvertibleTo<size_t>;
|
||||
};
|
||||
|
||||
template <typename R>
|
||||
concept CInputRange = CRange<R> && CInputIterator<TRangeIteratorType<R>>;
|
||||
|
||||
template <typename R, typename T>
|
||||
concept COutputRange = CRange<R> && COutputIterator<TRangeIteratorType<R>, T>;
|
||||
|
||||
template <typename R>
|
||||
concept CForwardRange = CInputRange<R> && CForwardIterator<TRangeIteratorType<R>>;
|
||||
|
||||
template <typename R>
|
||||
concept CBidirectionalRange = CForwardRange<R> && CBidirectionalIterator<TRangeIteratorType<R>>;
|
||||
|
||||
template <typename R>
|
||||
concept CRandomAccessRange = CBidirectionalRange<R> && CRandomAccessIterator<TRangeIteratorType<R>>;
|
||||
|
||||
template <typename R>
|
||||
concept CContiguousRange = CRandomAccessRange<R> && CContiguousIterator<TRangeIteratorType<R>>
|
||||
&& requires(R& Range)
|
||||
{
|
||||
{ Range::GetData(Range) } -> CSameAs<TAddPointer<TRangeReferenceType<R>>>;
|
||||
};
|
||||
|
||||
template <typename R>
|
||||
concept CCommonRange = CRange<R> && CSameAs<TRangeIteratorType<R>, TRangeSentinelType<R>>;
|
||||
|
||||
static_assert(CContiguousRange<int[8]>);
|
||||
static_assert( CCommonRange<int[8]>);
|
||||
using TRangeRValueReferenceType = TRangeRValueReference<R>;
|
||||
|
||||
NAMESPACE_BEGIN(Range)
|
||||
|
||||
|
4
Redcraft.Utility/Source/Public/Range/Range.h
Normal file
4
Redcraft.Utility/Source/Public/Range/Range.h
Normal file
@ -0,0 +1,4 @@
|
||||
#pragma once
|
||||
|
||||
#include "CoreTypes.h"
|
||||
#include "Range/Utility.h"
|
367
Redcraft.Utility/Source/Public/Range/Utility.h
Normal file
367
Redcraft.Utility/Source/Public/Range/Utility.h
Normal file
@ -0,0 +1,367 @@
|
||||
#pragma once
|
||||
|
||||
#include "CoreTypes.h"
|
||||
#include "Templates/Utility.h"
|
||||
#include "Iterator/Iterator.h"
|
||||
#include "TypeTraits/TypeTraits.h"
|
||||
|
||||
NAMESPACE_REDCRAFT_BEGIN
|
||||
NAMESPACE_MODULE_BEGIN(Redcraft)
|
||||
NAMESPACE_MODULE_BEGIN(Utility)
|
||||
|
||||
/**
|
||||
* The bool value that indicates whether the range always is borrowed range.
|
||||
* When the range always is borrowed range, it means that the iterators and sentinels
|
||||
* of the range remain valid even if the range object is destructed.
|
||||
*/
|
||||
template <typename R>
|
||||
inline constexpr bool bEnableBorrowedRange = false;
|
||||
|
||||
NAMESPACE_BEGIN(Range)
|
||||
|
||||
/** @return The iterator to the beginning of a container. */
|
||||
template <typename T> requires ((CLValueReference<T> || bEnableBorrowedRange<TRemoveCVRef<T>>)
|
||||
&& requires(T&& Container) { { Container.Begin() } -> CInputOrOutputIterator; })
|
||||
NODISCARD FORCEINLINE constexpr auto Begin(T&& Container)
|
||||
{
|
||||
return Container.Begin();
|
||||
}
|
||||
|
||||
/** Overloads the Begin algorithm for arrays. */
|
||||
template <typename T> requires ((CLValueReference<T> || bEnableBorrowedRange<TRemoveCVRef<T>>)
|
||||
&& CArray<TRemoveReference<T>>)
|
||||
NODISCARD FORCEINLINE constexpr auto Begin(T&& Container)
|
||||
{
|
||||
return Container + 0;
|
||||
}
|
||||
|
||||
/** Overloads the Begin algorithm for initializer_list. */
|
||||
template <typename T>
|
||||
NODISCARD FORCEINLINE constexpr auto Begin(initializer_list<T>& Container)
|
||||
{
|
||||
return Container.begin();
|
||||
}
|
||||
|
||||
NAMESPACE_END(Range)
|
||||
|
||||
template <typename R>
|
||||
using TRangeIterator = decltype(Range::Begin(DeclVal<R&>()));
|
||||
|
||||
|
||||
NAMESPACE_BEGIN(Range)
|
||||
|
||||
/** @return The iterator to the end of a container. */
|
||||
template <typename T> requires ((CLValueReference<T> || bEnableBorrowedRange<TRemoveCVRef<T>>)
|
||||
&& requires(T&& Container) { { Container.End() } -> CSentinelFor<TRangeIterator<T>>; })
|
||||
NODISCARD FORCEINLINE constexpr auto End(T&& Container)
|
||||
{
|
||||
return Container.End();
|
||||
}
|
||||
|
||||
/** Overloads the End algorithm for arrays. */
|
||||
template <typename T> requires ((CLValueReference<T> || bEnableBorrowedRange<TRemoveCVRef<T>>)
|
||||
&& CBoundedArray<TRemoveReference<T>>)
|
||||
NODISCARD FORCEINLINE constexpr auto End(T&& Container)
|
||||
{
|
||||
return Container + TExtent<TRemoveReference<T>>;
|
||||
}
|
||||
|
||||
/** Overloads the End algorithm for initializer_list. */
|
||||
template <typename T>
|
||||
NODISCARD FORCEINLINE constexpr auto End(initializer_list<T>& Container)
|
||||
{
|
||||
return Container.end();
|
||||
}
|
||||
|
||||
NAMESPACE_END(Range)
|
||||
|
||||
template <typename R>
|
||||
using TRangeSentinel = decltype(Range::End(DeclVal<R&>()));
|
||||
|
||||
|
||||
NAMESPACE_BEGIN(Range)
|
||||
|
||||
/** @return The reverse iterator to the beginning of a container. */
|
||||
template <typename T> requires ((CLValueReference<T> || bEnableBorrowedRange<TRemoveCVRef<T>>)
|
||||
&& requires(T&& Container) { { Container.RBegin() } -> CInputOrOutputIterator; })
|
||||
NODISCARD FORCEINLINE constexpr auto RBegin(T&& Container)
|
||||
{
|
||||
return Container.RBegin();
|
||||
}
|
||||
|
||||
/** Overloads the RBegin algorithm for synthesized. */
|
||||
template <typename T> requires ((CLValueReference<T> || bEnableBorrowedRange<TRemoveCVRef<T>>)
|
||||
&& !requires(T&& Container) { { Container.RBegin() } -> CInputOrOutputIterator; }
|
||||
&& (CSameAs<TRangeIterator<T>, TRangeSentinel<T>> && CBidirectionalIterator<TRangeIterator<T>>))
|
||||
NODISCARD FORCEINLINE constexpr auto RBegin(T&& Container)
|
||||
{
|
||||
return MakeReverseIterator(Range::End(Forward<T>(Container)));
|
||||
}
|
||||
|
||||
/** @return The reverse iterator to the end of a container. */
|
||||
template <typename T> requires ((CLValueReference<T> || bEnableBorrowedRange<TRemoveCVRef<T>>)
|
||||
&& requires(T&& Container) { { Container.REnd() } -> CSentinelFor<decltype(Range::RBegin(DeclVal<T&>()))>; })
|
||||
NODISCARD FORCEINLINE constexpr auto REnd(T&& Container)
|
||||
{
|
||||
return Container.REnd();
|
||||
}
|
||||
|
||||
/** Overloads the REnd algorithm for synthesized. */
|
||||
template <typename T> requires ((CLValueReference<T> || bEnableBorrowedRange<TRemoveCVRef<T>>)
|
||||
&& !requires(T&& Container) { { Container.REnd() } -> CSentinelFor<decltype(Range::RBegin(DeclVal<T&>()))>; }
|
||||
&& (CSameAs<TRangeIterator<T>, TRangeSentinel<T>> && CBidirectionalIterator<TRangeIterator<T>>))
|
||||
NODISCARD FORCEINLINE constexpr auto REnd(T&& Container)
|
||||
{
|
||||
return MakeReverseIterator(Range::Begin(Forward<T>(Container)));
|
||||
}
|
||||
|
||||
NAMESPACE_END(Range)
|
||||
|
||||
template <typename R>
|
||||
using TRangeElement = TIteratorElement<TRangeIterator<R>>;
|
||||
|
||||
template <typename R>
|
||||
using TRangePointer = TIteratorPointer<TRangeIterator<R>>;
|
||||
|
||||
template <typename R>
|
||||
using TRangeReference = TIteratorReference<TRangeIterator<R>>;
|
||||
|
||||
template <typename R>
|
||||
using TRangeRValueReference = TIteratorRValueReference<TRangeIterator<R>>;
|
||||
|
||||
NAMESPACE_BEGIN(Range)
|
||||
|
||||
/** @return The pointer to the container element storage. */
|
||||
template <typename T> requires ((CLValueReference<T> || bEnableBorrowedRange<TRemoveCVRef<T>>)
|
||||
&& requires(T&& Container) { { Container.GetData() } -> CSameAs<TAddPointer<TRangeReference<T>>>; })
|
||||
NODISCARD FORCEINLINE constexpr auto GetData(T&& Container)
|
||||
{
|
||||
return Container.GetData();
|
||||
}
|
||||
|
||||
/** Overloads the GetData algorithm for synthesized. */
|
||||
template <typename T> requires ((CLValueReference<T> || bEnableBorrowedRange<TRemoveCVRef<T>>)
|
||||
&& !requires(T&& Container) { { Container.GetData() } -> CSameAs<TAddPointer<TRangeReference<T>>>; }
|
||||
&& requires(T&& Container) { { Range::Begin(Forward<T>(Container)) } -> CContiguousIterator; })
|
||||
NODISCARD FORCEINLINE constexpr auto GetData(T&& Container)
|
||||
{
|
||||
return ToAddress(Range::Begin(Forward<T>(Container)));
|
||||
}
|
||||
|
||||
NAMESPACE_END(Range)
|
||||
|
||||
/** Disable the CSizedRange concept for specific types. */
|
||||
template <typename R>
|
||||
inline constexpr bool bDisableSizedRange = false;
|
||||
|
||||
NAMESPACE_BEGIN(Range)
|
||||
|
||||
/** @return The number of elements in the container. */
|
||||
template <typename T> requires (!bDisableSizedRange<TRemoveCVRef<T>>
|
||||
&& requires(T&& Container) { { Container.Num() } -> CSameAs<size_t>; })
|
||||
NODISCARD FORCEINLINE constexpr size_t Num(T&& Container)
|
||||
{
|
||||
return Container.Num();
|
||||
}
|
||||
|
||||
/** Overloads the Num algorithm for arrays. */
|
||||
template <typename T> requires (!bDisableSizedRange<TRemoveCVRef<T>>
|
||||
&& CBoundedArray<TRemoveReference<T>>)
|
||||
NODISCARD FORCEINLINE constexpr size_t Num(T&& Container)
|
||||
{
|
||||
return TExtent<TRemoveReference<T>>;
|
||||
}
|
||||
|
||||
/** Overloads the Num algorithm for synthesized. */
|
||||
template <typename T> requires (!bDisableSizedRange<TRemoveCVRef<T>>
|
||||
&& !requires(T&& Container) { { Container.Num() } -> CSameAs<size_t>; } && !CBoundedArray<TRemoveReference<T>>
|
||||
&& CSizedSentinelFor<TRangeSentinel<T>, TRangeIterator<T>> && CForwardIterator<TRangeIterator<T>>)
|
||||
NODISCARD FORCEINLINE constexpr size_t Num(T&& Container)
|
||||
{
|
||||
return Range::End(Forward<T>(Container)) - Range::Begin(Forward<T>(Container));
|
||||
}
|
||||
|
||||
/** @return true if the container is empty, false otherwise. */
|
||||
template <typename T> requires (requires(T&& Container) { { Container.IsEmpty() } -> CBooleanTestable; })
|
||||
NODISCARD FORCEINLINE constexpr bool IsEmpty(T&& Container)
|
||||
{
|
||||
return Container.IsEmpty();
|
||||
}
|
||||
|
||||
/** Overloads the IsEmpty algorithm for synthesized. */
|
||||
template <typename T> requires ((CBoundedArray<TRemoveReference<T>>
|
||||
|| requires(T&& Container) { { Container.Num() } -> CSameAs<size_t>; })
|
||||
&& !requires(T&& Container) { { Container.IsEmpty() } -> CBooleanTestable; })
|
||||
NODISCARD FORCEINLINE constexpr bool IsEmpty(T&& Container)
|
||||
{
|
||||
return Range::Num(Forward<T>(Container)) == 0;
|
||||
}
|
||||
|
||||
/** Overloads the IsEmpty algorithm for synthesized. */
|
||||
template <typename T> requires (!CBoundedArray<TRemoveReference<T>>
|
||||
&& !requires(T&& Container) { { Container.Num() } -> CSameAs<size_t>; }
|
||||
&& !requires(T&& Container) { { Container.IsEmpty() } -> CBooleanTestable; }
|
||||
&& CForwardIterator<TRangeIterator<T>>)
|
||||
NODISCARD FORCEINLINE constexpr bool IsEmpty(T&& Container)
|
||||
{
|
||||
return Range::End(Forward<T>(Container)) == Range::Begin(Forward<T>(Container));
|
||||
}
|
||||
|
||||
NAMESPACE_END(Range)
|
||||
|
||||
/**
|
||||
* A concept specifies a type is a range.
|
||||
* A range is an iterator-sentinel pair that represents a sequence of elements.
|
||||
*/
|
||||
template <typename R>
|
||||
concept CRange =
|
||||
requires(R Range)
|
||||
{
|
||||
typename TRangeIterator<R>;
|
||||
typename TRangeSentinel<R>;
|
||||
}
|
||||
&& CInputOrOutputIterator<TRangeIterator<R>>
|
||||
&& CSentinelFor<TRangeSentinel<R>, TRangeIterator<R>>;
|
||||
|
||||
/** This is an example of a range type, indicate the traits that define a range type. */
|
||||
template <CInputOrOutputIterator I, CSentinelFor<I> S = ISentinelFor<I>>
|
||||
struct IRange
|
||||
{
|
||||
/**
|
||||
* Get the iterator-sentinel pair.
|
||||
* If the function is const, it means that the const IRange satisfies CRange.
|
||||
*/
|
||||
I Begin() /* const */;
|
||||
S End() /* const */;
|
||||
};
|
||||
|
||||
// Use IRange<...> represents an range type.
|
||||
static_assert(CRange<IRange<IInputOrOutputIterator<int&>>>);
|
||||
|
||||
/**
|
||||
* A concept specifies a type is a borrowed range.
|
||||
* When the range is borrowed range, it means that the iterators and sentinels
|
||||
* of the range remain valid even if the range value (note not object) is destructed.
|
||||
*/
|
||||
template <typename R>
|
||||
concept CBorrowedRange = CRange<R> && (CLValueReference<R> || bEnableBorrowedRange<TRemoveCVRef<R>>);
|
||||
|
||||
/**
|
||||
* A concept specifies a type is a sized range.
|
||||
* Indicates the expression 'Range::Num(Range)' can get the size of the range at constant time
|
||||
* without modifying the range object. Modifying the range usually occurs when the iterator of
|
||||
* the range is an input iterator. Indirect calculation of the range by obtaining the iterator
|
||||
* may cause the range to become invalid, that is, the iterator cannot be obtained again.
|
||||
*/
|
||||
template <typename R>
|
||||
concept CSizedRange = CRange<R>
|
||||
&& requires(R Range)
|
||||
{
|
||||
{ Range::Num(Range) } -> CConvertibleTo<size_t>;
|
||||
};
|
||||
|
||||
/** This is an example of a sized range type, indicate the traits that define a sized range type. */
|
||||
template <CInputOrOutputIterator I, CSizedSentinelFor<I> S = ISizedSentinelFor<I>>
|
||||
struct ISizedRange /* : IRange<I, S> */
|
||||
{
|
||||
// ~Begin CRange
|
||||
|
||||
I Begin() /* const */;
|
||||
S End() /* const */;
|
||||
|
||||
// ~End CRange
|
||||
|
||||
/**
|
||||
* Get the number of elements in the range.
|
||||
* The function is optional if the range size can be computed indirectly from the iterator-sentinel pair.
|
||||
* If this function is provided so that types that satisfy CSizedRange but do not satisfy the comments
|
||||
* requirements of CSizedRange are undefined behavior, this should be resolved by specializing bDisableSizedRange.
|
||||
* If the function is const, it means that the const ISizedRange satisfies CSizedRange.
|
||||
*/
|
||||
size_t Num() /* const */;
|
||||
};
|
||||
|
||||
// Use ISizedRange<...> represents a sized range type.
|
||||
static_assert(CSizedRange<ISizedRange<IInputOrOutputIterator<int&>>>);
|
||||
|
||||
/** A concept specifies a type is a range with an input iterator. */
|
||||
template <typename R>
|
||||
concept CInputRange = CRange<R> && CInputIterator<TRangeIterator<R>>;
|
||||
|
||||
// Use IRange<IInputIterator<...>> represents an input range type.
|
||||
static_assert(CInputRange<IRange<IInputIterator<int&>>>);
|
||||
|
||||
/** A concept specifies a type is a range with an output iterator. */
|
||||
template <typename R, typename T>
|
||||
concept COutputRange = CRange<R> && COutputIterator<TRangeIterator<R>, T>;
|
||||
|
||||
// Use IRange<IOutputIterator<...>, int> represents an output range type.
|
||||
static_assert(COutputRange<IRange<IOutputIterator<int&>>, int>);
|
||||
|
||||
/** A concept specifies a type is a range with a forward iterator. */
|
||||
template <typename R>
|
||||
concept CForwardRange = CInputRange<R> && CForwardIterator<TRangeIterator<R>>;
|
||||
|
||||
// Use IRange<IForwardIterator<...>> represents a forward range type.
|
||||
static_assert(CForwardRange<IRange<IForwardIterator<int&>>>);
|
||||
|
||||
/** A concept specifies a type is a range with a bidirectional iterator. */
|
||||
template <typename R>
|
||||
concept CBidirectionalRange = CForwardRange<R> && CBidirectionalIterator<TRangeIterator<R>>;
|
||||
|
||||
// Use IRange<IBidirectionalIterator<...>> represents a bidirectional range type.
|
||||
static_assert(CBidirectionalRange<IRange<IBidirectionalIterator<int&>>>);
|
||||
|
||||
/** A concept specifies a type is a range with a random access iterator. */
|
||||
template <typename R>
|
||||
concept CRandomAccessRange = CBidirectionalRange<R> && CRandomAccessIterator<TRangeIterator<R>>;
|
||||
|
||||
// Use IRange<IRandomAccessIterator<...>> represents a random access range type.
|
||||
static_assert(CRandomAccessRange<IRange<IRandomAccessIterator<int&>>>);
|
||||
|
||||
/** A concept specifies a type is a range with a contiguous iterator. */
|
||||
template <typename R>
|
||||
concept CContiguousRange = CRandomAccessRange<R> && CContiguousIterator<TRangeIterator<R>>
|
||||
&& requires(R& Range)
|
||||
{
|
||||
{ Range::GetData(Range) } -> CSameAs<TAddPointer<TRangeReference<R>>>;
|
||||
};
|
||||
|
||||
/** This is an example of a contiguous range type, indicate the traits that define a contiguous range type. */
|
||||
template <CContiguousIterator I, CSentinelFor<I> S = ISentinelFor<I>>
|
||||
struct IContiguousRange /* : IRange<I, S> */
|
||||
{
|
||||
// ~Begin CRange
|
||||
|
||||
I Begin() /* const */;
|
||||
S End() /* const */;
|
||||
|
||||
// ~End CRange
|
||||
|
||||
/**
|
||||
* Get the pointer to the container element storage.
|
||||
* The function is optional if the range size can be computed indirectly from the iterator.
|
||||
* If the function is provided, then the expression 'ToAddress(Range::Begin(Range)) == Range::GetData(Range)'
|
||||
* must be satisfied to always be true.
|
||||
* If the function is const, it means that the const IContiguousRange satisfies CContiguousRange.
|
||||
*/
|
||||
TIteratorPointer<I> GetData() /* const */;
|
||||
};
|
||||
|
||||
// Use IContiguousRange<...> represents a contiguous range type.
|
||||
static_assert(CContiguousRange<IContiguousRange<IContiguousIterator<int&>>>);
|
||||
|
||||
/** A concept specifies a type is a range and its iterators and sentinel types are the same. */
|
||||
template <typename R>
|
||||
concept CCommonRange = CRange<R> && CSameAs<TRangeIterator<R>, TRangeSentinel<R>>;
|
||||
|
||||
/** This is an example of a common range type, indicate the traits that define a common range type. */
|
||||
template <CForwardIterator I>
|
||||
using TCommonRange = IRange<I, I>;
|
||||
|
||||
// Use TCommonRange<...> represents a common range type.
|
||||
static_assert(CCommonRange<TCommonRange<IForwardIterator<int&>>>);
|
||||
|
||||
NAMESPACE_MODULE_END(Utility)
|
||||
NAMESPACE_MODULE_END(Redcraft)
|
||||
NAMESPACE_REDCRAFT_END
|
Loading…
Reference in New Issue
Block a user