#pragma once #include "CoreTypes.h" #include "TypeTraits/TypeTraits.h" #include "Templates/Utility.h" #include "Iterator/Utility.h" #include "Iterator/BasicIterator.h" #include "Iterator/Sentinel.h" #include "Iterator/ReverseIterator.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 inline constexpr bool bEnableBorrowedRange = false; NAMESPACE_BEGIN(Range) /** @return The iterator to the beginning of a container. */ template requires ((CLValueReference || bEnableBorrowedRange>) && requires(T&& Container) { { Container.Begin() } -> CInputOrOutputIterator; }) NODISCARD FORCEINLINE constexpr auto Begin(T&& Container) { return Container.Begin(); } /** Overloads the Begin algorithm for arrays. */ template requires ((CLValueReference || bEnableBorrowedRange>) && CArray>) NODISCARD FORCEINLINE constexpr auto Begin(T&& Container) { return Container + 0; } /** Overloads the Begin algorithm for initializer_list. */ template NODISCARD FORCEINLINE constexpr const T* Begin(initializer_list& Container) { return Container.begin(); } NAMESPACE_END(Range) template using TRangeIterator = decltype(Range::Begin(DeclVal())); NAMESPACE_BEGIN(Range) /** @return The iterator to the end of a container. */ template requires ((CLValueReference || bEnableBorrowedRange>) && requires(T&& Container) { { Container.End() } -> CSentinelFor>; }) NODISCARD FORCEINLINE constexpr auto End(T&& Container) { return Container.End(); } /** Overloads the End algorithm for arrays. */ template requires ((CLValueReference || bEnableBorrowedRange>) && CBoundedArray>) NODISCARD FORCEINLINE constexpr auto End(T&& Container) { return Container + TExtent>; } /** Overloads the End algorithm for initializer_list. */ template NODISCARD FORCEINLINE constexpr const T* End(initializer_list& Container) { return Container.end(); } NAMESPACE_END(Range) template using TRangeSentinel = decltype(Range::End(DeclVal())); NAMESPACE_BEGIN(Range) /** @return The reverse iterator to the beginning of a container. */ template requires ((CLValueReference || bEnableBorrowedRange>) && requires(T&& Container) { { Container.RBegin() } -> CInputOrOutputIterator; }) NODISCARD FORCEINLINE constexpr auto RBegin(T&& Container) { return Container.RBegin(); } /** Overloads the RBegin algorithm for synthesized. */ template requires ((CLValueReference || bEnableBorrowedRange>) && !requires(T&& Container) { { Container.RBegin() } -> CInputOrOutputIterator; } && (CSameAs, TRangeSentinel> && CBidirectionalIterator>)) NODISCARD FORCEINLINE constexpr auto RBegin(T&& Container) { return MakeReverseIterator(Range::End(Forward(Container))); } /** @return The reverse iterator to the end of a container. */ template requires ((CLValueReference || bEnableBorrowedRange>) && requires(T&& Container) { { Container.REnd() } -> CSentinelFor()))>; }) NODISCARD FORCEINLINE constexpr auto REnd(T&& Container) { return Container.REnd(); } /** Overloads the REnd algorithm for synthesized. */ template requires ((CLValueReference || bEnableBorrowedRange>) && !requires(T&& Container) { { Container.REnd() } -> CSentinelFor()))>; } && (CSameAs, TRangeSentinel> && CBidirectionalIterator>)) NODISCARD FORCEINLINE constexpr auto REnd(T&& Container) { return MakeReverseIterator(Range::Begin(Forward(Container))); } NAMESPACE_END(Range) template using TRangeElement = TIteratorElement>; template using TRangePointer = TIteratorPointer>; template using TRangeReference = TIteratorReference>; template using TRangeRValueReference = TIteratorRValueReference>; NAMESPACE_BEGIN(Range) /** @return The pointer to the container element storage. */ template requires ((CLValueReference || bEnableBorrowedRange>) && requires(T&& Container) { { Container.GetData() } -> CSameAs>>; }) NODISCARD FORCEINLINE constexpr auto GetData(T&& Container) { return Container.GetData(); } /** Overloads the GetData algorithm for synthesized. */ template requires ((CLValueReference || bEnableBorrowedRange>) && !requires(T&& Container) { { Container.GetData() } -> CSameAs>>; } && requires(T&& Container) { { Range::Begin(Forward(Container)) } -> CContiguousIterator; }) NODISCARD FORCEINLINE constexpr auto GetData(T&& Container) { return ToAddress(Range::Begin(Forward(Container))); } NAMESPACE_END(Range) /** Disable the CSizedRange concept for specific types. */ template inline constexpr bool bDisableSizedRange = false; NAMESPACE_BEGIN(Range) /** @return The number of elements in the container. */ template requires (!bDisableSizedRange> && requires(T&& Container) { { Container.Num() } -> CSameAs; }) NODISCARD FORCEINLINE constexpr size_t Num(T&& Container) { return Container.Num(); } /** Overloads the Num algorithm for arrays. */ template requires (!bDisableSizedRange> && CBoundedArray>) NODISCARD FORCEINLINE constexpr size_t Num(T&& Container) { return TExtent>; } /** Overloads the Num algorithm for synthesized. */ template requires (!bDisableSizedRange> && !requires(T&& Container) { { Container.Num() } -> CSameAs; } && !CBoundedArray> && CSizedSentinelFor, TRangeIterator> && CForwardIterator>) NODISCARD FORCEINLINE constexpr size_t Num(T&& Container) { return Range::End(Forward(Container)) - Range::Begin(Forward(Container)); } /** Overloads the Num algorithm for initializer_list. */ template NODISCARD FORCEINLINE constexpr size_t Num(initializer_list& Container) { return Container.size(); } /** @return true if the container is empty, false otherwise. */ template requires (requires(T&& Container) { { Container.IsEmpty() } -> CBooleanTestable; }) NODISCARD FORCEINLINE constexpr bool IsEmpty(T&& Container) { return Container.IsEmpty(); } /** Overloads the IsEmpty algorithm for synthesized. */ template requires ((CBoundedArray> || requires(T&& Container) { { Container.Num() } -> CSameAs; }) && !requires(T&& Container) { { Container.IsEmpty() } -> CBooleanTestable; }) NODISCARD FORCEINLINE constexpr bool IsEmpty(T&& Container) { return Range::Num(Forward(Container)) == 0; } /** Overloads the IsEmpty algorithm for synthesized. */ template requires (!CBoundedArray> && !requires(T&& Container) { { Container.Num() } -> CSameAs; } && !requires(T&& Container) { { Container.IsEmpty() } -> CBooleanTestable; } && CForwardIterator>) NODISCARD FORCEINLINE constexpr bool IsEmpty(T&& Container) { return Range::End(Forward(Container)) == Range::Begin(Forward(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. * This concept does not require that iterator-sentinel pair can be fetched multiple times * from the range object. again this means that const R may not be a range if R is a range, * e.g. fetching the iterator-sentinel pair from the input range may require moving the iterator * directly from the range object and thus the range object may be modified. */ template concept CRange = requires(R Range) { typename TRangeIterator; typename TRangeSentinel; } && CInputOrOutputIterator> && CSentinelFor, TRangeIterator>; /** This is an example of a range type, indicate the traits that define a range type. */ template S = ISentinelFor> 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>>); /** * 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 concept CBorrowedRange = CRange && (CLValueReference || bEnableBorrowedRange>); /** * 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 concept CSizedRange = CRange && requires(R Range) { { Range::Num(Range) } -> CConvertibleTo; }; /** This is an example of a sized range type, indicate the traits that define a sized range type. */ template S = ISizedSentinelFor> struct ISizedRange /* : IRange */ { // ~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>>); /** A concept specifies a type is a range with an input iterator. */ template concept CInputRange = CRange && CInputIterator>; // Use IRange> represents an input range type. static_assert(CInputRange>>); /** A concept specifies a type is a range with an output iterator. */ template concept COutputRange = CRange && COutputIterator, T>; // Use IRange, int> represents an output range type. static_assert(COutputRange>, int>); /** A concept specifies a type is a range with a forward iterator. */ template concept CForwardRange = CInputRange && CForwardIterator>; // Use IRange> represents a forward range type. static_assert(CForwardRange>>); /** A concept specifies a type is a range with a bidirectional iterator. */ template concept CBidirectionalRange = CForwardRange && CBidirectionalIterator>; // Use IRange> represents a bidirectional range type. static_assert(CBidirectionalRange>>); /** A concept specifies a type is a range with a random access iterator. */ template concept CRandomAccessRange = CBidirectionalRange && CRandomAccessIterator>; // Use IRange> represents a random access range type. static_assert(CRandomAccessRange>>); /** A concept specifies a type is a range with a contiguous iterator. */ template concept CContiguousRange = CRandomAccessRange && CContiguousIterator> && requires(R& Range) { { Range::GetData(Range) } -> CSameAs>>; }; /** This is an example of a contiguous range type, indicate the traits that define a contiguous range type. */ template S = ISentinelFor> struct IContiguousRange /* : IRange */ { // ~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 GetData() /* const */; }; // Use IContiguousRange<...> represents a contiguous range type. static_assert(CContiguousRange>>); /** A concept specifies a type is a range and its iterator and sentinel types are the same. */ template concept CCommonRange = CRange && CSameAs, TRangeSentinel>; /** This is an example of a common range type, indicate the traits that define a common range type. */ template using ICommonRange = IRange; // Use TCommonRange<...> represents a common range type. static_assert(CCommonRange>>); NAMESPACE_MODULE_END(Utility) NAMESPACE_MODULE_END(Redcraft) NAMESPACE_REDCRAFT_END