diff --git a/Redcraft.Utility/Source/Public/Miscellaneous/Range.h b/Redcraft.Utility/Source/Public/Miscellaneous/Range.h index 8d60fea..88da545 100644 --- a/Redcraft.Utility/Source/Public/Miscellaneous/Range.h +++ b/Redcraft.Utility/Source/Public/Miscellaneous/Range.h @@ -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 +using TRangeIteratorType = TRangeIterator; 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 auto Begin(initializer_list& Container) -{ - return Container.begin(); -} - -NAMESPACE_END(Range) +using TRangeSentinelType = TRangeSentinel; template -using TRangeIteratorType = 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 auto End(initializer_list& Container) -{ - return Container.end(); -} - -NAMESPACE_END(Range) +using TRangeElementType = TRangeElement; template -using TRangeSentinelType = 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, TRangeSentinelType> && 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, TRangeSentinelType> && CBidirectionalIterator>)) -NODISCARD FORCEINLINE constexpr auto REnd(T&& Container) -{ - return MakeReverseIterator(Range::Begin(Forward(Container))); -} - -NAMESPACE_END(Range) - -NAMESPACE_PRIVATE_BEGIN - -template struct TRangeElementType { using Type = typename R::ElementType; }; -template struct TRangeElementType { using Type = T; }; -template struct TRangeElementType { using Type = T; }; - -NAMESPACE_PRIVATE_END +using TRangeReferenceType = TRangeReference; template -using TRangeElementType = typename NAMESPACE_PRIVATE::TRangeElementType>::Type; - -template -using TRangeReferenceType = TIteratorReferenceType>; - -template -using TRangeRValueReferenceType = TIteratorRValueReferenceType>; - -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) - -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, TRangeSentinelType> && CForwardIterator>) -NODISCARD FORCEINLINE constexpr size_t Num(T&& Container) -{ - return Range::End(Forward(Container)) - Range::Begin(Forward(Container)); -} - -/** @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) - -template -concept CRange = - requires(R Range) - { - typename TRangeIteratorType; - typename TRangeSentinelType; - } - && CInputOrOutputIterator> - && CSentinelFor, TRangeIteratorType>; - -template -concept CBorrowedRange = CRange && (CLValueReference || bEnableBorrowedRange>); - -template -concept CSizedRange = CRange - && requires(R Range) - { - { Range::Num(Range) } -> CConvertibleTo; - }; - -template -concept CInputRange = CRange && CInputIterator>; - -template -concept COutputRange = CRange && COutputIterator, T>; - -template -concept CForwardRange = CInputRange && CForwardIterator>; - -template -concept CBidirectionalRange = CForwardRange && CBidirectionalIterator>; - -template -concept CRandomAccessRange = CBidirectionalRange && CRandomAccessIterator>; - -template -concept CContiguousRange = CRandomAccessRange && CContiguousIterator> - && requires(R& Range) - { - { Range::GetData(Range) } -> CSameAs>>; - }; - -template -concept CCommonRange = CRange && CSameAs, TRangeSentinelType>; - -static_assert(CContiguousRange); -static_assert( CCommonRange); +using TRangeRValueReferenceType = TRangeRValueReference; NAMESPACE_BEGIN(Range) diff --git a/Redcraft.Utility/Source/Public/Range/Range.h b/Redcraft.Utility/Source/Public/Range/Range.h new file mode 100644 index 0000000..72c0ef1 --- /dev/null +++ b/Redcraft.Utility/Source/Public/Range/Range.h @@ -0,0 +1,4 @@ +#pragma once + +#include "CoreTypes.h" +#include "Range/Utility.h" diff --git a/Redcraft.Utility/Source/Public/Range/Utility.h b/Redcraft.Utility/Source/Public/Range/Utility.h new file mode 100644 index 0000000..a9b85a2 --- /dev/null +++ b/Redcraft.Utility/Source/Public/Range/Utility.h @@ -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 +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 auto 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 auto 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)); +} + +/** @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. + */ +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 iterators 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 TCommonRange = IRange; + +// Use TCommonRange<...> represents a common range type. +static_assert(CCommonRange>>); + +NAMESPACE_MODULE_END(Utility) +NAMESPACE_MODULE_END(Redcraft) +NAMESPACE_REDCRAFT_END