diff --git a/Redcraft.Utility/Source/Public/Miscellaneous/Range.h b/Redcraft.Utility/Source/Public/Miscellaneous/Range.h index 88da545..442c206 100644 --- a/Redcraft.Utility/Source/Public/Miscellaneous/Range.h +++ b/Redcraft.Utility/Source/Public/Miscellaneous/Range.h @@ -30,91 +30,9 @@ using TRangeRValueReferenceType = TRangeRValueReference; NAMESPACE_BEGIN(Range) -template requires (CClass && CSameAs>) -class TViewInterface -{ -public: - - /** @return The pointer to the underlying element storage. */ - NODISCARD FORCEINLINE constexpr auto Data() requires (CContiguousRange< T>) { return Range::GetData(static_cast< T&>(*this)); } - NODISCARD FORCEINLINE constexpr auto Data() const requires (CContiguousRange) { return Range::GetData(static_cast(*this)); } - - /** @return The reverse iterator to the first or end element. */ - NODISCARD FORCEINLINE constexpr auto Begin() requires (CRange< T>) { return Range::Begin(static_cast< T&>(*this)); } - NODISCARD FORCEINLINE constexpr auto End() requires (CRange< T>) { return Range::End (static_cast< T&>(*this)); } - NODISCARD FORCEINLINE constexpr auto Begin() const requires (CRange) { return Range::Begin(static_cast(*this)); } - NODISCARD FORCEINLINE constexpr auto End() const requires (CRange) { return Range::End (static_cast(*this)); } - - /** @return The reverse iterator to the first or end element. */ - NODISCARD FORCEINLINE constexpr auto RBegin() requires (CBidirectionalRange< T> && CCommonRange< T>) { return Range::RBegin(static_cast< T&>(*this)); } - NODISCARD FORCEINLINE constexpr auto REnd() requires (CBidirectionalRange< T> && CCommonRange< T>) { return Range::REnd (static_cast< T&>(*this)); } - NODISCARD FORCEINLINE constexpr auto RBegin() const requires (CBidirectionalRange && CCommonRange) { return Range::RBegin(static_cast(*this)); } - NODISCARD FORCEINLINE constexpr auto REnd() const requires (CBidirectionalRange && CCommonRange) { return Range::REnd (static_cast(*this)); } - - /** @return The number of elements in the container. */ - NODISCARD FORCEINLINE constexpr size_t Num() requires (CSizedRange< T>) { return Range::Num(static_cast< T&>(*this)); } - NODISCARD FORCEINLINE constexpr size_t Num() const requires (CSizedRange) { return Range::Num(static_cast(*this)); } - - /** @return true if the container is empty, false otherwise. */ - NODISCARD FORCEINLINE constexpr bool IsEmpty() requires (CSizedRange< T> || CForwardRange< T>) { return Range::IsEmpty(static_cast< T&>(*this)); } - NODISCARD FORCEINLINE constexpr bool IsEmpty() const requires (CSizedRange || CForwardRange) { return Range::IsEmpty(static_cast(*this)); } - - /** @return true if the container is empty, false otherwise. */ - NODISCARD FORCEINLINE constexpr explicit operator bool() requires (CSizedRange< T> || CForwardRange< T>) { return !Range::IsEmpty(static_cast< T&>(*this)); } - NODISCARD FORCEINLINE constexpr explicit operator bool() const requires (CSizedRange || CForwardRange) { return !Range::IsEmpty(static_cast(*this)); } - - /** @return The reference to the requested element. */ - NODISCARD FORCEINLINE constexpr decltype(auto) operator[](size_t Index) requires (CRandomAccessRange< T>) { return Range::Begin(static_cast< T&>(*this))[Index]; } - NODISCARD FORCEINLINE constexpr decltype(auto) operator[](size_t Index) const requires (CRandomAccessRange) { return Range::Begin(static_cast(*this))[Index]; } - - /** @return The reference to the first or last element. */ - NODISCARD FORCEINLINE constexpr decltype(auto) Front() requires (CForwardRange< T>) { return *Range::Begin(static_cast< T&>(*this)); } - NODISCARD FORCEINLINE constexpr decltype(auto) Front() const requires (CForwardRange) { return *Range::Begin(static_cast(*this)); } - NODISCARD FORCEINLINE constexpr decltype(auto) Back() requires (CBidirectionalRange< T> && CCommonRange< T>) { return *Range::RBegin(static_cast< T&>(*this)); } - NODISCARD FORCEINLINE constexpr decltype(auto) Back() const requires (CBidirectionalRange && CCommonRange) { return *Range::RBegin(static_cast(*this)); } - - ENABLE_RANGE_BASED_FOR_LOOP_SUPPORT - -private: - - FORCEINLINE constexpr TViewInterface() = default; - - FORCEINLINE constexpr TViewInterface(const TViewInterface&) = default; - FORCEINLINE constexpr TViewInterface(TViewInterface&&) = default; - FORCEINLINE constexpr TViewInterface& operator=(const TViewInterface&) = default; - FORCEINLINE constexpr TViewInterface& operator=(TViewInterface&&) = default; - - FORCEINLINE constexpr ~TViewInterface() = default; - - friend T; -}; - -NAMESPACE_END(Range) - -template requires (bEnableBorrowedRange) -inline constexpr bool bEnableBorrowedRange> = true; - -template -concept CView = CRange && CMovable && CDerivedFrom>>; - -NAMESPACE_PRIVATE_BEGIN - -template struct TIsInitializerList : FFalse { }; -template struct TIsInitializerList> : FTrue { }; - -NAMESPACE_PRIVATE_END - -template -concept CViewableRange = CRange - && ((CView> && CConstructibleFrom, R>) - || (!CView> && (CLValueReference || (CMovable> - && !NAMESPACE_PRIVATE::TIsInitializerList>::Value)))); - -NAMESPACE_BEGIN(Range) - /** A view type that produces a view of no elements of a particular type. */ template -class TEmptyView : public TViewInterface> +class TEmptyView : public IBasicViewInterface> { public: @@ -147,7 +65,7 @@ NAMESPACE_BEGIN(Range) /** A view type that contains exactly one element of a specified value. */ template requires (CMoveConstructible) -class TSingleView : public TViewInterface> +class TSingleView : public IBasicViewInterface> { public: @@ -198,7 +116,7 @@ static_assert( CView>); /** A view type that generates a sequence of elements by repeatedly incrementing an initial value. Can be either bounded or unbounded. */ template S = FUnreachableSentinel> requires (CSemiregular && CCopyable) -class TIotaView : public TViewInterface> +class TIotaView : public IBasicViewInterface> { private: @@ -303,7 +221,7 @@ NAMESPACE_BEGIN(Range) /** A view type that generates a sequence of elements by repeatedly producing the same value. Can be either bounded or unbounded. */ template requires (CMoveConstructible && CSameAs>) -class TRepeatView : public TViewInterface> +class TRepeatView : public IBasicViewInterface> { public: @@ -449,57 +367,9 @@ NAMESPACE_END(Range) NAMESPACE_BEGIN(Range) -/** A view adapter that combines an iterator-sentinel pair. */ -template S = I> -class TRangeView : public TViewInterface> -{ -public: - - using ElementType = TIteratorElementType; - using Reference = TIteratorReferenceType; - using Iterator = I; - using Sentinel = S; - - FORCEINLINE constexpr TRangeView() requires (CDefaultConstructible) = default; - - FORCEINLINE constexpr TRangeView(I InFirst, S InLast) : First(MoveTemp(InFirst)), Last(InLast) { } - - template requires (!CSameAs, TRangeView> - && CConvertibleTo, I> && CConvertibleTo, S>) - FORCEINLINE constexpr TRangeView(R&& InRange) : First(Range::Begin(Forward(InRange))), Last(Range::End(Forward(InRange))) { } - - NODISCARD FORCEINLINE constexpr I Begin() requires (!CCopyable) { return MoveTemp(First); } - NODISCARD FORCEINLINE constexpr S End() requires (!CCopyable) { return MoveTemp(Last); } - NODISCARD FORCEINLINE constexpr I Begin() const requires ( CCopyable) { return First; } - NODISCARD FORCEINLINE constexpr S End() const requires ( CCopyable) { return Last; } - - NODISCARD FORCEINLINE constexpr size_t Num() const requires (CSizedSentinelFor) { return Last - First; } - - NODISCARD FORCEINLINE constexpr bool IsEmpty() const { return First == Last; } - -private: - - NO_UNIQUE_ADDRESS I First; - NO_UNIQUE_ADDRESS S Last; - -}; - -template S> -TRangeView(I, S) -> TRangeView; - -template -TRangeView(R&&) -> TRangeView, TRangeSentinelType>; - -NAMESPACE_END(Range) - -template -constexpr bool bEnableBorrowedRange> = true; - -NAMESPACE_BEGIN(Range) - /** A view adapter that references the elements of some other range. */ template requires (CObject) -class TRefView : public TViewInterface> +class TRefView : public IBasicViewInterface> { public: @@ -545,7 +415,7 @@ NAMESPACE_BEGIN(Range) /** A view adapter that has unique ownership of a range. */ template requires (CMovable && !NAMESPACE_PRIVATE::TIsInitializerList::Value) -class TOwningView : public TViewInterface> +class TOwningView : public IBasicViewInterface> { public: @@ -609,7 +479,7 @@ using TAllView = /** A view adapter that consists of the elements of a range that satisfies a predicate. */ template > Pred> requires (CView && CObject && CMoveConstructible) -class TFilterView : public TViewInterface> +class TFilterView : public IBasicViewInterface> { private: @@ -752,7 +622,7 @@ static_assert( CView, decltype([](auto /** A view adapter of a sequence that applies a transformation function to each element. */ template requires (CView && CObject && CRegularInvocable> && CReferenceable>>) -class TTransformView : public TViewInterface> +class TTransformView : public IBasicViewInterface> { private: @@ -940,13 +810,6 @@ NAMESPACE_END(Range) NAMESPACE_BEGIN(Range) -/** Creates A view adapter that combines an iterator-sentinel pair. */ -template S = I> -NODISCARD FORCEINLINE constexpr TRangeView View(I First, S Last) -{ - return TRangeView(MoveTemp(First), MoveTemp(Last)); -} - /** Creates A view adapter that includes all elements of a range. */ template NODISCARD FORCEINLINE constexpr TAllView All(R&& InRange) diff --git a/Redcraft.Utility/Source/Public/Range/Range.h b/Redcraft.Utility/Source/Public/Range/Range.h index 72c0ef1..d240bf0 100644 --- a/Redcraft.Utility/Source/Public/Range/Range.h +++ b/Redcraft.Utility/Source/Public/Range/Range.h @@ -2,3 +2,4 @@ #include "CoreTypes.h" #include "Range/Utility.h" +#include "Range/View.h" diff --git a/Redcraft.Utility/Source/Public/Range/Utility.h b/Redcraft.Utility/Source/Public/Range/Utility.h index a9b85a2..0003368 100644 --- a/Redcraft.Utility/Source/Public/Range/Utility.h +++ b/Redcraft.Utility/Source/Public/Range/Utility.h @@ -212,6 +212,10 @@ 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 = diff --git a/Redcraft.Utility/Source/Public/Range/View.h b/Redcraft.Utility/Source/Public/Range/View.h new file mode 100644 index 0000000..c18f1cd --- /dev/null +++ b/Redcraft.Utility/Source/Public/Range/View.h @@ -0,0 +1,145 @@ +#pragma once + +#include "CoreTypes.h" +#include "Range/Utility.h" +#include "TypeTraits/TypeTraits.h" + +NAMESPACE_REDCRAFT_BEGIN +NAMESPACE_MODULE_BEGIN(Redcraft) +NAMESPACE_MODULE_BEGIN(Utility) + +NAMESPACE_BEGIN(Range) + +/** A helper class template for defining a view interface. Not directly instantiable. */ +template requires (CClass && CSameAs>) +class IBasicViewInterface +{ +public: + + /** @return The pointer to the underlying element storage. */ + NODISCARD FORCEINLINE constexpr auto GetData() requires (CContiguousRange< T>) { return Range::GetData(static_cast< T&>(*this)); } + NODISCARD FORCEINLINE constexpr auto GetData() const requires (CContiguousRange) { return Range::GetData(static_cast(*this)); } + + /** @return The reverse iterator to the first or end element. */ + NODISCARD FORCEINLINE constexpr auto Begin() requires (CRange< T>) { return Range::Begin(static_cast< T&>(*this)); } + NODISCARD FORCEINLINE constexpr auto End() requires (CRange< T>) { return Range::End (static_cast< T&>(*this)); } + NODISCARD FORCEINLINE constexpr auto Begin() const requires (CRange) { return Range::Begin(static_cast(*this)); } + NODISCARD FORCEINLINE constexpr auto End() const requires (CRange) { return Range::End (static_cast(*this)); } + + /** @return The reverse iterator to the first or end element. */ + NODISCARD FORCEINLINE constexpr auto RBegin() requires (CBidirectionalRange< T> && CCommonRange< T>) { return Range::RBegin(static_cast< T&>(*this)); } + NODISCARD FORCEINLINE constexpr auto REnd() requires (CBidirectionalRange< T> && CCommonRange< T>) { return Range::REnd (static_cast< T&>(*this)); } + NODISCARD FORCEINLINE constexpr auto RBegin() const requires (CBidirectionalRange && CCommonRange) { return Range::RBegin(static_cast(*this)); } + NODISCARD FORCEINLINE constexpr auto REnd() const requires (CBidirectionalRange && CCommonRange) { return Range::REnd (static_cast(*this)); } + + /** @return The number of elements in the container. */ + NODISCARD FORCEINLINE constexpr size_t Num() requires (CSizedRange< T>) { return Range::Num(static_cast< T&>(*this)); } + NODISCARD FORCEINLINE constexpr size_t Num() const requires (CSizedRange) { return Range::Num(static_cast(*this)); } + + /** @return true if the container is empty, false otherwise. */ + NODISCARD FORCEINLINE constexpr bool IsEmpty() requires (CSizedRange< T> || CForwardRange< T>) { return Range::IsEmpty(static_cast< T&>(*this)); } + NODISCARD FORCEINLINE constexpr bool IsEmpty() const requires (CSizedRange || CForwardRange) { return Range::IsEmpty(static_cast(*this)); } + + /** @return true if the container is empty, false otherwise. */ + NODISCARD FORCEINLINE constexpr explicit operator bool() requires (CSizedRange< T> || CForwardRange< T>) { return !Range::IsEmpty(static_cast< T&>(*this)); } + NODISCARD FORCEINLINE constexpr explicit operator bool() const requires (CSizedRange || CForwardRange) { return !Range::IsEmpty(static_cast(*this)); } + + /** @return The reference to the requested element. */ + NODISCARD FORCEINLINE constexpr decltype(auto) operator[](size_t Index) requires (CRandomAccessRange< T>) { return Range::Begin(static_cast< T&>(*this))[Index]; } + NODISCARD FORCEINLINE constexpr decltype(auto) operator[](size_t Index) const requires (CRandomAccessRange) { return Range::Begin(static_cast(*this))[Index]; } + + /** @return The reference to the first or last element. */ + NODISCARD FORCEINLINE constexpr decltype(auto) Front() requires (CForwardRange< T>) { return *Range::Begin(static_cast< T&>(*this)); } + NODISCARD FORCEINLINE constexpr decltype(auto) Front() const requires (CForwardRange) { return *Range::Begin(static_cast(*this)); } + NODISCARD FORCEINLINE constexpr decltype(auto) Back() requires (CBidirectionalRange< T> && CCommonRange< T>) { return *Range::RBegin(static_cast< T&>(*this)); } + NODISCARD FORCEINLINE constexpr decltype(auto) Back() const requires (CBidirectionalRange && CCommonRange) { return *Range::RBegin(static_cast(*this)); } + + ENABLE_RANGE_BASED_FOR_LOOP_SUPPORT + +private: + + FORCEINLINE constexpr IBasicViewInterface() = default; + FORCEINLINE constexpr IBasicViewInterface(const IBasicViewInterface&) = default; + FORCEINLINE constexpr IBasicViewInterface(IBasicViewInterface&&) = default; + FORCEINLINE constexpr IBasicViewInterface& operator=(const IBasicViewInterface&) = default; + FORCEINLINE constexpr IBasicViewInterface& operator=(IBasicViewInterface&&) = default; + FORCEINLINE constexpr ~IBasicViewInterface() = default; + + friend T; +}; + +NAMESPACE_END(Range) + +/** + * A concept specifies that a range is a view, that is, it has constant time copy, move and assignment. + * Specify, a view can be movable only but not copyable, or it can be both movable and copyable. + */ +template +concept CView = CRange && CMovable && CDerivedFrom>>; + +NAMESPACE_PRIVATE_BEGIN + +template struct TIsInitializerList : FFalse { }; +template struct TIsInitializerList> : FTrue { }; + +NAMESPACE_PRIVATE_END + +/** A concept specifies that a viewable range that can be converted into a view through Range::All. */ +template +concept CViewableRange = CRange + && ((CView> && CConstructibleFrom, R>) + || (!CView> && (CLValueReference || (CMovable> + && !NAMESPACE_PRIVATE::TIsInitializerList>::Value)))); + +NAMESPACE_BEGIN(Range) + +/** A simple view that combines an iterator-sentinel pair into a view. */ +template S = I> +class TRangeView : public IBasicViewInterface> +{ +public: + + using ElementType = TIteratorElementType; + + FORCEINLINE constexpr TRangeView() requires (CDefaultConstructible) = default; + + FORCEINLINE constexpr TRangeView(I InFirst, S InLast) : First(MoveTemp(InFirst)), Last(InLast) { } + + NODISCARD FORCEINLINE constexpr I Begin() requires (!CCopyable) { return MoveTemp(First); } + NODISCARD FORCEINLINE constexpr I Begin() const requires ( CCopyable) { return First; } + + NODISCARD FORCEINLINE constexpr S End() const { return Last; } + + NODISCARD FORCEINLINE constexpr size_t Num() const requires (CSizedSentinelFor) { return Last - First; } + + NODISCARD FORCEINLINE constexpr bool IsEmpty() const { return First == Last; } + +private: + + NO_UNIQUE_ADDRESS I First; + NO_UNIQUE_ADDRESS S Last; + +}; + +template S> +TRangeView(I, S) -> TRangeView; + +NAMESPACE_END(Range) + +template +constexpr bool bEnableBorrowedRange> = true; + +NAMESPACE_BEGIN(Range) + +/** Creates A simple view that combines an iterator-sentinel pair. */ +template S = I> +NODISCARD FORCEINLINE constexpr TRangeView View(I First, S Last) +{ + return TRangeView(MoveTemp(First), Last); +} + +NAMESPACE_END(Range) + +NAMESPACE_MODULE_END(Utility) +NAMESPACE_MODULE_END(Redcraft) +NAMESPACE_REDCRAFT_END