#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 using TWithReference = T&; template struct TIteratorElementImpl { }; template struct TIteratorElementImpl { using Type = TRemoveCV; }; template requires (requires { typename I::ElementType; }) struct TIteratorElementImpl { using Type = typename I::ElementType; }; template struct TIteratorPointerImpl { }; template struct TIteratorPointerImpl { using Type = T*; }; template requires (requires(I& Iter) { { Iter.operator->() } -> CPointer; }) struct TIteratorPointerImpl { using Type = decltype(DeclVal().operator->()); }; NAMESPACE_PRIVATE_END template concept CReferenceable = requires { typename NAMESPACE_PRIVATE::TWithReference; }; template concept CDereferenceable = requires(T& A) { { *A } -> CReferenceable; }; template using TIteratorElement = typename NAMESPACE_PRIVATE::TIteratorElementImpl>::Type; template using TIteratorPointer = typename NAMESPACE_PRIVATE::TIteratorPointerImpl>::Type; template using TIteratorReference = decltype(*DeclVal()); template requires (requires(I& Iter) { { MoveTemp(*Iter) } -> CReferenceable; }) using TIteratorRValueReference = decltype(MoveTemp(*DeclVal())); NAMESPACE_PRIVATE_BEGIN template concept CIndirectlyReadable = requires(const I Iter) { typename TIteratorElement; typename TIteratorReference; typename TIteratorRValueReference; { *Iter } -> CSameAs>; { MoveTemp(*Iter) } -> CSameAs>; } && CSameAs, TRemoveCVRef>> && CCommonReference&&, TIteratorElement&> && CCommonReference&&, TIteratorRValueReference&&> && CCommonReference&&, const TIteratorElement&>; NAMESPACE_PRIVATE_END /** A concept specifies a type is indirectly readable by expression '*Iter'. */ template concept CIndirectlyReadable = NAMESPACE_PRIVATE::CIndirectlyReadable>; /** This is an example of an indirectly readable type, indicate the traits that define an indirectly readable type. */ template 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; /** * 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 represents an indirectly readable type and int is the regular element type. static_assert(CIndirectlyReadable> && CRegular); // The CIndirectlyReadable requires this code is valid. static_assert( requires(IIndirectlyReadable Iter, int& A) { A = *Iter; } ); /** A concept specifies a type is indirectly writable by expression '*Iter = A'. */ template concept CIndirectlyWritable = requires(I&& Iter, T&& A) { *Iter = Forward(A); *Forward(Iter) = Forward(A); const_cast&&>(*Iter) = Forward(A); const_cast&&>(*Forward(Iter)) = Forward(A); }; /** This is an example of an indirectly writable type, indicate the traits that define an indirectly writable type. */ template 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 represents an indirectly writable type and int is the regular element type. static_assert(CIndirectlyWritable, int> && CRegular); // The CIndirectlyWritable requires this code is valid. static_assert( requires(IIndirectlyWritable Iter, int& A) { *Iter = A; } ); /** A concept specifies a type is incrementable by expression '++Iter' and the type must be movable. */ template concept CWeaklyIncrementable = CMovable && requires(I Iter) { { ++Iter } -> CSameAs; 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); /** * 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 concept CIncrementable = CRegular && CWeaklyIncrementable && requires(I Iter) { { Iter++ } -> CSameAs; }; /** * 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); /** * 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 concept CInputOrOutputIterator = CWeaklyIncrementable && 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 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>); /** A concept specifies a type is an input iterator. */ template concept CInputIterator = CInputOrOutputIterator && CIndirectlyReadable; /** This is an example of an input iterator, indicate the traits that define an input iterator. */ template struct IInputIterator /* : IInputOrOutputIterator, IIndirectlyReadable */ { // ~Begin CIndirectlyReadable. using ElementType = TRemoveCVRef; // ~End CIndirectlyReadable. // ~Begin CInputOrOutputIterator. IInputIterator(IInputIterator&&); IInputIterator* operator=(IInputIterator&&); T operator*() const; // Also satisfies CIndirectlyReadable. IInputIterator& operator++(); void operator++(int); // ~End CInputOrOutputIterator. }; // Use IInputIterator represents an input iterator and int is the regular element type. static_assert(CInputIterator> && CRegular); // The CInputIterator requires this code is valid. static_assert( requires(IInputIterator 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 concept COutputIterator = CInputOrOutputIterator && CIndirectlyWritable && requires(I Iter) { { Iter++ } -> CIndirectlyWritable; }; /** This is an example of an output iterator, indicate the traits that define an output iterator. */ template struct IOutputIterator /* : IInputOrOutputIterator, IIndirectlyWritable */ { // ~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 is also valid. * Also satisfies CIndirectlyWritable. */ IIndirectlyWritable operator++(int); // ~End CIndirectlyWritable. }; // Use IOutputIterator represents an output iterator and int is the regular element type. static_assert(COutputIterator, int> && CRegular); // The CInputIterator requires this code is valid. static_assert( requires(IOutputIterator 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