feat(range): add TTakeView adapter

This commit is contained in:
Redstone1024 2024-12-18 21:29:44 +08:00
parent 87e48e5ca1
commit 8f36410346
2 changed files with 188 additions and 0 deletions

View File

@ -10,3 +10,4 @@
#include "Range/MoveView.h" #include "Range/MoveView.h"
#include "Range/FilterView.h" #include "Range/FilterView.h"
#include "Range/TransformView.h" #include "Range/TransformView.h"
#include "Range/TakeView.h"

View File

@ -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 <CView V>
class TTakeView : public IBasicViewInterface<TTakeView<V>>
{
private:
template <bool bConst> class FSentinelImpl;
public:
FORCEINLINE constexpr TTakeView() requires (CDefaultConstructible<V>) = default;
FORCEINLINE constexpr TTakeView(V InBase, size_t InCount) : Base(MoveTemp(InBase)), Count(InCount) { }
NODISCARD FORCEINLINE constexpr auto Begin()
{
if constexpr (CSizedRange<V>)
{
if constexpr (CRandomAccessRange<V>)
{
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<const V>)
{
if constexpr (CSizedRange<const V>)
{
if constexpr (CRandomAccessRange<const V>)
{
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<V>)
{
if constexpr (CRandomAccessRange<V>)
{
return Range::Begin(Base) + Num();
}
else return DefaultSentinel;
}
else return FSentinelImpl<false>(Range::End(Base));
}
NODISCARD FORCEINLINE constexpr auto End() const requires (CRange<const V>)
{
if constexpr (CSizedRange<const V>)
{
if constexpr (CRandomAccessRange<const V>)
{
return Range::Begin(Base) + Num();
}
else return DefaultSentinel;
}
else return FSentinelImpl<true>(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<const V>) { return Math::Min(Range::Num(Base), Count); }
NODISCARD FORCEINLINE constexpr V GetBase() const& requires (CCopyConstructible<V>) { return Base; }
NODISCARD FORCEINLINE constexpr V GetBase() && { return MoveTemp(Base); }
private:
NO_UNIQUE_ADDRESS V Base;
size_t Count;
template <bool bConst>
class FSentinelImpl final
{
private:
using FBase = TConditional<bConst, const V, V>;
public:
FORCEINLINE constexpr FSentinelImpl() = default;
FORCEINLINE constexpr FSentinelImpl(FSentinelImpl<!bConst> Sentinel) requires (bConst && CConvertibleTo<TRangeSentinel<V>, TRangeSentinel<FBase>>)
: Current(Sentinel.Current)
{ }
NODISCARD FORCEINLINE constexpr bool operator==(const TCountedIterator<TRangeIterator<FBase>>& InValue) const&
{
return InValue.Num() == 0 || InValue.GetBase() == Current;
}
template <bool bOther = !bConst> requires (CSentinelFor<TRangeSentinel<FBase>, TRangeIterator<TConditional<bOther, const V, V>>>)
NODISCARD FORCEINLINE constexpr bool operator==(const TCountedIterator<TRangeIterator<TConditional<bOther, const V, V>>>& InValue)
{
return InValue.Num() == 0 || InValue.GetBase() == Current;
}
NODISCARD FORCEINLINE constexpr const TRangeIterator<FBase>& GetBase() const& { return Current; }
NODISCARD FORCEINLINE constexpr TRangeIterator<FBase> GetBase() && { return MoveTemp(Current); }
private:
NO_UNIQUE_ADDRESS TRangeSentinel<FBase> Current;
FORCEINLINE constexpr FSentinelImpl(TRangeSentinel<FBase> InCurrent) : Current(InCurrent) { }
friend TTakeView;
};
};
template <typename R>
TTakeView(R&&, size_t) -> TTakeView<TAllView<R>>;
static_assert( CInputRange<TTakeView<TAllView<IRange< IInputIterator<int&>>>>>);
static_assert( CForwardRange<TTakeView<TAllView<IRange< IForwardIterator<int&>>>>>);
static_assert(CBidirectionalRange<TTakeView<TAllView<IRange<IBidirectionalIterator<int&>>>>>);
static_assert( CRandomAccessRange<TTakeView<TAllView<IRange< IRandomAccessIterator<int&>>>>>);
static_assert( CContiguousRange<TTakeView<TAllView<IRange< IContiguousIterator<int&>>>>>);
static_assert(CCommonRange<TTakeView<TAllView<ISizedRange< IRandomAccessIterator<int>>>>>);
static_assert( CSizedRange<TTakeView<TAllView<ISizedRange<IInputOrOutputIterator<int>>>>>);
static_assert( CView<TTakeView<TAllView< IRange<IInputOrOutputIterator<int>>>>>);
static_assert(COutputRange<TTakeView<TAllView<IRange<IOutputIterator<int&>>>>, int>);
NAMESPACE_END(Range)
template <typename T>
constexpr bool bEnableBorrowedRange<Range::TTakeView<T>> = bEnableBorrowedRange<T>;
NAMESPACE_BEGIN(Range)
/** Creates A view adapter that includes a specified number of elements from the beginning of a range. */
template <CViewableRange R> requires (requires { TTakeView(DeclVal<R>(), DeclVal<size_t>()); })
NODISCARD FORCEINLINE constexpr auto Take(R&& Base, size_t Count)
{
return TTakeView(Forward<R>(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([]<CViewableRange R> requires (requires { Range::Take(DeclVal<R>(), DeclVal<size_t>()); }) (R&& Base, size_t Count)
{
return Range::Take(Forward<R>(Base), Count);
});
return TAdaptorClosure<FClosure, size_t>(Count);
}
NAMESPACE_END(Range)
NAMESPACE_MODULE_END(Utility)
NAMESPACE_MODULE_END(Redcraft)
NAMESPACE_REDCRAFT_END