diff --git a/Redcraft.Utility/Source/Public/Range/Range.h b/Redcraft.Utility/Source/Public/Range/Range.h index 2ccee39..f823b08 100644 --- a/Redcraft.Utility/Source/Public/Range/Range.h +++ b/Redcraft.Utility/Source/Public/Range/Range.h @@ -11,3 +11,4 @@ #include "Range/FilterView.h" #include "Range/TransformView.h" #include "Range/TakeView.h" +#include "Range/TakeWhileView.h" diff --git a/Redcraft.Utility/Source/Public/Range/TakeWhileView.h b/Redcraft.Utility/Source/Public/Range/TakeWhileView.h new file mode 100644 index 0000000..bacb0a1 --- /dev/null +++ b/Redcraft.Utility/Source/Public/Range/TakeWhileView.h @@ -0,0 +1,149 @@ +#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 elements that satisfy the predicate from the beginning of the range. + * When based on an input view, the take while view satisfies at least an input view up to a contiguous view. + * When based on a forward and output view, the take while view satisfies an output view. + */ +template > Pred> requires (CView && CObject && CMoveConstructible) +class TTakeWhileView : public IBasicViewInterface> +{ +private: + + template class FSentinelImpl; + +public: + + using FElementType = TRangeElement; + using FReference = TRangeReference; + + FORCEINLINE constexpr TTakeWhileView() requires (CDefaultConstructible&& CDefaultConstructible) = default; + + FORCEINLINE constexpr explicit TTakeWhileView(V InBase, Pred InPredicate) : Base(MoveTemp(InBase)), Predicate(MoveTemp(InPredicate)) { } + + NODISCARD FORCEINLINE constexpr auto Begin() requires (!CSimpleView) + { + return Range::Begin(Base); + } + + NODISCARD FORCEINLINE constexpr auto Begin() const requires (CRange && CPredicate>) + { + return Range::Begin(Base); + } + + NODISCARD FORCEINLINE constexpr auto End() requires (!CSimpleView) + { + return FSentinelImpl(Range::End(Base), AddressOf(Predicate)); + } + + NODISCARD FORCEINLINE constexpr auto End() const requires (CRange && CPredicate>) + { + return FSentinelImpl(Range::End(Base), AddressOf(Predicate)); + } + + 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; + + template + class FSentinelImpl final + { + private: + + using FBase = TConditional; + using FPred = TConditional; + + public: + + FORCEINLINE constexpr FSentinelImpl() = default; + + FORCEINLINE constexpr FSentinelImpl(FSentinelImpl Sentinel) requires (bConst && CConvertibleTo, TRangeSentinel>) + : Current(Sentinel.Current), Predicate(Sentinel.Predicate) + { } + + NODISCARD FORCEINLINE constexpr bool operator==(const TRangeIterator& InValue) const& + { + return InValue == Current || !InvokeResult(*Predicate, *InValue); + } + + NODISCARD FORCEINLINE constexpr TRangeSentinel GetBase() const { return Current; } + + private: + + NO_UNIQUE_ADDRESS TRangeSentinel Current; + + FPred* Predicate; + + FORCEINLINE constexpr FSentinelImpl(TRangeSentinel InCurrent, FPred* InPredicate) : Current(InCurrent), Predicate(InPredicate) { } + + friend TTakeWhileView; + }; + +}; + +template +TTakeWhileView(R&&, Pred) -> TTakeWhileView, Pred>; + +static_assert( CInputRange>>, bool(*)(int)>>); +static_assert( CForwardRange>>, bool(*)(int)>>); +static_assert(CBidirectionalRange>>, bool(*)(int)>>); +static_assert( CRandomAccessRange>>, bool(*)(int)>>); +static_assert( CContiguousRange>>, bool(*)(int)>>); + +static_assert(CView>>, bool(*)(int)>>); + +static_assert(COutputRange>>, bool(*)(int)>, int>); + +NAMESPACE_END(Range) + +NAMESPACE_BEGIN(Range) + +/** Creates A view adapter that includes elements that satisfy the predicate from the beginning of the range. */ +template requires (requires { TTakeWhileView(DeclVal(), DeclVal()); }) +NODISCARD FORCEINLINE constexpr auto TakeWhile(R&& Base, Pred&& Predicate) +{ + return TTakeWhileView(Forward(Base), Forward(Predicate)); +} + +/** Creates A view adapter that includes elements that satisfy the predicate from the beginning of the range. */ +template +NODISCARD FORCEINLINE constexpr auto TakeWhile(Pred&& Predicate) +{ + using FClosure = decltype([] requires (requires { Range::TakeWhile(DeclVal(), DeclVal()); }) (R&& Base, T&& Predicate) + { + return Range::TakeWhile(Forward(Base), Forward(Predicate)); + }); + + return TAdaptorClosure>(Forward(Predicate)); +} + +NAMESPACE_END(Range) + +NAMESPACE_MODULE_END(Utility) +NAMESPACE_MODULE_END(Redcraft) +NAMESPACE_REDCRAFT_END