diff --git a/Redcraft.Utility/Source/Public/Miscellaneous/Range.h b/Redcraft.Utility/Source/Public/Miscellaneous/Range.h index 6a16e11..8d60fea 100644 --- a/Redcraft.Utility/Source/Public/Miscellaneous/Range.h +++ b/Redcraft.Utility/Source/Public/Miscellaneous/Range.h @@ -337,8 +337,8 @@ NAMESPACE_PRIVATE_END template concept CViewableRange = CRange && ((CView> && CConstructibleFrom, R>) - || (!CView> && (CLValueReference || CMovable> - && !NAMESPACE_PRIVATE::TIsInitializerList>::Value))); + || (!CView> && (CLValueReference || (CMovable> + && !NAMESPACE_PRIVATE::TIsInitializerList>::Value)))); NAMESPACE_BEGIN(Range) @@ -365,6 +365,7 @@ public: static_assert(CContiguousRange>); static_assert( CCommonRange>); +static_assert( CSizedRange>); static_assert( CView>); NAMESPACE_END(Range) @@ -422,6 +423,7 @@ TSingleView(T) -> TSingleView; static_assert(CContiguousRange>); static_assert( CCommonRange>); +static_assert( CSizedRange>); static_assert( CView>); /** A view type that generates a sequence of elements by repeatedly incrementing an initial value. Can be either bounded or unbounded. */ @@ -456,7 +458,7 @@ public: NODISCARD FORCEINLINE constexpr Sentinel End() const { return Sentinel(Last); } - NODISCARD FORCEINLINE constexpr auto Num() const requires ((CIntegral && CIntegral) || CSizedSentinelFor) { return Last - First; } + NODISCARD FORCEINLINE constexpr size_t Num() const requires ((CIntegral && CIntegral) || CSizedSentinelFor) { return Last - First; } NODISCARD FORCEINLINE constexpr bool IsEmpty() const { return First == Last; } @@ -627,6 +629,7 @@ TRepeatView(W, size_t) -> TRepeatView; static_assert(CRandomAccessRange>); static_assert( CCommonRange>); +static_assert( CSizedRange>); static_assert( CView>); NAMESPACE_END(Range) @@ -674,6 +677,549 @@ NODISCARD FORCEINLINE constexpr TRepeatView, false> Repeat(W&& Value, 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> +{ +public: + + using ElementType = TRangeElementType; + using Reference = TRangeReferenceType; + using Iterator = TRangeIteratorType; + using Sentinel = TRangeSentinelType; + + template requires (!CSameAs, TRefView> && CConvertibleTo && CLValueReference) + FORCEINLINE constexpr TRefView(T&& InRange) : Ptr(AddressOf(static_cast(Forward(InRange)))) { } + + NODISCARD FORCEINLINE constexpr Iterator Begin() const { return Range::Begin(*Ptr); } + NODISCARD FORCEINLINE constexpr Sentinel End() const { return Range::End (*Ptr); } + + NODISCARD FORCEINLINE constexpr auto GetData() const requires (CContiguousRange) { return Range::GetData(*Ptr); } + + NODISCARD FORCEINLINE constexpr size_t Num() const requires (CSizedRange) { return Range::Num(*Ptr); } + + NODISCARD FORCEINLINE constexpr bool IsEmpty() const requires (requires(R* Ptr) { Range::IsEmpty(*Ptr); }) { return Range::IsEmpty(*Ptr); } + + NODISCARD FORCEINLINE constexpr R& GetBase() const { return *Ptr; } + +private: + + R* Ptr; + +}; + +template +TRefView(R&) -> TRefView; + +static_assert(CContiguousRange>>); +static_assert( CCommonRange>>); +static_assert( CSizedRange>>); +static_assert( CView>>); + +NAMESPACE_END(Range) + +template +constexpr bool bEnableBorrowedRange> = true; + +NAMESPACE_BEGIN(Range) + +/** A view adapter that has unique ownership of a range. */ +template requires (CMovable && !NAMESPACE_PRIVATE::TIsInitializerList::Value) +class TOwningView : public TViewInterface> +{ +public: + + using ElementType = TRangeElementType; + using Reference = TRangeReferenceType; + using Iterator = TRangeIteratorType; + using Sentinel = TRangeSentinelType; + + FORCEINLINE constexpr TOwningView() requires (CDefaultConstructible) = default; + + FORCEINLINE constexpr TOwningView(const TOwningView&) = delete; + FORCEINLINE constexpr TOwningView(TOwningView&&) = default; + + FORCEINLINE constexpr TOwningView(R&& InRange) : Base(MoveTemp(InRange)) { } + + FORCEINLINE constexpr TOwningView& operator=(const TOwningView&) = delete; + FORCEINLINE constexpr TOwningView& operator=(TOwningView&&) = default; + + NODISCARD FORCEINLINE constexpr Iterator Begin() { return Range::Begin(Base); } + NODISCARD FORCEINLINE constexpr Sentinel End() { return Range::End (Base); } + NODISCARD FORCEINLINE constexpr Iterator Begin() const requires (CRange) { return Range::Begin(Base); } + NODISCARD FORCEINLINE constexpr Sentinel End() const requires (CRange) { return Range::End (Base); } + + NODISCARD FORCEINLINE constexpr auto GetData() requires (CContiguousRange< R>) { return Range::GetData(Base); } + NODISCARD FORCEINLINE constexpr auto GetData() const requires (CContiguousRange) { return Range::GetData(Base); } + + NODISCARD FORCEINLINE constexpr size_t Num() requires (CSizedRange< R>) { return Range::Num(Base); } + NODISCARD FORCEINLINE constexpr size_t Num() const requires (CSizedRange) { return Range::Num(Base); } + + NODISCARD FORCEINLINE constexpr bool IsEmpty() requires (requires( R Base) { Range::IsEmpty(Base); }) { return Range::IsEmpty(Base); } + NODISCARD FORCEINLINE constexpr bool IsEmpty() const requires (requires(const R Base) { Range::IsEmpty(Base); }) { return Range::IsEmpty(Base); } + + NODISCARD FORCEINLINE constexpr R& GetBase() & { return Base; } + NODISCARD FORCEINLINE constexpr R&& GetBase() && { return MoveTemp(Base); } + NODISCARD FORCEINLINE constexpr const R& GetBase() const& { return AsConst(Base); } + NODISCARD FORCEINLINE constexpr const R&& GetBase() const&& { return MoveTemp(AsConst(Base)); } + +private: + + NO_UNIQUE_ADDRESS R Base; + +}; + +static_assert(CContiguousRange>>); +static_assert( CCommonRange>>); +static_assert( CSizedRange>>); +static_assert( CView>>); + +NAMESPACE_END(Range) + +template +constexpr bool bEnableBorrowedRange> = bEnableBorrowedRange; + +NAMESPACE_BEGIN(Range) + +/** A view adapter that includes all elements of a range. */ +template +using TAllView = + TConditional>, TDecay, + TConditional, TRefView>, TOwningView>>>; + +/** 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> +{ +private: + + class FSentinelImpl; + +public: + + using ElementType = TRangeElementType; + + using Reference = TRangeReferenceType; + + class Iterator; + + using Sentinel = TConditional, Iterator, FSentinelImpl>; + + FORCEINLINE constexpr TFilterView() requires (CDefaultConstructible && CDefaultConstructible) = default; + + FORCEINLINE constexpr explicit TFilterView(V InBase, Pred InPredicate) : Base(MoveTemp(InBase)), Predicate(MoveTemp(InPredicate)) { } + + NODISCARD FORCEINLINE constexpr Iterator Begin() + { + Iterator Iter(*this, Range::Begin(Base)); + + do + { + if (Iter == End()) break; + + if (InvokeResult(GetPredicate(), *Iter)) break; + + ++Iter; + } + while (false); + + if constexpr (!CForwardRange) return MoveTemp(Iter); + + return Iter; + } + + NODISCARD FORCEINLINE constexpr Sentinel End() { return Sentinel(*this, Range::End(Base)); } + + NODISCARD FORCEINLINE constexpr V GetBase() const& requires (CCopyConstructible) { return Base; } + NODISCARD FORCEINLINE constexpr V GetBase() && { return MoveTemp(Base); } + + NODISCARD FORCEINLINE constexpr const Pred& GetPredicate() const { return Predicate; } + +private: + + NO_UNIQUE_ADDRESS V Base; + + NO_UNIQUE_ADDRESS Pred Predicate; + +public: + + class Iterator final + { + + public: + + using ElementType = TIteratorElementType>; + + FORCEINLINE constexpr Iterator() requires (CDefaultConstructible>) = default; + + NODISCARD friend FORCEINLINE constexpr bool operator==(const Iterator& LHS, const Iterator& RHS) + { + return LHS.Current == RHS.Current; + } + + NODISCARD FORCEINLINE constexpr TRangeReferenceType operator*() const { return *Current; } + NODISCARD FORCEINLINE constexpr TRangeIteratorType operator->() const { return Current; } + + FORCEINLINE constexpr Iterator& operator++() + { + do ++Current; while (*this != Owner->End() && !InvokeResult(Owner->GetPredicate(), *Current)); + + return *this; + } + + FORCEINLINE constexpr Iterator& operator--() requires (CBidirectionalIterator>) + { + do --Current; while (!InvokeResult(Owner->GetPredicate(), *Current)); + + return *this; + } + + FORCEINLINE constexpr void operator++(int) { Current++; } + FORCEINLINE constexpr Iterator operator++(int) requires (CForwardIterator>) { return Iterator(Owner, Current++); } + FORCEINLINE constexpr Iterator operator--(int) requires (CBidirectionalIterator>) { return Iterator(Owner, Current--); } + + friend FORCEINLINE void IndirectlyCopy(const Iterator& Iter, const Iterator& Jter) requires (CIndirectlyCopyable , TRangeIteratorType>) { IndirectlyCopy(Iter.Current, Jter.Current); } + friend FORCEINLINE void IndirectlyMove(const Iterator& Iter, const Iterator& Jter) requires (CIndirectlyMovable , TRangeIteratorType>) { IndirectlyMove(Iter.Current, Jter.Current); } + friend FORCEINLINE void IndirectlySwap(const Iterator& Iter, const Iterator& Jter) requires (CIndirectlySwappable, TRangeIteratorType>) { IndirectlySwap(Iter.Current, Jter.Current); } + + NODISCARD FORCEINLINE constexpr const TRangeIteratorType& GetBase() const& { return Current; } + NODISCARD FORCEINLINE constexpr TRangeIteratorType GetBase() && { return MoveTemp(Current); } + + private: + + TFilterView* Owner; + + NO_UNIQUE_ADDRESS TRangeIteratorType Current; + + FORCEINLINE constexpr Iterator(TFilterView& InOwner, TRangeIteratorType InCurrent) : Owner(&InOwner), Current(MoveTemp(InCurrent)) { } + + friend FSentinelImpl; + + friend TFilterView; + }; + +private: + + class FSentinelImpl final + { + public: + + FORCEINLINE constexpr FSentinelImpl() requires (CDefaultConstructible>) = default; + + NODISCARD FORCEINLINE constexpr bool operator==(const Iterator& InValue) const& { return Current == InValue.Current; } + + NODISCARD FORCEINLINE constexpr const TRangeIteratorType& GetBase() const& { return Current; } + NODISCARD FORCEINLINE constexpr TRangeIteratorType GetBase() && { return MoveTemp(Current); } + + private: + + TRangeSentinelType Current; + + FORCEINLINE constexpr FSentinelImpl(TFilterView& InOwner, TRangeSentinelType InCurrent) : Current(InCurrent) { } + + friend TFilterView; + }; + +}; + +template +TFilterView(R&&, Pred) -> TFilterView, Pred>; + +static_assert(CBidirectionalRange, decltype([](auto) { return true; })>>); +static_assert( CCommonRange, decltype([](auto) { return true; })>>); +static_assert( CView, decltype([](auto) { return true; })>>); + +/** A view adapter of a sequence that applies a transformation function to each element. */ +template requires (CView && CObject + && CRegularInvocable> && CReferenceable>>) +class TTransformView : public TViewInterface> +{ +private: + + template class FIteratorImpl; + template class FSentinelImpl; + +public: + + using ElementType = TRemoveReference>>; + + FORCEINLINE constexpr TTransformView() requires (CDefaultConstructible&& CDefaultConstructible) = default; + + FORCEINLINE constexpr explicit TTransformView(V InBase, F InFunc) : Base(MoveTemp(InBase)), Func(MoveTemp(InFunc)) { } + + NODISCARD FORCEINLINE constexpr FIteratorImpl Begin() + { + return FIteratorImpl(*this, Range::Begin(Base)); + } + + NODISCARD FORCEINLINE constexpr FIteratorImpl Begin() const + requires (CRange && CRegularInvocable>) + { + return FIteratorImpl(*this, Range::Begin(Base)); + } + + NODISCARD FORCEINLINE constexpr FSentinelImpl End() + { + return FSentinelImpl(*this, Range::End(Base)); + } + + NODISCARD FORCEINLINE constexpr FIteratorImpl End() requires (CCommonRange) + { + return FIteratorImpl(*this, Range::End(Base)); + } + + NODISCARD FORCEINLINE constexpr FSentinelImpl End() const + requires (CRange && CRegularInvocable>) + { + return FSentinelImpl(*this, Range::End(Base)); + } + + NODISCARD FORCEINLINE constexpr FIteratorImpl End() const + requires (CCommonRange && CRegularInvocable>) + { + return FIteratorImpl(*this, Range::End(Base)); + } + + NODISCARD FORCEINLINE constexpr size_t Num() requires CSizedRange< V> { return Range::Num(Base); } + NODISCARD FORCEINLINE constexpr size_t Num() const requires CSizedRange { return Range::Num(Base); } + + NODISCARD FORCEINLINE constexpr V GetBase() const& requires (CCopyConstructible) { return Base; } + NODISCARD FORCEINLINE constexpr V GetBase() && { return MoveTemp(Base); } + +private: + + NO_UNIQUE_ADDRESS V Base; + NO_UNIQUE_ADDRESS F Func; + + template + class FIteratorImpl + { + private: + + using FOwner = TConditional; + using FBase = TConditional; + using FFunc = TConditional; + + public: + + using ElementType = TRemoveCVRef>>; + + FORCEINLINE constexpr FIteratorImpl() requires (CDefaultConstructible>) = default; + + FORCEINLINE constexpr FIteratorImpl(FIteratorImpl Iter) requires (bConst && CConvertibleTo, TRangeIteratorType>) + : Owner(Iter.Owner), Current(MoveTemp(Iter.Current)) + { } + + NODISCARD friend FORCEINLINE constexpr bool operator==(const FIteratorImpl& LHS, const FIteratorImpl& RHS) + requires (CSentinelFor, TRangeIteratorType>) + { + return LHS.Current == RHS.Current; + } + + NODISCARD friend FORCEINLINE constexpr auto operator<=>(const FIteratorImpl& LHS, const FIteratorImpl& RHS) + requires (CSizedSentinelFor, TRangeIteratorType>) + { + return LHS.Current <=> RHS.Current; + } + + NODISCARD FORCEINLINE constexpr decltype(auto) operator*() const { return Invoke(Owner->Func, *Current); } + + NODISCARD FORCEINLINE constexpr decltype(auto) operator[](ptrdiff Index) const requires (CRandomAccessRange) { return Invoke(Owner->Func, Current[Index]); } + + FORCEINLINE constexpr FIteratorImpl& operator++() { ++Current; return *this; } + FORCEINLINE constexpr FIteratorImpl& operator--() requires (CBidirectionalRange) { --Current; return *this; } + + FORCEINLINE constexpr void operator++(int) { Current++; } + FORCEINLINE constexpr FIteratorImpl operator++(int) requires (CForwardRange) { return FIteratorImpl(Current++); } + FORCEINLINE constexpr FIteratorImpl operator--(int) requires (CBidirectionalRange) { return FIteratorImpl(Current--); } + + FORCEINLINE constexpr FIteratorImpl& operator+=(ptrdiff Offset) requires (CRandomAccessRange) { Current += Offset; return *this; } + FORCEINLINE constexpr FIteratorImpl& operator-=(ptrdiff Offset) requires (CRandomAccessRange) { Current -= Offset; return *this; } + + NODISCARD friend FORCEINLINE constexpr FIteratorImpl operator+(FIteratorImpl Iter, ptrdiff Offset) requires (CRandomAccessRange) { FIteratorImpl Temp = Iter; Temp += Offset; return Temp; } + NODISCARD friend FORCEINLINE constexpr FIteratorImpl operator+(ptrdiff Offset, FIteratorImpl Iter) requires (CRandomAccessRange) { FIteratorImpl Temp = Iter; Temp += Offset; return Temp; } + + NODISCARD FORCEINLINE constexpr FIteratorImpl operator-(ptrdiff Offset) const requires (CRandomAccessRange) { FIteratorImpl Temp = *this; Temp -= Offset; return Temp; } + + NODISCARD friend FORCEINLINE constexpr ptrdiff operator-(const FIteratorImpl& LHS, const FIteratorImpl& RHS) + requires (CSizedSentinelFor, TRangeIteratorType>) + { + return LHS.Current - RHS.Current; + } + + NODISCARD FORCEINLINE constexpr const TRangeIteratorType& GetBase() const& { return Current; } + NODISCARD FORCEINLINE constexpr TRangeIteratorType GetBase() && { return MoveTemp(Current); } + + private: + + NO_UNIQUE_ADDRESS FOwner* Owner; + + NO_UNIQUE_ADDRESS TRangeIteratorType Current; + + FORCEINLINE constexpr FIteratorImpl(FOwner& InOwner, TRangeIteratorType InCurrent) : Owner(&InOwner), Current(MoveTemp(InCurrent)) { } + + template friend class FIteratorImpl; + template friend class FSentinelImpl; + + friend TTransformView; + }; + + template + class FSentinelImpl + { + private: + + using FOwner = TConditional; + using FBase = TConditional; + + public: + + FORCEINLINE constexpr FSentinelImpl() requires (CDefaultConstructible>) = default; + + FORCEINLINE constexpr FSentinelImpl(FSentinelImpl Sentinel) requires (bConst && CConvertibleTo, TRangeSentinelType>) + : Current(Sentinel.Current) + { } + + NODISCARD FORCEINLINE constexpr bool operator==(const FIteratorImpl& InValue) const& { return Current == InValue.Current; } + + NODISCARD friend FORCEINLINE constexpr ptrdiff operator-(const FIteratorImpl& LHS, const FSentinelImpl& RHS) + requires CSizedSentinelFor, TRangeIteratorType> + { + return LHS.Current - RHS.Current; + } + + NODISCARD friend FORCEINLINE constexpr ptrdiff operator-(const FSentinelImpl& LHS, const FIteratorImpl& RHS) + requires CSizedSentinelFor, TRangeIteratorType> + { + return RHS.Current - LHS.Current; + } + + NODISCARD FORCEINLINE constexpr const TRangeIteratorType& GetBase() const& { return Current; } + NODISCARD FORCEINLINE constexpr TRangeIteratorType GetBase() && { return MoveTemp(Current); } + + private: + + NO_UNIQUE_ADDRESS TRangeSentinelType Current; + + FORCEINLINE constexpr FSentinelImpl(FOwner& InOwner, TRangeSentinelType InCurrent) : Current(InCurrent) { } + + friend TTransformView; + }; + +}; + +template +TTransformView(R&&, F) -> TTransformView, F>; + +static_assert(CRandomAccessRange, decltype([](auto) { return 0; })>>); +static_assert( CCommonRange, decltype([](auto) { return 0; })>>); +static_assert( CSizedRange, decltype([](auto) { return 0; })>>); +static_assert( CView, decltype([](auto) { return 0; })>>); + +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) +{ + return TAllView(Forward(InRange)); +} + +/** Creates A view adapter that consists of the elements of a range that satisfies a predicate. */ +template requires (requires { TFilterView(DeclVal(), DeclVal()); }) +NODISCARD FORCEINLINE constexpr auto Filter(R&& Base, Pred&& Predicate) +{ + return TFilterView(Forward(Base), Forward(Predicate)); +} + +/** Creates A view adapter that consists of the elements of a range that satisfies a predicate. */ +template +NODISCARD FORCEINLINE constexpr auto Filter(Pred&& Predicate) +{ + return [&Predicate](R&& Base) requires (requires { TFilterView(DeclVal(), DeclVal()); }) + { + return TFilterView(Forward(Base), Forward(Predicate)); + }; +} + +/** Creates A view adapter of a sequence that applies a transformation function to each element. */ +template requires (requires { TTransformView(DeclVal(), DeclVal()); }) +NODISCARD FORCEINLINE constexpr auto Transform(R&& Base, F&& Func) +{ + return TTransformView(Forward(Base), Forward(Func)); +} + +/** Creates A view adapter of a sequence that applies a transformation function to each element. */ +template +NODISCARD FORCEINLINE constexpr auto Transform(F&& Func) +{ + return [&Func](R&& Base) requires (requires { TTransformView(DeclVal(), DeclVal()); }) + { + return TTransformView(Forward(Base), Forward(Func)); + }; +} + +NAMESPACE_END(Range) + template requires (CRange>) NODISCARD FORCEINLINE constexpr auto operator|(R&& Range, T&& View) {