From ba9d35c1ff904516416898c043c9e7a866b96bc7 Mon Sep 17 00:00:00 2001 From: Redstone1024 <2824517378@qq.com> Date: Sun, 8 Dec 2024 20:44:48 +0800 Subject: [PATCH] feat(miscellaneous): add TViewInterface with basic view and other range tools --- .../Source/Public/Miscellaneous/Range.h | 224 ++++++++++++++++-- 1 file changed, 210 insertions(+), 14 deletions(-) diff --git a/Redcraft.Utility/Source/Public/Miscellaneous/Range.h b/Redcraft.Utility/Source/Public/Miscellaneous/Range.h index 3fa6da0..19dbcbd 100644 --- a/Redcraft.Utility/Source/Public/Miscellaneous/Range.h +++ b/Redcraft.Utility/Source/Public/Miscellaneous/Range.h @@ -2,6 +2,7 @@ #include "CoreTypes.h" #include "Memory/Address.h" +#include "Templates/Invoke.h" #include "Templates/Utility.h" #include "TypeTraits/TypeTraits.h" #include "Miscellaneous/Iterator.h" @@ -10,6 +11,8 @@ 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 inline constexpr bool bEnableBorrowedRange = false; @@ -33,7 +36,7 @@ NODISCARD FORCEINLINE constexpr auto Begin(T&& Container) /** Overloads the Begin algorithm for initializer_list. */ template -NODISCARD FORCEINLINE constexpr auto Begin(initializer_list Container) +NODISCARD FORCEINLINE constexpr auto Begin(initializer_list& Container) { return Container.begin(); } @@ -63,7 +66,7 @@ NODISCARD FORCEINLINE constexpr auto End(T&& Container) /** Overloads the End algorithm for initializer_list. */ template -NODISCARD FORCEINLINE constexpr auto End(initializer_list Container) +NODISCARD FORCEINLINE constexpr auto End(initializer_list& Container) { return Container.end(); } @@ -89,7 +92,7 @@ template requires ((CLValueReference || bEnableBorrowedRange, TRangeSentinelType> && CBidirectionalIterator>)) NODISCARD FORCEINLINE constexpr auto RBegin(T&& Container) { - return MakeReverseIterator(Range::End(Container)); + return MakeReverseIterator(Range::End(Forward(Container))); } /** @return The reverse iterator to the end of a container. */ @@ -106,13 +109,21 @@ template requires ((CLValueReference || bEnableBorrowedRange, TRangeSentinelType> && CBidirectionalIterator>)) NODISCARD FORCEINLINE constexpr auto REnd(T&& Container) { - return MakeReverseIterator(Range::Begin(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 + template -using TRangeElementType = TIteratorElementType>; +using TRangeElementType = typename NAMESPACE_PRIVATE::TRangeElementType>::Type; template using TRangeReferenceType = TIteratorReferenceType>; @@ -168,7 +179,33 @@ template requires (!bDisableSizedRange> && CSizedSentinelFor, TRangeSentinelType> && CForwardIterator>) NODISCARD FORCEINLINE constexpr size_t Num(T&& Container) { - return Range::End(Container) - Range::Begin(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) @@ -193,12 +230,6 @@ concept CSizedRange = CRange { Range::Num(Range) } -> CConvertibleTo; }; -template -inline constexpr bool bEnableView = false; - -template -concept CView = CRange && CMovable && bEnableView; - template concept CInputRange = CRange && CInputIterator>; @@ -218,12 +249,84 @@ template concept CContiguousRange = CRandomAccessRange && CContiguousIterator> && requires(R& Range) { - { Range::GetData(Range) } -> CSameAs>>; + { Range::GetData(Range) } -> CSameAs>>; }; template concept CCommonRange = CRange && CSameAs, TRangeSentinelType>; +static_assert(CContiguousRange); +static_assert( CCommonRange); + +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 { }; @@ -237,7 +340,100 @@ concept CViewableRange = CRange || (!CView> && (CLValueReference || CMovable> && !NAMESPACE_PRIVATE::TIsInitializerList>::Value))); -static_assert(CRange && CContiguousRange && CCommonRange); +NAMESPACE_BEGIN(Range) + +template +class TEmptyView : public TViewInterface> +{ +public: + + using ElementType = T; + using Reference = T&; + using Iterator = T*; + using Sentinel = T*; + + using ReverseIterator = TReverseIterator; + + FORCEINLINE constexpr TEmptyView() = default; + + NODISCARD static FORCEINLINE constexpr Iterator Begin() { return nullptr; } + NODISCARD static FORCEINLINE constexpr Sentinel End() { return nullptr; } + NODISCARD static FORCEINLINE constexpr T* GetData() { return nullptr; } + NODISCARD static FORCEINLINE constexpr size_t Num() { return 0; } + NODISCARD static FORCEINLINE constexpr bool IsEmpty() { return true; } + +}; + +static_assert(CContiguousRange>); +static_assert( CCommonRange>); +static_assert( CView>); + +NAMESPACE_END(Range) + +template +constexpr bool bEnableBorrowedRange> = true; + +NAMESPACE_BEGIN(Range) + +template requires (CMoveConstructible) +class TSingleView : public TViewInterface> +{ +public: + + using ElementType = T; + + using Reference = T&; + using ConstReference = const T&; + + using Iterator = T*; + using ConstIterator = const T*; + + using Sentinel = T*; + using ConstSentinel = const T*; + + using ReverseIterator = TReverseIterator< Iterator>; + using ConstReverseIterator = TReverseIterator; + + FORCEINLINE constexpr TSingleView() requires (CDefaultConstructible) = default; + + FORCEINLINE constexpr explicit TSingleView(const T& InValue) requires (CCopyConstructible) : Value(InValue) { } + + FORCEINLINE constexpr explicit TSingleView(T&& InValue) : Value(MoveTemp(InValue)) { } + + template requires (CConstructibleFrom) + FORCEINLINE explicit TSingleView(FInPlace, Ts&&... Args) : Value(Forward(Args)...) { } + + FORCEINLINE constexpr Iterator Begin() { return GetData(); } + FORCEINLINE constexpr ConstIterator Begin() const { return GetData(); } + FORCEINLINE constexpr Sentinel End() { return GetData() + 1; } + FORCEINLINE constexpr ConstSentinel End() const { return GetData() + 1; } + + NODISCARD FORCEINLINE constexpr T* GetData() { return AddressOf(Value); } + NODISCARD FORCEINLINE constexpr const T* GetData() const { return AddressOf(Value); } + + NODISCARD static FORCEINLINE constexpr size_t Num() { return 1; } + NODISCARD static FORCEINLINE constexpr bool IsEmpty() { return false; } + +private: + + NO_UNIQUE_ADDRESS T Value; + +}; + +template +TSingleView(T) -> TSingleView; + +static_assert(CContiguousRange>); +static_assert( CCommonRange>); +static_assert( CView>); + +NAMESPACE_END(Range) + +template requires (CRange>) +NODISCARD FORCEINLINE constexpr auto operator|(R&& Range, T&& View) +{ + return Invoke(Forward(View), Forward(Range)); +} NAMESPACE_MODULE_END(Utility) NAMESPACE_MODULE_END(Redcraft)