#pragma once #include "CoreTypes.h" #include "Memory/Address.h" #include "Templates/Invoke.h" #include "Templates/Utility.h" #include "TypeTraits/TypeTraits.h" #include "Miscellaneous/Iterator.h" 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; 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 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) 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 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); 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) 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) NAMESPACE_REDCRAFT_END