From 8f36410346486dccd9ebe17d82fd68c72523f4fe Mon Sep 17 00:00:00 2001 From: Redstone1024 <2824517378@qq.com> Date: Wed, 18 Dec 2024 21:29:44 +0800 Subject: [PATCH] feat(range): add TTakeView adapter --- Redcraft.Utility/Source/Public/Range/Range.h | 1 + .../Source/Public/Range/TakeView.h | 187 ++++++++++++++++++ 2 files changed, 188 insertions(+) create mode 100644 Redcraft.Utility/Source/Public/Range/TakeView.h diff --git a/Redcraft.Utility/Source/Public/Range/Range.h b/Redcraft.Utility/Source/Public/Range/Range.h index 8c2b29b..2ccee39 100644 --- a/Redcraft.Utility/Source/Public/Range/Range.h +++ b/Redcraft.Utility/Source/Public/Range/Range.h @@ -10,3 +10,4 @@ #include "Range/MoveView.h" #include "Range/FilterView.h" #include "Range/TransformView.h" +#include "Range/TakeView.h" diff --git a/Redcraft.Utility/Source/Public/Range/TakeView.h b/Redcraft.Utility/Source/Public/Range/TakeView.h new file mode 100644 index 0000000..2e17a4e --- /dev/null +++ b/Redcraft.Utility/Source/Public/Range/TakeView.h @@ -0,0 +1,187 @@ +#pragma once + +#include "CoreTypes.h" +#include "TypeTraits/TypeTraits.h" +#include "Templates/Utility.h" +#include "Iterator/Utility.h" +#include "Iterator/BasicIterator.h" +#include "Iterator/CountedIterator.h" +#include "Numeric/Math.h" +#include "Range/Utility.h" +#include "Range/Pipe.h" +#include "Range/View.h" +#include "Range/AllView.h" + +NAMESPACE_REDCRAFT_BEGIN +NAMESPACE_MODULE_BEGIN(Redcraft) +NAMESPACE_MODULE_BEGIN(Utility) + +NAMESPACE_BEGIN(Range) + +/** + * A view adapter that includes a specified number of elements from the beginning of a range. + * When based on any view, the take view satisfies the corresponding any view. + * When based on a random access and sized view, the take view satisfies a common view. + */ +template +class TTakeView : public IBasicViewInterface> +{ +private: + + template class FSentinelImpl; + +public: + + FORCEINLINE constexpr TTakeView() requires (CDefaultConstructible) = default; + + FORCEINLINE constexpr TTakeView(V InBase, size_t InCount) : Base(MoveTemp(InBase)), Count(InCount) { } + + NODISCARD FORCEINLINE constexpr auto Begin() + { + if constexpr (CSizedRange) + { + if constexpr (CRandomAccessRange) + { + return Range::Begin(Base); + } + else return MakeCountedIterator(Range::Begin(Base), Num()); + } + else return MakeCountedIterator(Range::Begin(Base), Count); + } + + NODISCARD FORCEINLINE constexpr auto Begin() const requires (CRange) + { + if constexpr (CSizedRange) + { + if constexpr (CRandomAccessRange) + { + return Range::Begin(Base); + } + else return MakeCountedIterator(Range::Begin(Base), Num()); + } + else return MakeCountedIterator(Range::Begin(Base), Count); + } + + NODISCARD FORCEINLINE constexpr auto End() + { + if constexpr (CSizedRange) + { + if constexpr (CRandomAccessRange) + { + return Range::Begin(Base) + Num(); + } + else return DefaultSentinel; + } + else return FSentinelImpl(Range::End(Base)); + } + + NODISCARD FORCEINLINE constexpr auto End() const requires (CRange) + { + if constexpr (CSizedRange) + { + if constexpr (CRandomAccessRange) + { + return Range::Begin(Base) + Num(); + } + else return DefaultSentinel; + } + else return FSentinelImpl(Range::End(Base)); + } + + NODISCARD FORCEINLINE constexpr size_t Num() requires (CSizedRange< V>) { return Math::Min(Range::Num(Base), Count); } + NODISCARD FORCEINLINE constexpr size_t Num() const requires (CSizedRange) { return Math::Min(Range::Num(Base), Count); } + + NODISCARD FORCEINLINE constexpr V GetBase() const& requires (CCopyConstructible) { return Base; } + NODISCARD FORCEINLINE constexpr V GetBase() && { return MoveTemp(Base); } + +private: + + NO_UNIQUE_ADDRESS V Base; + + size_t Count; + + template + class FSentinelImpl final + { + private: + + using FBase = TConditional; + + public: + + FORCEINLINE constexpr FSentinelImpl() = default; + + FORCEINLINE constexpr FSentinelImpl(FSentinelImpl Sentinel) requires (bConst && CConvertibleTo, TRangeSentinel>) + : Current(Sentinel.Current) + { } + + NODISCARD FORCEINLINE constexpr bool operator==(const TCountedIterator>& InValue) const& + { + return InValue.Num() == 0 || InValue.GetBase() == Current; + } + + template requires (CSentinelFor, TRangeIterator>>) + NODISCARD FORCEINLINE constexpr bool operator==(const TCountedIterator>>& InValue) + { + return InValue.Num() == 0 || InValue.GetBase() == Current; + } + + NODISCARD FORCEINLINE constexpr const TRangeIterator& GetBase() const& { return Current; } + NODISCARD FORCEINLINE constexpr TRangeIterator GetBase() && { return MoveTemp(Current); } + + private: + + NO_UNIQUE_ADDRESS TRangeSentinel Current; + + FORCEINLINE constexpr FSentinelImpl(TRangeSentinel InCurrent) : Current(InCurrent) { } + + friend TTakeView; + }; + +}; + +template +TTakeView(R&&, size_t) -> TTakeView>; + +static_assert( CInputRange>>>>); +static_assert( CForwardRange>>>>); +static_assert(CBidirectionalRange>>>>); +static_assert( CRandomAccessRange>>>>); +static_assert( CContiguousRange>>>>); + +static_assert(CCommonRange>>>>); +static_assert( CSizedRange>>>>); +static_assert( CView>>>>); + +static_assert(COutputRange>>>, int>); + +NAMESPACE_END(Range) + +template +constexpr bool bEnableBorrowedRange> = bEnableBorrowedRange; + +NAMESPACE_BEGIN(Range) + +/** Creates A view adapter that includes a specified number of elements from the beginning of a range. */ +template requires (requires { TTakeView(DeclVal(), DeclVal()); }) +NODISCARD FORCEINLINE constexpr auto Take(R&& Base, size_t Count) +{ + return TTakeView(Forward(Base), Count); +} + +/** Creates A view adapter that includes a specified number of elements from the beginning of a range. */ +NODISCARD FORCEINLINE constexpr auto Take(size_t Count) +{ + using FClosure = decltype([] requires (requires { Range::Take(DeclVal(), DeclVal()); }) (R&& Base, size_t Count) + { + return Range::Take(Forward(Base), Count); + }); + + return TAdaptorClosure(Count); +} + +NAMESPACE_END(Range) + +NAMESPACE_MODULE_END(Utility) +NAMESPACE_MODULE_END(Redcraft) +NAMESPACE_REDCRAFT_END