refactor(*): refactor the tool library's parent folder to plural form
This commit is contained in:
183
Redcraft.Utility/Source/Public/Ranges/AllView.h
Normal file
183
Redcraft.Utility/Source/Public/Ranges/AllView.h
Normal file
@ -0,0 +1,183 @@
|
||||
#pragma once
|
||||
|
||||
#include "CoreTypes.h"
|
||||
#include "Ranges/View.h"
|
||||
#include "Ranges/Pipe.h"
|
||||
#include "Ranges/Utility.h"
|
||||
#include "Templates/Utility.h"
|
||||
#include "TypeTraits/TypeTraits.h"
|
||||
|
||||
NAMESPACE_REDCRAFT_BEGIN
|
||||
NAMESPACE_MODULE_BEGIN(Redcraft)
|
||||
NAMESPACE_MODULE_BEGIN(Utility)
|
||||
|
||||
NAMESPACE_BEGIN(Range)
|
||||
|
||||
/**
|
||||
* A view adapter that references other range.
|
||||
* No matter which it is base range, the reference view always satisfies the same range concept.
|
||||
*/
|
||||
template <CRange R> requires (CObject<R>)
|
||||
class TRefView : public IBasicViewInterface<TRefView<R>>
|
||||
{
|
||||
private:
|
||||
|
||||
// Use the function to check constructability.
|
||||
static void Func(R&);
|
||||
static void Func(R&&) = delete;
|
||||
|
||||
public:
|
||||
|
||||
template <typename T> requires (!CSameAs<TRemoveCVRef<T>, TRefView> && CConvertibleTo<T, R&> && requires { Func(DeclVal<T>()); })
|
||||
FORCEINLINE constexpr TRefView(T&& InRange) : Ptr(AddressOf(static_cast<R&>(Forward<T>(InRange)))) { }
|
||||
|
||||
NODISCARD FORCEINLINE constexpr TRangeIterator<R> Begin() const { return Range::Begin(*Ptr); }
|
||||
NODISCARD FORCEINLINE constexpr TRangeSentinel<R> End() const { return Range::End (*Ptr); }
|
||||
|
||||
NODISCARD FORCEINLINE constexpr auto GetData() const requires (CContiguousRange<R>) { return Range::GetData(*Ptr); }
|
||||
NODISCARD FORCEINLINE constexpr size_t Num() const requires (CSizedRange<R>) { return Range::Num (*Ptr); }
|
||||
NODISCARD FORCEINLINE constexpr bool IsEmpty() const requires (requires(R Range) { Range::IsEmpty(Range); }) { return Range::IsEmpty(*Ptr); }
|
||||
|
||||
NODISCARD FORCEINLINE constexpr R& GetBase() const { return *Ptr; }
|
||||
|
||||
private:
|
||||
|
||||
R* Ptr;
|
||||
|
||||
};
|
||||
|
||||
template <typename R>
|
||||
TRefView(R&) -> TRefView<R>;
|
||||
|
||||
static_assert( CInputRange<TRefView<IRange< IInputIterator<int&>>>>);
|
||||
static_assert( CForwardRange<TRefView<IRange< IForwardIterator<int&>>>>);
|
||||
static_assert(CBidirectionalRange<TRefView<IRange<IBidirectionalIterator<int&>>>>);
|
||||
static_assert( CRandomAccessRange<TRefView<IRange< IRandomAccessIterator<int&>>>>);
|
||||
static_assert( CContiguousRange<TRefView<IRange< IContiguousIterator<int&>>>>);
|
||||
|
||||
static_assert(CCommonRange<TRefView<ICommonRange< IForwardIterator<int>>>>);
|
||||
static_assert( CSizedRange<TRefView< ISizedRange<IInputOrOutputIterator<int>>>>);
|
||||
static_assert( CView<TRefView< IRange<IInputOrOutputIterator<int>>>>);
|
||||
|
||||
static_assert(COutputRange<TRefView<IRange<IOutputIterator<int&>>>, int>);
|
||||
|
||||
NAMESPACE_END(Range)
|
||||
|
||||
template <typename T>
|
||||
constexpr bool bEnableBorrowedRange<Range::TRefView<T>> = true;
|
||||
|
||||
NAMESPACE_BEGIN(Range)
|
||||
|
||||
/**
|
||||
* A view adapter that has unique ownership of a range.
|
||||
* No matter which it is base range, the reference view always satisfies the same range concept.
|
||||
* Specify, the base range type must be movable, and the owning view always is movable but not copyable.
|
||||
*/
|
||||
template <CRange R> requires (CMovable<R> && !NAMESPACE_PRIVATE::TIsInitializerList<R>::Value)
|
||||
class TOwningView : public IBasicViewInterface<TOwningView<R>>
|
||||
{
|
||||
public:
|
||||
|
||||
FORCEINLINE constexpr TOwningView() requires (CDefaultConstructible<R>) = 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 auto Begin() { return Range::Begin(Base); }
|
||||
NODISCARD FORCEINLINE constexpr auto End() { return Range::End (Base); }
|
||||
NODISCARD FORCEINLINE constexpr auto Begin() const requires (CRange<const R>) { return Range::Begin(Base); }
|
||||
NODISCARD FORCEINLINE constexpr auto End() const requires (CRange<const R>) { return Range::End (Base); }
|
||||
|
||||
NODISCARD FORCEINLINE constexpr auto GetData() requires (CContiguousRange< R>) { return Range::GetData(Base); }
|
||||
NODISCARD FORCEINLINE constexpr auto GetData() const requires (CContiguousRange<const R>) { 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<const R>) { 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( CInputRange<TOwningView<IRange< IInputIterator<int&>>>>);
|
||||
static_assert( CForwardRange<TOwningView<IRange< IForwardIterator<int&>>>>);
|
||||
static_assert(CBidirectionalRange<TOwningView<IRange<IBidirectionalIterator<int&>>>>);
|
||||
static_assert( CRandomAccessRange<TOwningView<IRange< IRandomAccessIterator<int&>>>>);
|
||||
static_assert( CContiguousRange<TOwningView<IRange< IContiguousIterator<int&>>>>);
|
||||
|
||||
static_assert(CCommonRange<TOwningView<ICommonRange< IForwardIterator<int>>>>);
|
||||
static_assert( CSizedRange<TOwningView< ISizedRange<IInputOrOutputIterator<int>>>>);
|
||||
static_assert( CView<TOwningView< IRange<IInputOrOutputIterator<int>>>>);
|
||||
|
||||
static_assert(COutputRange<TOwningView<IRange<IOutputIterator<int&>>>, int>);
|
||||
|
||||
NAMESPACE_END(Range)
|
||||
|
||||
template <typename T>
|
||||
constexpr bool bEnableBorrowedRange<Range::TOwningView<T>> = bEnableBorrowedRange<T>;
|
||||
|
||||
NAMESPACE_BEGIN(Range)
|
||||
|
||||
/** Creates A view adapter that includes all elements of a range. */
|
||||
template <CViewableRange R>
|
||||
NODISCARD FORCEINLINE constexpr auto All(R&& InRange)
|
||||
{
|
||||
if constexpr (CView<TDecay<R>>)
|
||||
{
|
||||
return TDecay<R>(Forward<R>(InRange));
|
||||
}
|
||||
|
||||
else if constexpr (requires { TRefView(Forward<R>(InRange)); })
|
||||
{
|
||||
return TRefView(Forward<R>(InRange));
|
||||
}
|
||||
|
||||
else return TOwningView(Forward<R>(InRange));
|
||||
}
|
||||
|
||||
/** Creates A view adapter that includes all elements of a range. */
|
||||
NODISCARD FORCEINLINE constexpr auto All()
|
||||
{
|
||||
using FClosure = decltype([]<CViewableRange R> requires (requires { Range::All(DeclVal<R>()); }) (R&& Base)
|
||||
{
|
||||
return Range::All(Forward<R>(Base));
|
||||
});
|
||||
|
||||
return TAdaptorClosure<FClosure>();
|
||||
}
|
||||
|
||||
/** A view adapter that includes all elements of a range. */
|
||||
template <CViewableRange R>
|
||||
using TAllView = decltype(Range::All(DeclVal<R>()));
|
||||
|
||||
static_assert( CInputRange<TAllView<IRange< IInputIterator<int&>>>>);
|
||||
static_assert( CForwardRange<TAllView<IRange< IForwardIterator<int&>>>>);
|
||||
static_assert(CBidirectionalRange<TAllView<IRange<IBidirectionalIterator<int&>>>>);
|
||||
static_assert( CRandomAccessRange<TAllView<IRange< IRandomAccessIterator<int&>>>>);
|
||||
static_assert( CContiguousRange<TAllView<IRange< IContiguousIterator<int&>>>>);
|
||||
|
||||
static_assert(CCommonRange<TAllView<ICommonRange< IForwardIterator<int>>>>);
|
||||
static_assert( CSizedRange<TAllView< ISizedRange<IInputOrOutputIterator<int>>>>);
|
||||
static_assert( CView<TAllView< IRange<IInputOrOutputIterator<int>>>>);
|
||||
|
||||
static_assert(COutputRange<TAllView<IRange<IOutputIterator<int&>>>, int>);
|
||||
|
||||
NAMESPACE_END(Range)
|
||||
|
||||
NAMESPACE_MODULE_END(Utility)
|
||||
NAMESPACE_MODULE_END(Redcraft)
|
||||
NAMESPACE_REDCRAFT_END
|
163
Redcraft.Utility/Source/Public/Ranges/Conversion.h
Normal file
163
Redcraft.Utility/Source/Public/Ranges/Conversion.h
Normal file
@ -0,0 +1,163 @@
|
||||
#pragma once
|
||||
|
||||
#include "CoreTypes.h"
|
||||
#include "Ranges/View.h"
|
||||
#include "Ranges/Utility.h"
|
||||
#include "Ranges/AllView.h"
|
||||
#include "Templates/Utility.h"
|
||||
#include "Ranges/TransformView.h"
|
||||
#include "TypeTraits/TypeTraits.h"
|
||||
|
||||
NAMESPACE_REDCRAFT_BEGIN
|
||||
NAMESPACE_MODULE_BEGIN(Redcraft)
|
||||
NAMESPACE_MODULE_BEGIN(Utility)
|
||||
|
||||
// NOTE: In the STL, use std::from_range_t as a disambiguation tag that resolves ambiguity
|
||||
// introduced by the list-initialization. For example, for the following code:
|
||||
//
|
||||
// R RangeOfInts = /* ... */;
|
||||
// static_assert(CRange<R> and CSameAs<TRangeElement<R>, int>);
|
||||
//
|
||||
// TArray Arr(RangeOfInts);
|
||||
// TArray Brr{RangeOfInts};
|
||||
//
|
||||
// If R is TArray<int> than decltype(Arr) is TArray<int> and decltype(Brr) is TArray<int>,
|
||||
// otherwise, decltype(Arr) is TArray<int> and decltype(Brr) is TArray<R>.
|
||||
//
|
||||
// But Redcraft can't use the std::from_range_t tag because list-initialization is discouraged.
|
||||
|
||||
/** A concept specifies a container that can reserve size. */
|
||||
template <typename C>
|
||||
concept CReservableContainer = CSizedRange<C>
|
||||
&& requires (C& Container, size_t N)
|
||||
{
|
||||
Container.Reserve(N);
|
||||
{ Container.Max() } -> CSameAs<size_t>;
|
||||
};
|
||||
|
||||
/** A concept specifies a container that can append elements. */
|
||||
template <typename C, typename Ref>
|
||||
concept CAppendableContainer =
|
||||
requires (C& Container, Ref&& Reference)
|
||||
{
|
||||
requires
|
||||
(
|
||||
requires { Container.EmplaceBack (Forward<Ref>(Reference)); } ||
|
||||
requires { Container.PushBack (Forward<Ref>(Reference)); } ||
|
||||
requires { Container.Emplace(Container.End(), Forward<Ref>(Reference)); } ||
|
||||
requires { Container.Insert (Container.End(), Forward<Ref>(Reference)); }
|
||||
);
|
||||
};
|
||||
|
||||
NAMESPACE_BEGIN(Range)
|
||||
|
||||
/** Constructs a non-view object from the elements of the range. */
|
||||
template <typename C, CInputRange R, typename... Ts> requires (!CView<C>)
|
||||
NODISCARD FORCEINLINE constexpr auto To(R&& Range, Ts&&... Args)
|
||||
{
|
||||
if constexpr (!CInputRange<C> || CConvertibleTo<TRangeReference<R>, TRangeElement<C>>)
|
||||
{
|
||||
if constexpr (CConstructibleFrom<C, R, Ts...>)
|
||||
{
|
||||
return C(Forward<R>(Range), Forward<Ts>(Args)...);
|
||||
}
|
||||
|
||||
else if constexpr (CCommonRange<R> && CInputRange<R> && CConstructibleFrom<C, TRangeIterator<R>, TRangeSentinel<R>, Ts...>)
|
||||
{
|
||||
return C(Range::Begin(Range), Range::End(Range), Forward<Ts>(Args)...);
|
||||
}
|
||||
|
||||
else if constexpr (CConstructibleFrom<C, Ts...> && CAppendableContainer<C, TRangeReference<R>>)
|
||||
{
|
||||
C Result(Forward<Ts>(Args)...);
|
||||
|
||||
if constexpr (CSizedRange<R> && CReservableContainer<C>)
|
||||
{
|
||||
Result.Reserve(Range::Num(Range));
|
||||
}
|
||||
|
||||
for (TRangeReference<R> Element : Range)
|
||||
{
|
||||
if constexpr (requires { Result.EmplaceBack(DeclVal<TRangeReference<R>>()); })
|
||||
{
|
||||
Result.EmplaceBack(Forward<TRangeReference<R>>(Element));
|
||||
}
|
||||
|
||||
else if constexpr (requires { Result.PushBack(DeclVal<TRangeReference<R>>()); })
|
||||
{
|
||||
Result.PushBack(Forward<TRangeReference<R>>(Element));
|
||||
}
|
||||
|
||||
else if constexpr (requires { Result.Emplace(Result.End(), DeclVal<TRangeReference<R>>()); })
|
||||
{
|
||||
Result.Emplace(Result.End(), Forward<TRangeReference<R>>(Element));
|
||||
}
|
||||
|
||||
else /* if constexpr (requires { Result.Insert(Result.End(), DeclVal<TRangeReference<R>>()); }) */
|
||||
{
|
||||
Result.Insert(Result.End(), Forward<TRangeReference<R>>(Element));
|
||||
}
|
||||
}
|
||||
|
||||
return Result;
|
||||
}
|
||||
|
||||
else static_assert(sizeof(R) == -1, "The container type is not constructible from a range");
|
||||
}
|
||||
else
|
||||
{
|
||||
if constexpr (CInputRange<TRangeReference<C>>)
|
||||
{
|
||||
return Range::To<C>(Range::All(Range) | Range::Transform([]<typename T>(T&& Element) { return Range::To<TRangeElement<C>>(Forward<T>(Element)); }), Forward<Args>(Args)...);
|
||||
}
|
||||
|
||||
else static_assert(sizeof(R) == -1, "The container type is not constructible from a range");
|
||||
}
|
||||
}
|
||||
|
||||
/** Constructs a non-view object from the elements of the range. */
|
||||
template <template <typename...> typename C, CInputRange R, typename... Ts>
|
||||
NODISCARD FORCEINLINE constexpr auto To(R&& Range, Ts&&... Args)
|
||||
{
|
||||
if constexpr (requires { C(DeclVal<R>(), DeclVal<Ts>()...); })
|
||||
{
|
||||
return Range::To<decltype(C(DeclVal<R>(), DeclVal<Ts>()...))>(Forward<R>(Range), Forward<Ts>(Args)...);
|
||||
}
|
||||
|
||||
else if constexpr (requires { C(DeclVal<TRangeIterator<R>>(), DeclVal<TRangeSentinel<R>>(), DeclVal<Args>()...); })
|
||||
{
|
||||
return Range::To<decltype(C(DeclVal<TRangeIterator<R>>(), DeclVal<TRangeSentinel<R>>(), DeclVal<Args>()...))>(Forward<R>(Range), Forward<Ts>(Args)...);
|
||||
}
|
||||
|
||||
else static_assert(sizeof(R) == -1, "The container type is not constructible from a range");
|
||||
}
|
||||
|
||||
/** Constructs a non-view object from the elements of the range. */
|
||||
template <typename C, typename... Ts> requires (!CView<C>)
|
||||
NODISCARD FORCEINLINE constexpr auto To(Ts&&... Args)
|
||||
{
|
||||
using FClosure = decltype([]<CInputRange R, typename... Us> requires (requires { Range::To<C>(DeclVal<R>(), DeclVal<Us>()...); }) (R&& Range, Us&&... Args)
|
||||
{
|
||||
return Range::To<C>(Forward<R>(Range), Forward<Us>(Args)...);
|
||||
});
|
||||
|
||||
return TAdaptorClosure<FClosure, TDecay<Ts>...>(Forward<Ts>(Args)...);
|
||||
}
|
||||
|
||||
/** Constructs a non-view object from the elements of the range. */
|
||||
template <template <typename...> typename C, typename... Ts>
|
||||
NODISCARD FORCEINLINE constexpr auto To(Ts&&... Args)
|
||||
{
|
||||
using FClosure = decltype([]<CInputRange R, typename... Us> requires (requires { Range::To<C>(DeclVal<R>(), DeclVal<Us>()...); }) (R&& Range, Us&&... Args)
|
||||
{
|
||||
return Range::To<C>(Forward<R>(Range), Forward<Us>(Args)...);
|
||||
});
|
||||
|
||||
return TAdaptorClosure<FClosure, TDecay<Ts>...>(Forward<Ts>(Args)...);
|
||||
}
|
||||
|
||||
NAMESPACE_END(Range)
|
||||
|
||||
NAMESPACE_MODULE_END(Utility)
|
||||
NAMESPACE_MODULE_END(Redcraft)
|
||||
NAMESPACE_REDCRAFT_END
|
357
Redcraft.Utility/Source/Public/Ranges/Factory.h
Normal file
357
Redcraft.Utility/Source/Public/Ranges/Factory.h
Normal file
@ -0,0 +1,357 @@
|
||||
#pragma once
|
||||
|
||||
#include "CoreTypes.h"
|
||||
#include "Ranges/View.h"
|
||||
#include "Ranges/Utility.h"
|
||||
#include "Memory/Address.h"
|
||||
#include "Templates/Utility.h"
|
||||
#include "TypeTraits/TypeTraits.h"
|
||||
|
||||
NAMESPACE_REDCRAFT_BEGIN
|
||||
NAMESPACE_MODULE_BEGIN(Redcraft)
|
||||
NAMESPACE_MODULE_BEGIN(Utility)
|
||||
|
||||
NAMESPACE_BEGIN(Range)
|
||||
|
||||
/** A view type that produces a view of no elements of a particular type. */
|
||||
template <CObject T>
|
||||
class TEmptyView : public IBasicViewInterface<TEmptyView<T>>
|
||||
{
|
||||
public:
|
||||
|
||||
using FElementType = T;
|
||||
using FReference = T&;
|
||||
using FIterator = T*;
|
||||
using FSentinel = T*;
|
||||
|
||||
FORCEINLINE constexpr TEmptyView() = default;
|
||||
|
||||
NODISCARD static FORCEINLINE constexpr FIterator Begin() { return nullptr; }
|
||||
NODISCARD static FORCEINLINE constexpr FSentinel 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<TEmptyView<int>>);
|
||||
static_assert( CCommonRange<TEmptyView<int>>);
|
||||
static_assert( CSizedRange<TEmptyView<int>>);
|
||||
static_assert( CView<TEmptyView<int>>);
|
||||
|
||||
NAMESPACE_END(Range)
|
||||
|
||||
template <typename T>
|
||||
constexpr bool bEnableBorrowedRange<Range::TEmptyView<T>> = true;
|
||||
|
||||
NAMESPACE_BEGIN(Range)
|
||||
|
||||
/** A view type that contains exactly one element of a specified value. */
|
||||
template <CObject T> requires (CMoveConstructible<T>)
|
||||
class TSingleView : public IBasicViewInterface<TSingleView<T>>
|
||||
{
|
||||
public:
|
||||
|
||||
using FElementType = T;
|
||||
|
||||
using FReference = T&;
|
||||
using FConstReference = const T&;
|
||||
|
||||
using FIterator = T*;
|
||||
using FConstIterator = const T*;
|
||||
|
||||
using FSentinel = T*;
|
||||
using FConstSentinel = const T*;
|
||||
|
||||
FORCEINLINE constexpr TSingleView() requires (CDefaultConstructible<T>) = default;
|
||||
|
||||
FORCEINLINE constexpr explicit TSingleView(const T& InValue) requires (CCopyConstructible<T>) : Value(InValue) { }
|
||||
|
||||
FORCEINLINE constexpr explicit TSingleView(T&& InValue) : Value(MoveTemp(InValue)) { }
|
||||
|
||||
template <typename... Ts> requires (CConstructibleFrom<T, Ts...>)
|
||||
FORCEINLINE constexpr explicit TSingleView(FInPlace, Ts&&... Args) : Value(Forward<Ts>(Args)...) { }
|
||||
|
||||
FORCEINLINE constexpr FIterator Begin() { return GetData(); }
|
||||
FORCEINLINE constexpr FConstIterator Begin() const { return GetData(); }
|
||||
FORCEINLINE constexpr FSentinel End() { return GetData() + 1; }
|
||||
FORCEINLINE constexpr FConstSentinel 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 <typename T>
|
||||
TSingleView(T) -> TSingleView<T>;
|
||||
|
||||
static_assert(CContiguousRange<TSingleView<int>>);
|
||||
static_assert( CCommonRange<TSingleView<int>>);
|
||||
static_assert( CSizedRange<TSingleView<int>>);
|
||||
static_assert( CView<TSingleView<int>>);
|
||||
|
||||
/** A view type that generates a sequence of elements by repeatedly incrementing an initial value. Can be either bounded or unbounded. */
|
||||
template <CWeaklyIncrementable W, CWeaklyEqualityComparable<W> S = FUnreachableSentinel> requires (CSemiregular<S> && CCopyable<W>)
|
||||
class TIotaView : public IBasicViewInterface<TIotaView<W, S>>
|
||||
{
|
||||
private:
|
||||
|
||||
class FIteratorImpl;
|
||||
class FSentinelImpl;
|
||||
|
||||
public:
|
||||
|
||||
using FElementType = TRemoveCV<W>;
|
||||
|
||||
using FReference = W;
|
||||
|
||||
using FIterator = FIteratorImpl;
|
||||
|
||||
using FSentinel = TConditional<CSameAs<W, S>, FIteratorImpl, FSentinelImpl>;
|
||||
|
||||
FORCEINLINE constexpr TIotaView() requires (CDefaultConstructible<W>) = default;
|
||||
|
||||
FORCEINLINE constexpr explicit TIotaView(W InValue) requires (CDefaultConstructible<S>) : First(InValue), Last() { }
|
||||
|
||||
FORCEINLINE constexpr explicit TIotaView(TIdentity<W> InValue, TIdentity<S> InLast) : First(InValue), Last(InLast) { }
|
||||
|
||||
FORCEINLINE constexpr explicit TIotaView(FIterator InFirst, FSentinel InLast) : First(InFirst.Value), Last(InLast.Value) { }
|
||||
|
||||
FORCEINLINE constexpr explicit TIotaView(FIterator InFirst, FUnreachableSentinel) requires (CSameAs<S, FUnreachableSentinel>) : First(InFirst.Value) { }
|
||||
|
||||
NODISCARD FORCEINLINE constexpr FIterator Begin() const { return FIterator(First); }
|
||||
|
||||
NODISCARD FORCEINLINE constexpr FSentinel End() const { return FSentinel(Last); }
|
||||
|
||||
NODISCARD FORCEINLINE constexpr size_t Num() const requires ((CIntegral<W> && CIntegral<S>) || CSizedSentinelFor<S, W>) { return Last - First; }
|
||||
|
||||
NODISCARD FORCEINLINE constexpr bool IsEmpty() const { return First == Last; }
|
||||
|
||||
private:
|
||||
|
||||
NO_UNIQUE_ADDRESS W First;
|
||||
NO_UNIQUE_ADDRESS S Last;
|
||||
|
||||
class FIteratorImpl final
|
||||
{
|
||||
public:
|
||||
|
||||
using FElementType = TRemoveCV<W>;
|
||||
|
||||
FORCEINLINE constexpr FIteratorImpl() requires (CDefaultConstructible<W>) = default;
|
||||
|
||||
NODISCARD friend FORCEINLINE constexpr bool operator==(const FIteratorImpl& LHS, const FIteratorImpl& RHS) requires (CEqualityComparable<W>) { return LHS.Value == RHS.Value; }
|
||||
|
||||
NODISCARD FORCEINLINE constexpr FReference operator*() const { return Value; }
|
||||
NODISCARD FORCEINLINE constexpr const W* operator->() const { return AddressOf(Value); }
|
||||
|
||||
FORCEINLINE constexpr FIteratorImpl& operator++() { ++Value; return *this; }
|
||||
|
||||
FORCEINLINE constexpr FIteratorImpl operator++(int) { FIteratorImpl Temp = *this; ++*this; return Temp; }
|
||||
|
||||
private:
|
||||
|
||||
NO_UNIQUE_ADDRESS W Value;
|
||||
|
||||
constexpr explicit FIteratorImpl(W InValue) : Value(InValue) { }
|
||||
|
||||
friend FSentinelImpl;
|
||||
friend TIotaView;
|
||||
};
|
||||
|
||||
class FSentinelImpl final
|
||||
{
|
||||
public:
|
||||
|
||||
FORCEINLINE constexpr FSentinelImpl() = default;
|
||||
|
||||
NODISCARD FORCEINLINE constexpr bool operator==(const FIteratorImpl& InValue) const& { return Value == InValue.Value; }
|
||||
|
||||
private:
|
||||
|
||||
NO_UNIQUE_ADDRESS S Value;
|
||||
|
||||
FORCEINLINE constexpr FSentinelImpl(S InValue) : Value(InValue) { }
|
||||
|
||||
friend TIotaView;
|
||||
};
|
||||
};
|
||||
|
||||
template <typename T, typename U>
|
||||
TIotaView(T, U) -> TIotaView<T, U>;
|
||||
|
||||
static_assert(CForwardRange<TIotaView<int>>);
|
||||
static_assert( CView<TIotaView<int>>);
|
||||
|
||||
NAMESPACE_END(Range)
|
||||
|
||||
template <typename T, typename U>
|
||||
constexpr bool bEnableBorrowedRange<Range::TIotaView<T, U>> = true;
|
||||
|
||||
NAMESPACE_BEGIN(Range)
|
||||
|
||||
/** A view type that generates a sequence of elements by repeatedly producing the same value. Can be either bounded or unbounded. */
|
||||
template <CObject W, bool bIsUnreachable = true> requires (CMoveConstructible<W> && CSameAs<W, TRemoveCV<W>>)
|
||||
class TRepeatView : public IBasicViewInterface<TRepeatView<W, bIsUnreachable>>
|
||||
{
|
||||
private:
|
||||
|
||||
class FIteratorImpl;
|
||||
|
||||
public:
|
||||
|
||||
using FElementType = W;
|
||||
|
||||
using FReference = const W&;
|
||||
|
||||
using FIterator = FIteratorImpl;
|
||||
|
||||
using FSentinel = TConditional<bIsUnreachable, FUnreachableSentinel, FIterator>;
|
||||
|
||||
FORCEINLINE constexpr TRepeatView() requires (CDefaultConstructible<W>) = default;
|
||||
|
||||
FORCEINLINE constexpr explicit TRepeatView(const W& InValue) requires (bIsUnreachable && CCopyConstructible<W>) : Value(InValue) { }
|
||||
|
||||
FORCEINLINE constexpr explicit TRepeatView(W&& InValue) requires (bIsUnreachable) : Value(MoveTemp(InValue)) { }
|
||||
|
||||
FORCEINLINE constexpr explicit TRepeatView(const W& InValue, size_t InCount) requires (!bIsUnreachable && CCopyConstructible<W>) : Value(MoveTemp(InValue)), Count(InCount) { }
|
||||
|
||||
FORCEINLINE constexpr explicit TRepeatView(W&& InValue, size_t InCount) requires (!bIsUnreachable) : Value(MoveTemp(InValue)), Count(InCount) { }
|
||||
|
||||
template <typename... Ts> requires (CConstructibleFrom<W, Ts...>)
|
||||
FORCEINLINE constexpr explicit TRepeatView(FInPlace, Ts&&... Args, size_t InCount) : Value(Forward<Ts>(Args)...), Count(InCount) { }
|
||||
|
||||
NODISCARD FORCEINLINE constexpr FIterator Begin() const { return FIterator(Value, 0); }
|
||||
|
||||
NODISCARD FORCEINLINE constexpr FSentinel End() const
|
||||
{
|
||||
if constexpr (bIsUnreachable)
|
||||
{
|
||||
return UnreachableSentinel;
|
||||
}
|
||||
|
||||
else return FSentinel(Value, Count);
|
||||
}
|
||||
|
||||
NODISCARD FORCEINLINE constexpr size_t Num() const requires (!bIsUnreachable) { return Count; }
|
||||
|
||||
private:
|
||||
|
||||
using FSizeType = TConditional<bIsUnreachable, FUnreachableSentinel, size_t>;
|
||||
|
||||
NO_UNIQUE_ADDRESS W Value;
|
||||
|
||||
NO_UNIQUE_ADDRESS FSizeType Count;
|
||||
|
||||
class FIteratorImpl final
|
||||
{
|
||||
public:
|
||||
|
||||
using FElementType = W;
|
||||
|
||||
FORCEINLINE constexpr FIteratorImpl() requires (CDefaultConstructible<W>) = default;
|
||||
|
||||
NODISCARD friend FORCEINLINE constexpr bool operator==(const FIteratorImpl& LHS, const FIteratorImpl& RHS) { return LHS.Current == RHS.Current; }
|
||||
|
||||
NODISCARD friend FORCEINLINE constexpr strong_ordering operator<=>(const FIteratorImpl& LHS, const FIteratorImpl& RHS) { return LHS.Current <=> RHS.Current; }
|
||||
|
||||
NODISCARD FORCEINLINE constexpr FReference operator*() const { return *Ptr; }
|
||||
NODISCARD FORCEINLINE constexpr const W* operator->() const { return Ptr; }
|
||||
|
||||
NODISCARD FORCEINLINE constexpr FReference operator[](ptrdiff) const { return *Ptr; }
|
||||
|
||||
FORCEINLINE constexpr FIteratorImpl& operator++() { ++Current; return *this; }
|
||||
FORCEINLINE constexpr FIteratorImpl& operator--() { --Current; return *this; }
|
||||
|
||||
FORCEINLINE constexpr FIteratorImpl operator++(int) { FIteratorImpl Temp = *this; ++*this; return Temp; }
|
||||
FORCEINLINE constexpr FIteratorImpl operator--(int) { FIteratorImpl Temp = *this; --*this; return Temp; }
|
||||
|
||||
FORCEINLINE constexpr FIteratorImpl& operator+=(ptrdiff Offset) { Current += Offset; return *this; }
|
||||
FORCEINLINE constexpr FIteratorImpl& operator-=(ptrdiff Offset) { Current -= Offset; return *this; }
|
||||
|
||||
NODISCARD friend FORCEINLINE constexpr FIteratorImpl operator+(FIteratorImpl Iter, ptrdiff Offset) { FIteratorImpl Temp = Iter; Temp += Offset; return Temp; }
|
||||
NODISCARD friend FORCEINLINE constexpr FIteratorImpl operator+(ptrdiff Offset, FIteratorImpl Iter) { FIteratorImpl Temp = Iter; Temp += Offset; return Temp; }
|
||||
|
||||
NODISCARD FORCEINLINE constexpr FIteratorImpl operator-(ptrdiff Offset) const { FIteratorImpl Temp = *this; Temp -= Offset; return Temp; }
|
||||
|
||||
NODISCARD friend FORCEINLINE constexpr ptrdiff operator-(const FIteratorImpl& LHS, const FIteratorImpl& RHS) { return LHS.Current - RHS.Current; }
|
||||
|
||||
private:
|
||||
|
||||
const W* Ptr;
|
||||
|
||||
NO_UNIQUE_ADDRESS size_t Current;
|
||||
|
||||
FORCEINLINE constexpr FIteratorImpl(const W& InObject, size_t InCurrent) : Ptr(AddressOf(InObject)), Current(InCurrent) { }
|
||||
|
||||
friend TRepeatView;
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
template <typename W>
|
||||
TRepeatView(W) -> TRepeatView<W>;
|
||||
|
||||
template <typename W>
|
||||
TRepeatView(W, size_t) -> TRepeatView<W, false>;
|
||||
|
||||
static_assert(CRandomAccessRange<TRepeatView<int, false>>);
|
||||
static_assert( CCommonRange<TRepeatView<int, false>>);
|
||||
static_assert( CSizedRange<TRepeatView<int, false>>);
|
||||
static_assert( CView<TRepeatView<int, false>>);
|
||||
|
||||
NAMESPACE_END(Range)
|
||||
|
||||
NAMESPACE_BEGIN(Range)
|
||||
|
||||
/** A view of no elements of a particular type. */
|
||||
template <CObject T>
|
||||
inline constexpr TEmptyView<T> Empty;
|
||||
|
||||
/** Creates a view that contains exactly one element of a specified value. */
|
||||
template <typename T> requires (CObject<TDecay<T>> && CMoveConstructible<TDecay<T>>)
|
||||
NODISCARD FORCEINLINE constexpr TSingleView<TDecay<T>> Single(T&& Value)
|
||||
{
|
||||
return TSingleView<TDecay<T>>(Forward<T>(Value));
|
||||
}
|
||||
|
||||
/** Creates a view that generates a sequence of elements by repeatedly incrementing an initial value. */
|
||||
template <typename W> requires (CWeaklyIncrementable<TDecay<W>> && CCopyable<TDecay<W>>)
|
||||
NODISCARD FORCEINLINE constexpr TIotaView<TDecay<W>> Iota(W&& Value)
|
||||
{
|
||||
return TIotaView<TDecay<W>>(Forward<W>(Value));
|
||||
}
|
||||
|
||||
/** Creates a view that generates a sequence of elements by repeatedly incrementing an initial value. */
|
||||
template <typename W, typename S> requires (CWeaklyIncrementable<TDecay<W>> && CWeaklyEqualityComparable<W, S> && CCopyable<TDecay<W>> && CSemiregular<TDecay<S>>)
|
||||
NODISCARD FORCEINLINE constexpr TIotaView<TDecay<W>, TDecay<S>> Iota(W&& Value, S&& Last)
|
||||
{
|
||||
return TIotaView<TDecay<W>, TDecay<S>>(Forward<W>(Value), Forward<S>(Last));
|
||||
}
|
||||
|
||||
/** Creates a view that generates a sequence of elements by repeatedly producing the same value. */
|
||||
template <typename W> requires (CObject<TDecay<W>> && CMoveConstructible<TDecay<W>>)
|
||||
NODISCARD FORCEINLINE constexpr TRepeatView<TDecay<W>> Repeat(W&& Value)
|
||||
{
|
||||
return TRepeatView<TDecay<W>>(Forward<W>(Value));
|
||||
}
|
||||
|
||||
/** Creates a view that generates a sequence of elements by repeatedly producing the same value. */
|
||||
template <typename W> requires (CObject<TDecay<W>> && CMoveConstructible<TDecay<W>>)
|
||||
NODISCARD FORCEINLINE constexpr TRepeatView<TDecay<W>, false> Repeat(W&& Value, size_t Count)
|
||||
{
|
||||
return TRepeatView<TDecay<W>, false>(Forward<W>(Value), Count);
|
||||
}
|
||||
|
||||
NAMESPACE_END(Range)
|
||||
|
||||
NAMESPACE_MODULE_END(Utility)
|
||||
NAMESPACE_MODULE_END(Redcraft)
|
||||
NAMESPACE_REDCRAFT_END
|
191
Redcraft.Utility/Source/Public/Ranges/FilterView.h
Normal file
191
Redcraft.Utility/Source/Public/Ranges/FilterView.h
Normal file
@ -0,0 +1,191 @@
|
||||
#pragma once
|
||||
|
||||
#include "CoreTypes.h"
|
||||
#include "TypeTraits/TypeTraits.h"
|
||||
#include "Templates/Utility.h"
|
||||
#include "Templates/Invoke.h"
|
||||
#include "Iterators/Utility.h"
|
||||
#include "Iterators/BasicIterator.h"
|
||||
#include "Memory/Address.h"
|
||||
#include "Ranges/Utility.h"
|
||||
#include "Ranges/Pipe.h"
|
||||
#include "Ranges/View.h"
|
||||
#include "Ranges/AllView.h"
|
||||
|
||||
NAMESPACE_REDCRAFT_BEGIN
|
||||
NAMESPACE_MODULE_BEGIN(Redcraft)
|
||||
NAMESPACE_MODULE_BEGIN(Utility)
|
||||
|
||||
NAMESPACE_BEGIN(Range)
|
||||
|
||||
/**
|
||||
* A view adapter that consists of the elements of a range that satisfies a predicate.
|
||||
* When based on an input view, the filter view satisfies at least an input view up to a bidirectional view.
|
||||
* When based on a common view, the filter view satisfies a common view.
|
||||
*/
|
||||
template <CInputRange V, CPredicate<TRangeReference<V>> Pred> requires (CView<V> && CObject<Pred> && CMoveConstructible<Pred>)
|
||||
class TFilterView : public IBasicViewInterface<TFilterView<V, Pred>>
|
||||
{
|
||||
private:
|
||||
|
||||
class FIteratorImpl;
|
||||
class FSentinelImpl;
|
||||
|
||||
public:
|
||||
|
||||
using FElementType = TRangeElement<V>;
|
||||
using FReference = TRangeReference<V>;
|
||||
|
||||
using FIterator = FIteratorImpl;
|
||||
|
||||
using FSentinel = TConditional<CCommonRange<V>, FIteratorImpl, FSentinelImpl>;
|
||||
|
||||
FORCEINLINE constexpr TFilterView() requires (CDefaultConstructible<V> && CDefaultConstructible<Pred>) = default;
|
||||
|
||||
FORCEINLINE constexpr explicit TFilterView(V InBase, Pred InPredicate) : Base(MoveTemp(InBase)), Predicate(MoveTemp(InPredicate)) { }
|
||||
|
||||
NODISCARD FORCEINLINE constexpr FIterator Begin()
|
||||
{
|
||||
FIterator Iter(*this, Range::Begin(Base));
|
||||
|
||||
do
|
||||
{
|
||||
if (Iter == End()) break;
|
||||
|
||||
if (InvokeResult<bool>(GetPredicate(), *Iter)) break;
|
||||
|
||||
++Iter;
|
||||
}
|
||||
while (false);
|
||||
|
||||
if constexpr (!CForwardRange<V>) return MoveTemp(Iter);
|
||||
|
||||
return Iter;
|
||||
}
|
||||
|
||||
NODISCARD FORCEINLINE constexpr FSentinel End() { return FSentinel(*this, Range::End(Base)); }
|
||||
|
||||
NODISCARD FORCEINLINE constexpr V GetBase() const& requires (CCopyConstructible<V>) { 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;
|
||||
|
||||
class FIteratorImpl final
|
||||
{
|
||||
|
||||
public:
|
||||
|
||||
using FElementType = TIteratorElement<TRangeIterator<V>>;
|
||||
|
||||
FORCEINLINE constexpr FIteratorImpl() requires (CDefaultConstructible<TRangeIterator<V>>) { } // Use '{ }' instead of '= default;' to avoid MSVC bug.
|
||||
|
||||
NODISCARD friend FORCEINLINE constexpr bool operator==(const FIteratorImpl& LHS, const FIteratorImpl& RHS)
|
||||
{
|
||||
return LHS.GetBase() == RHS.GetBase();
|
||||
}
|
||||
|
||||
NODISCARD FORCEINLINE constexpr TRangeReference<V> operator*() const { return *GetBase(); }
|
||||
|
||||
NODISCARD FORCEINLINE constexpr auto operator->() const requires (requires(const TRangeIterator<V> Iter) { { ToAddress(Iter) } -> CSameAs<TIteratorPointer<TRangeIterator<V>>>; }) { return ToAddress(GetBase()); }
|
||||
|
||||
FORCEINLINE constexpr FIteratorImpl& operator++()
|
||||
{
|
||||
do ++Current; while (*this != Owner->End() && !InvokeResult<bool>(Owner->GetPredicate(), *Current));
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
FORCEINLINE constexpr FIteratorImpl& operator--() requires (CBidirectionalIterator<TRangeIterator<V>>)
|
||||
{
|
||||
do --Current; while (!InvokeResult<bool>(Owner->GetPredicate(), *Current));
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
FORCEINLINE constexpr void operator++(int) { ++*this; }
|
||||
FORCEINLINE constexpr FIteratorImpl operator++(int) requires (CForwardIterator<TRangeIterator<V>>) { FIteratorImpl Temp = *this; ++*this; return Temp; }
|
||||
FORCEINLINE constexpr FIteratorImpl operator--(int) requires (CBidirectionalIterator<TRangeIterator<V>>) { FIteratorImpl Temp = *this; --*this; return Temp; }
|
||||
|
||||
NODISCARD FORCEINLINE constexpr const TRangeIterator<V>& GetBase() const& { return Current; }
|
||||
NODISCARD FORCEINLINE constexpr TRangeIterator<V> GetBase() && { return MoveTemp(Current); }
|
||||
|
||||
private:
|
||||
|
||||
TFilterView* Owner;
|
||||
|
||||
NO_UNIQUE_ADDRESS TRangeIterator<V> Current;
|
||||
|
||||
FORCEINLINE constexpr FIteratorImpl(TFilterView& InOwner, TRangeIterator<V> InCurrent) : Owner(&InOwner), Current(MoveTemp(InCurrent)) { }
|
||||
|
||||
friend FSentinelImpl;
|
||||
|
||||
friend TFilterView;
|
||||
};
|
||||
|
||||
class FSentinelImpl final
|
||||
{
|
||||
public:
|
||||
|
||||
FORCEINLINE constexpr FSentinelImpl() = default;
|
||||
|
||||
NODISCARD FORCEINLINE constexpr bool operator==(const FIteratorImpl& InValue) const& { return Current == InValue.Current; }
|
||||
|
||||
NODISCARD FORCEINLINE constexpr TRangeSentinel<V> GetBase() const { return Current; }
|
||||
|
||||
private:
|
||||
|
||||
TRangeSentinel<V> Current;
|
||||
|
||||
FORCEINLINE constexpr FSentinelImpl(TFilterView& InOwner, TRangeSentinel<V> InCurrent) : Current(InCurrent) { }
|
||||
|
||||
friend TFilterView;
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
template <typename R, typename Pred>
|
||||
TFilterView(R&&, Pred) -> TFilterView<TAllView<R>, Pred>;
|
||||
|
||||
static_assert( CInputRange<TFilterView<TAllView<IRange< IInputIterator<int&>>>, bool(*)(int)>>);
|
||||
static_assert( CForwardRange<TFilterView<TAllView<IRange< IForwardIterator<int&>>>, bool(*)(int)>>);
|
||||
static_assert(CBidirectionalRange<TFilterView<TAllView<IRange<IBidirectionalIterator<int&>>>, bool(*)(int)>>);
|
||||
static_assert(CBidirectionalRange<TFilterView<TAllView<IRange< IRandomAccessIterator<int&>>>, bool(*)(int)>>);
|
||||
static_assert(CBidirectionalRange<TFilterView<TAllView<IRange< IContiguousIterator<int&>>>, bool(*)(int)>>);
|
||||
|
||||
static_assert(CCommonRange<TFilterView<TAllView<ICommonRange<IForwardIterator<int>>>, bool(*)(int)>>);
|
||||
static_assert( CView<TFilterView<TAllView< IRange< IInputIterator<int>>>, bool(*)(int)>>);
|
||||
|
||||
NAMESPACE_END(Range)
|
||||
|
||||
NAMESPACE_BEGIN(Range)
|
||||
|
||||
/** Creates A view adapter that consists of the elements of a range that satisfies a predicate. */
|
||||
template <CViewableRange R, typename Pred> requires (requires { TFilterView(DeclVal<R>(), DeclVal<Pred>()); })
|
||||
NODISCARD FORCEINLINE constexpr auto Filter(R&& Base, Pred&& Predicate)
|
||||
{
|
||||
return TFilterView(Forward<R>(Base), Forward<Pred>(Predicate));
|
||||
}
|
||||
|
||||
/** Creates A view adapter that consists of the elements of a range that satisfies a predicate. */
|
||||
template <typename Pred>
|
||||
NODISCARD FORCEINLINE constexpr auto Filter(Pred&& Predicate)
|
||||
{
|
||||
using FClosure = decltype([]<CViewableRange R, typename T> requires (requires { Range::Filter(DeclVal<R>(), DeclVal<T>()); }) (R&& Base, T&& Predicate)
|
||||
{
|
||||
return Range::Filter(Forward<R>(Base), Forward<T>(Predicate));
|
||||
});
|
||||
|
||||
return TAdaptorClosure<FClosure, TDecay<Pred>>(Forward<Pred>(Predicate));
|
||||
}
|
||||
|
||||
NAMESPACE_END(Range)
|
||||
|
||||
NAMESPACE_MODULE_END(Utility)
|
||||
NAMESPACE_MODULE_END(Redcraft)
|
||||
NAMESPACE_REDCRAFT_END
|
118
Redcraft.Utility/Source/Public/Ranges/MoveView.h
Normal file
118
Redcraft.Utility/Source/Public/Ranges/MoveView.h
Normal file
@ -0,0 +1,118 @@
|
||||
#pragma once
|
||||
|
||||
#include "CoreTypes.h"
|
||||
#include "TypeTraits/TypeTraits.h"
|
||||
#include "Templates/Utility.h"
|
||||
#include "Iterators/Utility.h"
|
||||
#include "Iterators/BasicIterator.h"
|
||||
#include "Iterators/MoveIterator.h"
|
||||
#include "Ranges/Utility.h"
|
||||
#include "Ranges/Pipe.h"
|
||||
#include "Ranges/View.h"
|
||||
#include "Ranges/AllView.h"
|
||||
|
||||
NAMESPACE_REDCRAFT_BEGIN
|
||||
NAMESPACE_MODULE_BEGIN(Redcraft)
|
||||
NAMESPACE_MODULE_BEGIN(Utility)
|
||||
|
||||
NAMESPACE_BEGIN(Range)
|
||||
|
||||
/**
|
||||
* A view adapter which dereferences to a rvalue reference.
|
||||
* When based on an input view, the move view satisfies at least an input view up to a random access view.
|
||||
* When based on a common view, the move view satisfies a common view.
|
||||
*/
|
||||
template <CInputRange V> requires (CView<V>)
|
||||
class TMoveView : public IBasicViewInterface<TMoveView<V>>
|
||||
{
|
||||
public:
|
||||
|
||||
using FElementType = TRangeElement<V>;
|
||||
using FReference = TRangeRValueReference<V>;
|
||||
|
||||
FORCEINLINE constexpr TMoveView() requires (CDefaultConstructible<V>) = default;
|
||||
|
||||
FORCEINLINE constexpr explicit TMoveView(V InBase) : Base(MoveTemp(InBase)) { }
|
||||
|
||||
NODISCARD FORCEINLINE constexpr auto Begin() requires (!CSimpleView<V>)
|
||||
{
|
||||
return MakeMoveIterator(Range::Begin(Base));
|
||||
}
|
||||
|
||||
NODISCARD FORCEINLINE constexpr auto Begin() const requires (CRange<const V>)
|
||||
{
|
||||
return MakeMoveIterator(Range::Begin(Base));
|
||||
}
|
||||
|
||||
NODISCARD FORCEINLINE constexpr auto End() requires (!CSimpleView<V>)
|
||||
{
|
||||
if constexpr (CCommonRange<V>)
|
||||
{
|
||||
return MakeMoveIterator(Range::End(Base));
|
||||
}
|
||||
else return MakeMoveSentinel(Range::End(Base));
|
||||
}
|
||||
|
||||
NODISCARD FORCEINLINE constexpr auto End() const requires (CRange<const V>)
|
||||
{
|
||||
if constexpr (CCommonRange<V>)
|
||||
{
|
||||
return MakeMoveIterator(Range::End(Base));
|
||||
}
|
||||
else return MakeMoveSentinel(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<const V>) { return Range::Num(Base); }
|
||||
|
||||
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;
|
||||
|
||||
};
|
||||
|
||||
template <typename R>
|
||||
TMoveView(R&&) -> TMoveView<TAllView<R>>;
|
||||
|
||||
static_assert( CInputRange<TMoveView<TAllView<IRange< IInputIterator<int&>>>>>);
|
||||
static_assert( CForwardRange<TMoveView<TAllView<IRange< IForwardIterator<int&>>>>>);
|
||||
static_assert(CBidirectionalRange<TMoveView<TAllView<IRange<IBidirectionalIterator<int&>>>>>);
|
||||
static_assert( CRandomAccessRange<TMoveView<TAllView<IRange< IRandomAccessIterator<int&>>>>>);
|
||||
static_assert( CRandomAccessRange<TMoveView<TAllView<IRange< IContiguousIterator<int&>>>>>);
|
||||
|
||||
static_assert(CCommonRange<TMoveView<TAllView<ICommonRange<IForwardIterator<int>>>>>);
|
||||
static_assert( CView<TMoveView<TAllView< IRange< IInputIterator<int>>>>>);
|
||||
|
||||
NAMESPACE_END(Range)
|
||||
|
||||
template <typename T>
|
||||
constexpr bool bEnableBorrowedRange<Range::TMoveView<T>> = bEnableBorrowedRange<T>;
|
||||
|
||||
NAMESPACE_BEGIN(Range)
|
||||
|
||||
/** Creates A view adapter that dereferences to a rvalue reference. */
|
||||
template <CViewableRange R> requires (requires { TMoveView(DeclVal<R>()); })
|
||||
NODISCARD FORCEINLINE constexpr auto Move(R&& Base)
|
||||
{
|
||||
return TMoveView(Forward<R>(Base));
|
||||
}
|
||||
|
||||
/** Creates A view adapter that dereferences to a rvalue reference. */
|
||||
NODISCARD FORCEINLINE constexpr auto Move()
|
||||
{
|
||||
using FClosure = decltype([]<CViewableRange R> requires (requires { Range::Move(DeclVal<R>()); }) (R&& Base)
|
||||
{
|
||||
return Range::Move(Forward<R>(Base));
|
||||
});
|
||||
|
||||
return TAdaptorClosure<FClosure>();
|
||||
}
|
||||
|
||||
NAMESPACE_END(Range)
|
||||
|
||||
NAMESPACE_MODULE_END(Utility)
|
||||
NAMESPACE_MODULE_END(Redcraft)
|
||||
NAMESPACE_REDCRAFT_END
|
146
Redcraft.Utility/Source/Public/Ranges/Pipe.h
Normal file
146
Redcraft.Utility/Source/Public/Ranges/Pipe.h
Normal file
@ -0,0 +1,146 @@
|
||||
#pragma once
|
||||
|
||||
#include "CoreTypes.h"
|
||||
#include "Ranges/Utility.h"
|
||||
#include "Templates/Tuple.h"
|
||||
#include "Templates/Invoke.h"
|
||||
#include "Templates/Utility.h"
|
||||
#include "TypeTraits/TypeTraits.h"
|
||||
|
||||
NAMESPACE_REDCRAFT_BEGIN
|
||||
NAMESPACE_MODULE_BEGIN(Redcraft)
|
||||
NAMESPACE_MODULE_BEGIN(Utility)
|
||||
|
||||
NAMESPACE_BEGIN(Range)
|
||||
|
||||
/**
|
||||
* An interface class template for defining a range adaptor closure.
|
||||
* When the derived class has a unary operator() with range as a reference and is not itself a range,
|
||||
* the derived class is the range adaptor closure type and its objects can participate in pipe operations.
|
||||
* Specify, the unary operator() with any reference qualifier or cv-qualifier must be defined and has same effect.
|
||||
* Not directly instantiable.
|
||||
*/
|
||||
template <CObject D> requires (CSameAs<D, TRemoveCV<D>>)
|
||||
class IAdaptorClosure { };
|
||||
|
||||
/** An adaptor closure helper that wraps a callable object. */
|
||||
template <CDefaultConstructible F, CMoveConstructible... Ts> requires (CEmpty<F> && ... && CSameAs<TDecay<Ts>, Ts>)
|
||||
class TAdaptorClosure : public IAdaptorClosure<TAdaptorClosure<F, Ts...>>
|
||||
{
|
||||
public:
|
||||
|
||||
template <typename... Us> requires (CConstructibleFrom<TTuple<Ts...>, Us...> && ... && CSameAs<TDecay<Us>, Ts>)
|
||||
FORCEINLINE constexpr explicit TAdaptorClosure(Us&&... InArgs) : Args(Forward<Us>(InArgs)...) { }
|
||||
|
||||
template <typename R> requires (CInvocable<F, R, Ts&...>)
|
||||
NODISCARD FORCEINLINE constexpr auto operator()(R&& Range) &
|
||||
{
|
||||
return [this, &Range]<size_t... Indices>(TIndexSequence<Indices...>)
|
||||
{
|
||||
return Invoke(F(), Forward<R>(Range), Args.template GetValue<Indices>()...);
|
||||
}
|
||||
(TMakeIndexSequence<sizeof...(Ts)>());
|
||||
}
|
||||
|
||||
template <typename R> requires (CInvocable<F, R, const Ts&...>)
|
||||
NODISCARD FORCEINLINE constexpr auto operator()(R&& Range) const&
|
||||
{
|
||||
return [this, &Range]<size_t... Indices>(TIndexSequence<Indices...>)
|
||||
{
|
||||
return Invoke(F(), Forward<R>(Range), Args.template GetValue<Indices>()...);
|
||||
}
|
||||
(TMakeIndexSequence<sizeof...(Ts)>());
|
||||
}
|
||||
|
||||
template <typename R> requires (CInvocable<F, R, Ts&&...>)
|
||||
NODISCARD FORCEINLINE constexpr auto operator()(R&& Range) &&
|
||||
{
|
||||
return [this, &Range]<size_t... Indices>(TIndexSequence<Indices...>)
|
||||
{
|
||||
return Invoke(F(), Forward<R>(Range), MoveTemp(Args).template GetValue<Indices>()...);
|
||||
}
|
||||
(TMakeIndexSequence<sizeof...(Ts)>());
|
||||
}
|
||||
|
||||
template <typename R> requires (CInvocable<F, R, const Ts&&...>)
|
||||
NODISCARD FORCEINLINE constexpr auto operator()(R&& Range) const&&
|
||||
{
|
||||
return [this, &Range]<size_t... Indices>(TIndexSequence<Indices...>)
|
||||
{
|
||||
return Invoke(F(), Forward<R>(Range), MoveTemp(Args).template GetValue<Indices>()...);
|
||||
}
|
||||
(TMakeIndexSequence<sizeof...(Ts)>());
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
NO_UNIQUE_ADDRESS TTuple<Ts...> Args;
|
||||
|
||||
};
|
||||
|
||||
/** A pipe closure that wraps two adaptor closures. */
|
||||
template <CMoveConstructible T, CMoveConstructible U>
|
||||
requires (CSameAs<TRemoveCVRef<T>, T> && CDerivedFrom<T, IAdaptorClosure<T>>
|
||||
&& CSameAs<TRemoveCVRef<U>, U> && CDerivedFrom<U, IAdaptorClosure<U>>)
|
||||
class TPipeClosure final : public IAdaptorClosure<TPipeClosure<T, U>>
|
||||
{
|
||||
public:
|
||||
|
||||
template <typename V, typename W>
|
||||
requires (CSameAs<TRemoveCVRef<V>, T> && CConstructibleFrom<T, V>
|
||||
&& CSameAs<TRemoveCVRef<W>, U> && CConstructibleFrom<U, W>)
|
||||
FORCEINLINE constexpr explicit TPipeClosure(V InLHS, W InRHS)
|
||||
: LHS(Forward<V>(InLHS)), RHS(Forward<W>(InRHS))
|
||||
{ }
|
||||
|
||||
template <typename R> requires (CInvocable<T&, R> && CInvocable<U&, TInvokeResult<T&, R>>)
|
||||
NODISCARD FORCEINLINE constexpr auto operator()(R&& Range) &
|
||||
{
|
||||
return Forward<R>(Range) | LHS | RHS;
|
||||
}
|
||||
|
||||
template <typename R> requires (CInvocable<const T&, R> && CInvocable<const U&, TInvokeResult<const T&, R>>)
|
||||
NODISCARD FORCEINLINE constexpr auto operator()(R&& Range) const&
|
||||
{
|
||||
return Forward<R>(Range) | LHS | RHS;
|
||||
}
|
||||
|
||||
template <typename R> requires (CInvocable<T&&, R> && CInvocable<U&&, TInvokeResult<T&&, R>>)
|
||||
NODISCARD FORCEINLINE constexpr auto operator()(R&& Range) &&
|
||||
{
|
||||
return Forward<R>(Range) | MoveTemp(LHS) | MoveTemp(RHS);
|
||||
}
|
||||
|
||||
template <typename R> requires (CInvocable<const T&&, R> && CInvocable<const U&&, TInvokeResult<const T&&, R>>)
|
||||
NODISCARD FORCEINLINE constexpr auto operator()(R&& Range) const&&
|
||||
{
|
||||
return Forward<R>(Range) | MoveTemp(LHS) | MoveTemp(RHS);
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
NO_UNIQUE_ADDRESS T LHS;
|
||||
NO_UNIQUE_ADDRESS U RHS;
|
||||
};
|
||||
|
||||
/** Apply the range adaptor closure to the range. */
|
||||
template <CRange R, CInvocable<R> T> requires (CDerivedFrom<TRemoveCVRef<T>, IAdaptorClosure<TRemoveCVRef<T>>>)
|
||||
NODISCARD FORCEINLINE constexpr auto operator|(R&& Range, T&& Closure)
|
||||
{
|
||||
return Invoke(Forward<T>(Closure), Forward<R>(Range));
|
||||
}
|
||||
|
||||
/** Create a pipe closure that wraps two adaptor closures. */
|
||||
template <CMoveConstructible T, CMoveConstructible U>
|
||||
requires (CDerivedFrom<TRemoveCVRef<T>, IAdaptorClosure<TRemoveCVRef<T>>>
|
||||
&& CDerivedFrom<TRemoveCVRef<U>, IAdaptorClosure<TRemoveCVRef<U>>>)
|
||||
NODISCARD FORCEINLINE constexpr auto operator|(T&& LHS, U&& RHS)
|
||||
{
|
||||
return TPipeClosure<TRemoveCVRef<T>, TRemoveCVRef<U>>(Forward<T>(LHS), Forward<U>(RHS));
|
||||
}
|
||||
|
||||
NAMESPACE_END(Range)
|
||||
|
||||
NAMESPACE_MODULE_END(Utility)
|
||||
NAMESPACE_MODULE_END(Redcraft)
|
||||
NAMESPACE_REDCRAFT_END
|
14
Redcraft.Utility/Source/Public/Ranges/Ranges.h
Normal file
14
Redcraft.Utility/Source/Public/Ranges/Ranges.h
Normal file
@ -0,0 +1,14 @@
|
||||
#pragma once
|
||||
|
||||
#include "CoreTypes.h"
|
||||
#include "Ranges/Utility.h"
|
||||
#include "Ranges/View.h"
|
||||
#include "Ranges/Conversion.h"
|
||||
#include "Ranges/Factory.h"
|
||||
#include "Ranges/Pipe.h"
|
||||
#include "Ranges/AllView.h"
|
||||
#include "Ranges/MoveView.h"
|
||||
#include "Ranges/FilterView.h"
|
||||
#include "Ranges/TransformView.h"
|
||||
#include "Ranges/TakeView.h"
|
||||
#include "Ranges/TakeWhileView.h"
|
186
Redcraft.Utility/Source/Public/Ranges/TakeView.h
Normal file
186
Redcraft.Utility/Source/Public/Ranges/TakeView.h
Normal file
@ -0,0 +1,186 @@
|
||||
#pragma once
|
||||
|
||||
#include "CoreTypes.h"
|
||||
#include "TypeTraits/TypeTraits.h"
|
||||
#include "Templates/Utility.h"
|
||||
#include "Iterators/Utility.h"
|
||||
#include "Iterators/BasicIterator.h"
|
||||
#include "Iterators/CountedIterator.h"
|
||||
#include "Numerics/Math.h"
|
||||
#include "Ranges/Utility.h"
|
||||
#include "Ranges/Pipe.h"
|
||||
#include "Ranges/View.h"
|
||||
#include "Ranges/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() requires (!CSimpleView<V>)
|
||||
{
|
||||
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() requires (!CSimpleView<V>)
|
||||
{
|
||||
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 TRangeSentinel<FBase> GetBase() const { return 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
|
149
Redcraft.Utility/Source/Public/Ranges/TakeWhileView.h
Normal file
149
Redcraft.Utility/Source/Public/Ranges/TakeWhileView.h
Normal file
@ -0,0 +1,149 @@
|
||||
#pragma once
|
||||
|
||||
#include "CoreTypes.h"
|
||||
#include "TypeTraits/TypeTraits.h"
|
||||
#include "Templates/Utility.h"
|
||||
#include "Iterators/Utility.h"
|
||||
#include "Iterators/BasicIterator.h"
|
||||
#include "Iterators/CountedIterator.h"
|
||||
#include "Numerics/Math.h"
|
||||
#include "Ranges/Utility.h"
|
||||
#include "Ranges/Pipe.h"
|
||||
#include "Ranges/View.h"
|
||||
#include "Ranges/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 <CInputRange V, CPredicate<TRangeReference<V>> Pred> requires (CView<V> && CObject<Pred> && CMoveConstructible<Pred>)
|
||||
class TTakeWhileView : public IBasicViewInterface<TTakeWhileView<V, Pred>>
|
||||
{
|
||||
private:
|
||||
|
||||
template <bool bConst> class FSentinelImpl;
|
||||
|
||||
public:
|
||||
|
||||
using FElementType = TRangeElement<V>;
|
||||
using FReference = TRangeReference<V>;
|
||||
|
||||
FORCEINLINE constexpr TTakeWhileView() requires (CDefaultConstructible<V>&& CDefaultConstructible<Pred>) = default;
|
||||
|
||||
FORCEINLINE constexpr explicit TTakeWhileView(V InBase, Pred InPredicate) : Base(MoveTemp(InBase)), Predicate(MoveTemp(InPredicate)) { }
|
||||
|
||||
NODISCARD FORCEINLINE constexpr auto Begin() requires (!CSimpleView<V>)
|
||||
{
|
||||
return Range::Begin(Base);
|
||||
}
|
||||
|
||||
NODISCARD FORCEINLINE constexpr auto Begin() const requires (CRange<const V> && CPredicate<const Pred&, TRangeReference<const V>>)
|
||||
{
|
||||
return Range::Begin(Base);
|
||||
}
|
||||
|
||||
NODISCARD FORCEINLINE constexpr auto End() requires (!CSimpleView<V>)
|
||||
{
|
||||
return FSentinelImpl<false>(Range::End(Base), AddressOf(Predicate));
|
||||
}
|
||||
|
||||
NODISCARD FORCEINLINE constexpr auto End() const requires (CRange<const V> && CPredicate<const Pred&, TRangeReference<const V>>)
|
||||
{
|
||||
return FSentinelImpl<true>(Range::End(Base), AddressOf(Predicate));
|
||||
}
|
||||
|
||||
NODISCARD FORCEINLINE constexpr V GetBase() const& requires (CCopyConstructible<V>) { 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 <bool bConst>
|
||||
class FSentinelImpl final
|
||||
{
|
||||
private:
|
||||
|
||||
using FBase = TConditional<bConst, const V, V>;
|
||||
using FPred = TConditional<bConst, const Pred, Pred>;
|
||||
|
||||
public:
|
||||
|
||||
FORCEINLINE constexpr FSentinelImpl() = default;
|
||||
|
||||
FORCEINLINE constexpr FSentinelImpl(FSentinelImpl<!bConst> Sentinel) requires (bConst && CConvertibleTo<TRangeSentinel<V>, TRangeSentinel<FBase>>)
|
||||
: Current(Sentinel.Current), Predicate(Sentinel.Predicate)
|
||||
{ }
|
||||
|
||||
NODISCARD FORCEINLINE constexpr bool operator==(const TRangeIterator<FBase>& InValue) const&
|
||||
{
|
||||
return InValue == Current || !InvokeResult<bool>(*Predicate, *InValue);
|
||||
}
|
||||
|
||||
NODISCARD FORCEINLINE constexpr TRangeSentinel<FBase> GetBase() const { return Current; }
|
||||
|
||||
private:
|
||||
|
||||
NO_UNIQUE_ADDRESS TRangeSentinel<FBase> Current;
|
||||
|
||||
FPred* Predicate;
|
||||
|
||||
FORCEINLINE constexpr FSentinelImpl(TRangeSentinel<FBase> InCurrent, FPred* InPredicate) : Current(InCurrent), Predicate(InPredicate) { }
|
||||
|
||||
friend TTakeWhileView;
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
template <typename R, typename Pred>
|
||||
TTakeWhileView(R&&, Pred) -> TTakeWhileView<TAllView<R>, Pred>;
|
||||
|
||||
static_assert( CInputRange<TTakeWhileView<TAllView<IRange< IInputIterator<int&>>>, bool(*)(int)>>);
|
||||
static_assert( CForwardRange<TTakeWhileView<TAllView<IRange< IForwardIterator<int&>>>, bool(*)(int)>>);
|
||||
static_assert(CBidirectionalRange<TTakeWhileView<TAllView<IRange<IBidirectionalIterator<int&>>>, bool(*)(int)>>);
|
||||
static_assert( CRandomAccessRange<TTakeWhileView<TAllView<IRange< IRandomAccessIterator<int&>>>, bool(*)(int)>>);
|
||||
static_assert( CContiguousRange<TTakeWhileView<TAllView<IRange< IContiguousIterator<int&>>>, bool(*)(int)>>);
|
||||
|
||||
static_assert(CView<TTakeWhileView<TAllView<IRange<IInputIterator<int>>>, bool(*)(int)>>);
|
||||
|
||||
static_assert(COutputRange<TTakeWhileView<TAllView<IRange<IForwardIterator<int&>>>, 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 <CViewableRange R, typename Pred> requires (requires { TTakeWhileView(DeclVal<R>(), DeclVal<Pred>()); })
|
||||
NODISCARD FORCEINLINE constexpr auto TakeWhile(R&& Base, Pred&& Predicate)
|
||||
{
|
||||
return TTakeWhileView(Forward<R>(Base), Forward<Pred>(Predicate));
|
||||
}
|
||||
|
||||
/** Creates A view adapter that includes elements that satisfy the predicate from the beginning of the range. */
|
||||
template <typename Pred>
|
||||
NODISCARD FORCEINLINE constexpr auto TakeWhile(Pred&& Predicate)
|
||||
{
|
||||
using FClosure = decltype([]<CViewableRange R, typename T> requires (requires { Range::TakeWhile(DeclVal<R>(), DeclVal<T>()); }) (R&& Base, T&& Predicate)
|
||||
{
|
||||
return Range::TakeWhile(Forward<R>(Base), Forward<T>(Predicate));
|
||||
});
|
||||
|
||||
return TAdaptorClosure<FClosure, TDecay<Pred>>(Forward<Pred>(Predicate));
|
||||
}
|
||||
|
||||
NAMESPACE_END(Range)
|
||||
|
||||
NAMESPACE_MODULE_END(Utility)
|
||||
NAMESPACE_MODULE_END(Redcraft)
|
||||
NAMESPACE_REDCRAFT_END
|
236
Redcraft.Utility/Source/Public/Ranges/TransformView.h
Normal file
236
Redcraft.Utility/Source/Public/Ranges/TransformView.h
Normal file
@ -0,0 +1,236 @@
|
||||
#pragma once
|
||||
|
||||
#include "CoreTypes.h"
|
||||
#include "Ranges/View.h"
|
||||
#include "Ranges/Pipe.h"
|
||||
#include "Ranges/Utility.h"
|
||||
#include "Ranges/AllView.h"
|
||||
#include "Templates/Invoke.h"
|
||||
#include "Templates/Utility.h"
|
||||
#include "TypeTraits/TypeTraits.h"
|
||||
|
||||
NAMESPACE_REDCRAFT_BEGIN
|
||||
NAMESPACE_MODULE_BEGIN(Redcraft)
|
||||
NAMESPACE_MODULE_BEGIN(Utility)
|
||||
|
||||
NAMESPACE_BEGIN(Range)
|
||||
|
||||
/**
|
||||
* A view adapter of a sequence that applies a transformation function to each element.
|
||||
* When based on an input view, the transform view satisfies at least an input view up to a random access view.
|
||||
* When based on a common view, the transform view satisfies a common view. When based on a sized view,
|
||||
* the transform view satisfies a sized view. When based on a forward view and the function return
|
||||
* an assignable value, the transform view satisfies an output view.
|
||||
*/
|
||||
template <CInputRange V, CMoveConstructible F> requires (CView<V> && CObject<F>
|
||||
&& CRegularInvocable<F&, TRangeReference<V>> && CReferenceable<TInvokeResult<F&, TRangeReference<V>>>)
|
||||
class TTransformView : public IBasicViewInterface<TTransformView<V, F>>
|
||||
{
|
||||
private:
|
||||
|
||||
template <bool bConst> class FIteratorImpl;
|
||||
template <bool bConst> class FSentinelImpl;
|
||||
|
||||
public:
|
||||
|
||||
FORCEINLINE constexpr TTransformView() requires (CDefaultConstructible<V>&& CDefaultConstructible<F>) = default;
|
||||
|
||||
FORCEINLINE constexpr explicit TTransformView(V InBase, F InFunc) : Base(MoveTemp(InBase)), Func(MoveTemp(InFunc)) { }
|
||||
|
||||
NODISCARD FORCEINLINE constexpr auto Begin()
|
||||
{
|
||||
return FIteratorImpl<false>(*this, Range::Begin(Base));
|
||||
}
|
||||
|
||||
NODISCARD FORCEINLINE constexpr auto Begin() const requires (CRange<const V> && CRegularInvocable<const F&, TRangeReference<const V>>)
|
||||
{
|
||||
return FIteratorImpl<true>(*this, Range::Begin(Base));
|
||||
}
|
||||
|
||||
NODISCARD FORCEINLINE constexpr auto End()
|
||||
{
|
||||
if constexpr (CCommonRange<V>)
|
||||
{
|
||||
return FIteratorImpl<false>(*this, Range::End(Base));
|
||||
}
|
||||
|
||||
else return FSentinelImpl<false>(*this, Range::End(Base));
|
||||
}
|
||||
|
||||
NODISCARD FORCEINLINE constexpr auto End() const requires (CRange<const V> && CRegularInvocable<const F&, TRangeReference<const V>>)
|
||||
{
|
||||
if constexpr (CCommonRange<const V>)
|
||||
{
|
||||
return FIteratorImpl<true>(*this, Range::End(Base));
|
||||
}
|
||||
|
||||
else return FSentinelImpl<true>(*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<const V>) { return Range::Num(Base); }
|
||||
|
||||
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;
|
||||
NO_UNIQUE_ADDRESS F Func;
|
||||
|
||||
template <bool bConst>
|
||||
class FIteratorImpl
|
||||
{
|
||||
private:
|
||||
|
||||
using FOwner = TConditional<bConst, const TTransformView, TTransformView>;
|
||||
using FBase = TConditional<bConst, const V, V>;
|
||||
using FFunc = TConditional<bConst, const F, F>;
|
||||
|
||||
public:
|
||||
|
||||
using FElementType = TRemoveCVRef<TInvokeResult<FFunc&, TRangeReference<FBase>>>;
|
||||
|
||||
FORCEINLINE constexpr FIteratorImpl() requires (CDefaultConstructible<TRangeIterator<FBase>>) = default;
|
||||
|
||||
FORCEINLINE constexpr FIteratorImpl(FIteratorImpl<!bConst> Iter) requires (bConst && CConvertibleTo<TRangeIterator<V>, TRangeIterator<FBase>>)
|
||||
: Owner(Iter.Owner), Current(MoveTemp(Iter).GetBase())
|
||||
{ }
|
||||
|
||||
NODISCARD friend FORCEINLINE constexpr bool operator==(const FIteratorImpl& LHS, const FIteratorImpl& RHS) requires (CEqualityComparable<TRangeIterator<FBase>>)
|
||||
{
|
||||
return LHS.GetBase() == RHS.GetBase();
|
||||
}
|
||||
|
||||
NODISCARD friend FORCEINLINE constexpr auto operator<=>(const FIteratorImpl& LHS, const FIteratorImpl& RHS) requires (CThreeWayComparable<TRangeIterator<FBase>>)
|
||||
{
|
||||
return LHS.GetBase() <=> RHS.GetBase();
|
||||
}
|
||||
|
||||
NODISCARD FORCEINLINE constexpr decltype(auto) operator*() const { return Invoke(Owner->Func, *GetBase()); }
|
||||
|
||||
NODISCARD FORCEINLINE constexpr decltype(auto) operator[](ptrdiff Index) const requires (CRandomAccessRange<FBase>) { return Invoke(Owner->Func, GetBase()[Index]); }
|
||||
|
||||
FORCEINLINE constexpr FIteratorImpl& operator++() { ++Current; return *this; }
|
||||
FORCEINLINE constexpr FIteratorImpl& operator--() requires (CBidirectionalRange<FBase>) { --Current; return *this; }
|
||||
|
||||
FORCEINLINE constexpr void operator++(int) { ++*this; }
|
||||
FORCEINLINE constexpr FIteratorImpl operator++(int) requires (CForwardRange<FBase>) { FIteratorImpl Temp = *this; ++*this; return Temp; }
|
||||
FORCEINLINE constexpr FIteratorImpl operator--(int) requires (CBidirectionalRange<FBase>) { FIteratorImpl Temp = *this; --*this; return Temp; }
|
||||
|
||||
FORCEINLINE constexpr FIteratorImpl& operator+=(ptrdiff Offset) requires (CRandomAccessRange<FBase>) { Current += Offset; return *this; }
|
||||
FORCEINLINE constexpr FIteratorImpl& operator-=(ptrdiff Offset) requires (CRandomAccessRange<FBase>) { Current -= Offset; return *this; }
|
||||
|
||||
NODISCARD FORCEINLINE constexpr FIteratorImpl operator+(ptrdiff Offset) const requires (CRandomAccessRange<FBase>) { FIteratorImpl Temp = *this; Temp += Offset; return Temp; }
|
||||
NODISCARD FORCEINLINE constexpr FIteratorImpl operator-(ptrdiff Offset) const requires (CRandomAccessRange<FBase>) { FIteratorImpl Temp = *this; Temp -= Offset; return Temp; }
|
||||
|
||||
NODISCARD friend FORCEINLINE constexpr FIteratorImpl operator+(ptrdiff Offset, const FIteratorImpl& Iter) requires (CRandomAccessRange<FBase>) { return Iter + Offset; }
|
||||
|
||||
NODISCARD friend FORCEINLINE constexpr ptrdiff operator-(const FIteratorImpl& LHS, const FIteratorImpl& RHS) requires (CSizedSentinelFor<TRangeIterator<FBase>, TRangeIterator<FBase>>)
|
||||
{
|
||||
return LHS.GetBase() - RHS.GetBase();
|
||||
}
|
||||
|
||||
NODISCARD FORCEINLINE constexpr const TRangeIterator<FBase>& GetBase() const& { return Current; }
|
||||
NODISCARD FORCEINLINE constexpr TRangeIterator<FBase> GetBase() && { return MoveTemp(Current); }
|
||||
|
||||
private:
|
||||
|
||||
NO_UNIQUE_ADDRESS FOwner* Owner;
|
||||
|
||||
NO_UNIQUE_ADDRESS TRangeIterator<FBase> Current;
|
||||
|
||||
FORCEINLINE constexpr FIteratorImpl(FOwner& InOwner, TRangeIterator<FBase> InCurrent) : Owner(&InOwner), Current(MoveTemp(InCurrent)) { }
|
||||
|
||||
template <bool> friend class FIteratorImpl;
|
||||
template <bool> friend class FSentinelImpl;
|
||||
|
||||
friend TTransformView;
|
||||
};
|
||||
|
||||
template <bool bConst>
|
||||
class FSentinelImpl
|
||||
{
|
||||
private:
|
||||
|
||||
using FOwner = TConditional<bConst, const TTransformView, TTransformView>;
|
||||
using FBase = TConditional<bConst, const V, V>;
|
||||
|
||||
public:
|
||||
|
||||
FORCEINLINE constexpr FSentinelImpl() requires (CDefaultConstructible<TRangeSentinel<FBase>>) = default;
|
||||
|
||||
FORCEINLINE constexpr FSentinelImpl(FSentinelImpl<!bConst> Sentinel) requires (bConst && CConvertibleTo<TRangeSentinel<V>, TRangeSentinel<FBase>>)
|
||||
: Current(Sentinel.GetBase())
|
||||
{ }
|
||||
|
||||
NODISCARD FORCEINLINE constexpr bool operator==(const FIteratorImpl<bConst>& InValue) const& { return Current == InValue.GetBase(); }
|
||||
|
||||
NODISCARD friend FORCEINLINE constexpr ptrdiff operator-(const FIteratorImpl<bConst>& LHS, const FSentinelImpl& RHS)
|
||||
requires CSizedSentinelFor<TRangeSentinel<FBase>, TRangeIterator<FBase>>
|
||||
{
|
||||
return LHS.GetBase() - RHS.GetBase();
|
||||
}
|
||||
|
||||
NODISCARD friend FORCEINLINE constexpr ptrdiff operator-(const FSentinelImpl& LHS, const FIteratorImpl<bConst>& RHS)
|
||||
requires CSizedSentinelFor<TRangeSentinel<FBase>, TRangeIterator<FBase>>
|
||||
{
|
||||
return LHS.GetBase() - RHS.GetBase();
|
||||
}
|
||||
|
||||
NODISCARD FORCEINLINE constexpr TRangeSentinel<FBase> GetBase() const { return Current; }
|
||||
|
||||
private:
|
||||
|
||||
NO_UNIQUE_ADDRESS TRangeSentinel<FBase> Current;
|
||||
|
||||
FORCEINLINE constexpr FSentinelImpl(FOwner& InOwner, TRangeSentinel<FBase> InCurrent) : Current(InCurrent) { }
|
||||
|
||||
friend TTransformView;
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
template <typename R, typename F>
|
||||
TTransformView(R&&, F) -> TTransformView<TAllView<R>, F>;
|
||||
|
||||
static_assert( CInputRange<TTransformView<TAllView<IRange< IInputIterator<int&>>>, int(*)(int)>>);
|
||||
static_assert( CForwardRange<TTransformView<TAllView<IRange< IForwardIterator<int&>>>, int(*)(int)>>);
|
||||
static_assert(CBidirectionalRange<TTransformView<TAllView<IRange<IBidirectionalIterator<int&>>>, int(*)(int)>>);
|
||||
static_assert( CRandomAccessRange<TTransformView<TAllView<IRange< IRandomAccessIterator<int&>>>, int(*)(int)>>);
|
||||
static_assert( CRandomAccessRange<TTransformView<TAllView<IRange< IContiguousIterator<int&>>>, int(*)(int)>>);
|
||||
|
||||
static_assert(CCommonRange<TTransformView<TAllView<ICommonRange<IForwardIterator<int>>>, int(*)(int)>>);
|
||||
static_assert( CSizedRange<TTransformView<TAllView< ISizedRange< IInputIterator<int>>>, int(*)(int)>>);
|
||||
static_assert( CView<TTransformView<TAllView< IRange< IInputIterator<int>>>, int(*)(int)>>);
|
||||
|
||||
static_assert(COutputRange<TTransformView<TAllView<IRange<IForwardIterator<int>>>, int&(*)(int)>, int>);
|
||||
|
||||
NAMESPACE_END(Range)
|
||||
|
||||
NAMESPACE_BEGIN(Range)
|
||||
|
||||
/** Creates A view adapter of a sequence that applies a transformation function to each element. */
|
||||
template <CViewableRange R, typename F> requires (requires { TTransformView(DeclVal<R>(), DeclVal<F>()); })
|
||||
NODISCARD FORCEINLINE constexpr auto Transform(R&& Base, F&& Func)
|
||||
{
|
||||
return TTransformView(Forward<R>(Base), Forward<F>(Func));
|
||||
}
|
||||
|
||||
/** Creates A view adapter of a sequence that applies a transformation function to each element. */
|
||||
template <typename F>
|
||||
NODISCARD FORCEINLINE constexpr auto Transform(F&& Func)
|
||||
{
|
||||
using FClosure = decltype([]<CViewableRange R, typename T> requires (requires { Range::Transform(DeclVal<R>(), DeclVal<T>()); }) (R&& Base, T&& Func)
|
||||
{
|
||||
return Range::Transform(Forward<R>(Base), Forward<T>(Func));
|
||||
});
|
||||
|
||||
return TAdaptorClosure<FClosure, TDecay<F>>(Forward<F>(Func));
|
||||
}
|
||||
|
||||
NAMESPACE_END(Range)
|
||||
|
||||
NAMESPACE_MODULE_END(Utility)
|
||||
NAMESPACE_MODULE_END(Redcraft)
|
||||
NAMESPACE_REDCRAFT_END
|
380
Redcraft.Utility/Source/Public/Ranges/Utility.h
Normal file
380
Redcraft.Utility/Source/Public/Ranges/Utility.h
Normal file
@ -0,0 +1,380 @@
|
||||
#pragma once
|
||||
|
||||
#include "CoreTypes.h"
|
||||
#include "TypeTraits/TypeTraits.h"
|
||||
#include "Templates/Utility.h"
|
||||
#include "Iterators/Utility.h"
|
||||
#include "Iterators/BasicIterator.h"
|
||||
#include "Iterators/Sentinel.h"
|
||||
#include "Iterators/ReverseIterator.h"
|
||||
|
||||
NAMESPACE_REDCRAFT_BEGIN
|
||||
NAMESPACE_MODULE_BEGIN(Redcraft)
|
||||
NAMESPACE_MODULE_BEGIN(Utility)
|
||||
|
||||
/**
|
||||
* The bool value that indicates whether the range always is borrowed range.
|
||||
* When the range always is borrowed range, it means that the iterators and sentinels
|
||||
* of the range remain valid even if the range object is destructed.
|
||||
*/
|
||||
template <typename R>
|
||||
inline constexpr bool bEnableBorrowedRange = false;
|
||||
|
||||
NAMESPACE_BEGIN(Range)
|
||||
|
||||
/** @return The iterator to the beginning of a container. */
|
||||
template <typename T> requires ((CLValueReference<T> || bEnableBorrowedRange<TRemoveCVRef<T>>)
|
||||
&& requires(T&& Container) { { Container.Begin() } -> CInputOrOutputIterator; })
|
||||
NODISCARD FORCEINLINE constexpr auto Begin(T&& Container)
|
||||
{
|
||||
return Container.Begin();
|
||||
}
|
||||
|
||||
/** Overloads the Begin algorithm for arrays. */
|
||||
template <typename T> requires ((CLValueReference<T> || bEnableBorrowedRange<TRemoveCVRef<T>>)
|
||||
&& CArray<TRemoveReference<T>>)
|
||||
NODISCARD FORCEINLINE constexpr auto Begin(T&& Container)
|
||||
{
|
||||
return Container + 0;
|
||||
}
|
||||
|
||||
/** Overloads the Begin algorithm for initializer_list. */
|
||||
template <typename T>
|
||||
NODISCARD FORCEINLINE constexpr const T* Begin(initializer_list<T>& Container)
|
||||
{
|
||||
return Container.begin();
|
||||
}
|
||||
|
||||
NAMESPACE_END(Range)
|
||||
|
||||
template <typename R>
|
||||
using TRangeIterator = decltype(Range::Begin(DeclVal<R&>()));
|
||||
|
||||
NAMESPACE_BEGIN(Range)
|
||||
|
||||
/** @return The iterator to the end of a container. */
|
||||
template <typename T> requires ((CLValueReference<T> || bEnableBorrowedRange<TRemoveCVRef<T>>)
|
||||
&& requires(T&& Container) { { Container.End() } -> CSentinelFor<TRangeIterator<T>>; })
|
||||
NODISCARD FORCEINLINE constexpr auto End(T&& Container)
|
||||
{
|
||||
return Container.End();
|
||||
}
|
||||
|
||||
/** Overloads the End algorithm for arrays. */
|
||||
template <typename T> requires ((CLValueReference<T> || bEnableBorrowedRange<TRemoveCVRef<T>>)
|
||||
&& CBoundedArray<TRemoveReference<T>>)
|
||||
NODISCARD FORCEINLINE constexpr auto End(T&& Container)
|
||||
{
|
||||
return Container + TExtent<TRemoveReference<T>>;
|
||||
}
|
||||
|
||||
/** Overloads the End algorithm for initializer_list. */
|
||||
template <typename T>
|
||||
NODISCARD FORCEINLINE constexpr const T* End(initializer_list<T>& Container)
|
||||
{
|
||||
return Container.end();
|
||||
}
|
||||
|
||||
NAMESPACE_END(Range)
|
||||
|
||||
template <typename R>
|
||||
using TRangeSentinel = decltype(Range::End(DeclVal<R&>()));
|
||||
|
||||
|
||||
NAMESPACE_BEGIN(Range)
|
||||
|
||||
/** @return The reverse iterator to the beginning of a container. */
|
||||
template <typename T> requires ((CLValueReference<T> || bEnableBorrowedRange<TRemoveCVRef<T>>)
|
||||
&& requires(T&& Container) { { Container.RBegin() } -> CInputOrOutputIterator; })
|
||||
NODISCARD FORCEINLINE constexpr auto RBegin(T&& Container)
|
||||
{
|
||||
return Container.RBegin();
|
||||
}
|
||||
|
||||
/** Overloads the RBegin algorithm for synthesized. */
|
||||
template <typename T> requires ((CLValueReference<T> || bEnableBorrowedRange<TRemoveCVRef<T>>)
|
||||
&& !requires(T&& Container) { { Container.RBegin() } -> CInputOrOutputIterator; }
|
||||
&& (CSameAs<TRangeIterator<T>, TRangeSentinel<T>> && CBidirectionalIterator<TRangeIterator<T>>))
|
||||
NODISCARD FORCEINLINE constexpr auto RBegin(T&& Container)
|
||||
{
|
||||
return MakeReverseIterator(Range::End(Forward<T>(Container)));
|
||||
}
|
||||
|
||||
/** @return The reverse iterator to the end of a container. */
|
||||
template <typename T> requires ((CLValueReference<T> || bEnableBorrowedRange<TRemoveCVRef<T>>)
|
||||
&& requires(T&& Container) { { Container.REnd() } -> CSentinelFor<decltype(Range::RBegin(DeclVal<T&>()))>; })
|
||||
NODISCARD FORCEINLINE constexpr auto REnd(T&& Container)
|
||||
{
|
||||
return Container.REnd();
|
||||
}
|
||||
|
||||
/** Overloads the REnd algorithm for synthesized. */
|
||||
template <typename T> requires ((CLValueReference<T> || bEnableBorrowedRange<TRemoveCVRef<T>>)
|
||||
&& !requires(T&& Container) { { Container.REnd() } -> CSentinelFor<decltype(Range::RBegin(DeclVal<T&>()))>; }
|
||||
&& (CSameAs<TRangeIterator<T>, TRangeSentinel<T>> && CBidirectionalIterator<TRangeIterator<T>>))
|
||||
NODISCARD FORCEINLINE constexpr auto REnd(T&& Container)
|
||||
{
|
||||
return MakeReverseIterator(Range::Begin(Forward<T>(Container)));
|
||||
}
|
||||
|
||||
NAMESPACE_END(Range)
|
||||
|
||||
template <typename R>
|
||||
using TRangeElement = TIteratorElement<TRangeIterator<R>>;
|
||||
|
||||
template <typename R>
|
||||
using TRangePointer = TIteratorPointer<TRangeIterator<R>>;
|
||||
|
||||
template <typename R>
|
||||
using TRangeReference = TIteratorReference<TRangeIterator<R>>;
|
||||
|
||||
template <typename R>
|
||||
using TRangeRValueReference = TIteratorRValueReference<TRangeIterator<R>>;
|
||||
|
||||
NAMESPACE_BEGIN(Range)
|
||||
|
||||
/** @return The pointer to the container element storage. */
|
||||
template <typename T> requires ((CLValueReference<T> || bEnableBorrowedRange<TRemoveCVRef<T>>)
|
||||
&& requires(T&& Container) { { Container.GetData() } -> CSameAs<TAddPointer<TRangeReference<T>>>; })
|
||||
NODISCARD FORCEINLINE constexpr auto GetData(T&& Container)
|
||||
{
|
||||
return Container.GetData();
|
||||
}
|
||||
|
||||
/** Overloads the GetData algorithm for synthesized. */
|
||||
template <typename T> requires ((CLValueReference<T> || bEnableBorrowedRange<TRemoveCVRef<T>>)
|
||||
&& !requires(T&& Container) { { Container.GetData() } -> CSameAs<TAddPointer<TRangeReference<T>>>; }
|
||||
&& requires(T&& Container) { { Range::Begin(Forward<T>(Container)) } -> CContiguousIterator; })
|
||||
NODISCARD FORCEINLINE constexpr auto GetData(T&& Container)
|
||||
{
|
||||
return ToAddress(Range::Begin(Forward<T>(Container)));
|
||||
}
|
||||
|
||||
NAMESPACE_END(Range)
|
||||
|
||||
/** Disable the CSizedRange concept for specific types. */
|
||||
template <typename R>
|
||||
inline constexpr bool bDisableSizedRange = false;
|
||||
|
||||
NAMESPACE_BEGIN(Range)
|
||||
|
||||
/** @return The number of elements in the container. */
|
||||
template <typename T> requires (!bDisableSizedRange<TRemoveCVRef<T>>
|
||||
&& requires(T&& Container) { { Container.Num() } -> CSameAs<size_t>; })
|
||||
NODISCARD FORCEINLINE constexpr size_t Num(T&& Container)
|
||||
{
|
||||
return Container.Num();
|
||||
}
|
||||
|
||||
/** Overloads the Num algorithm for arrays. */
|
||||
template <typename T> requires (!bDisableSizedRange<TRemoveCVRef<T>>
|
||||
&& CBoundedArray<TRemoveReference<T>>)
|
||||
NODISCARD FORCEINLINE constexpr size_t Num(T&& Container)
|
||||
{
|
||||
return TExtent<TRemoveReference<T>>;
|
||||
}
|
||||
|
||||
/** Overloads the Num algorithm for synthesized. */
|
||||
template <typename T> requires (!bDisableSizedRange<TRemoveCVRef<T>>
|
||||
&& !requires(T&& Container) { { Container.Num() } -> CSameAs<size_t>; } && !CBoundedArray<TRemoveReference<T>>
|
||||
&& CSizedSentinelFor<TRangeSentinel<T>, TRangeIterator<T>> && CForwardIterator<TRangeIterator<T>>)
|
||||
NODISCARD FORCEINLINE constexpr size_t Num(T&& Container)
|
||||
{
|
||||
return Range::End(Forward<T>(Container)) - Range::Begin(Forward<T>(Container));
|
||||
}
|
||||
|
||||
/** Overloads the Num algorithm for initializer_list. */
|
||||
template <typename T>
|
||||
NODISCARD FORCEINLINE constexpr size_t Num(initializer_list<T>& Container)
|
||||
{
|
||||
return Container.size();
|
||||
}
|
||||
|
||||
/** @return true if the container is empty, false otherwise. */
|
||||
template <typename T> requires (requires(T&& Container) { { Container.IsEmpty() } -> CBooleanTestable; })
|
||||
NODISCARD FORCEINLINE constexpr bool IsEmpty(T&& Container)
|
||||
{
|
||||
return Container.IsEmpty();
|
||||
}
|
||||
|
||||
/** Overloads the IsEmpty algorithm for synthesized. */
|
||||
template <typename T> requires ((CBoundedArray<TRemoveReference<T>>
|
||||
|| requires(T&& Container) { { Container.Num() } -> CSameAs<size_t>; })
|
||||
&& !requires(T&& Container) { { Container.IsEmpty() } -> CBooleanTestable; })
|
||||
NODISCARD FORCEINLINE constexpr bool IsEmpty(T&& Container)
|
||||
{
|
||||
return Range::Num(Forward<T>(Container)) == 0;
|
||||
}
|
||||
|
||||
/** Overloads the IsEmpty algorithm for synthesized. */
|
||||
template <typename T> requires (!CBoundedArray<TRemoveReference<T>>
|
||||
&& !requires(T&& Container) { { Container.Num() } -> CSameAs<size_t>; }
|
||||
&& !requires(T&& Container) { { Container.IsEmpty() } -> CBooleanTestable; }
|
||||
&& CForwardIterator<TRangeIterator<T>>)
|
||||
NODISCARD FORCEINLINE constexpr bool IsEmpty(T&& Container)
|
||||
{
|
||||
return Range::End(Forward<T>(Container)) == Range::Begin(Forward<T>(Container));
|
||||
}
|
||||
|
||||
NAMESPACE_END(Range)
|
||||
|
||||
/**
|
||||
* A concept specifies a type is a range.
|
||||
* A range is an iterator-sentinel pair that represents a sequence of elements.
|
||||
* This concept does not require that iterator-sentinel pair can be fetched multiple times
|
||||
* from the range object. again this means that const R may not be a range if R is a range,
|
||||
* e.g. fetching the iterator-sentinel pair from the input range may require moving the iterator
|
||||
* directly from the range object and thus the range object may be modified.
|
||||
*/
|
||||
template <typename R>
|
||||
concept CRange =
|
||||
requires(R Range)
|
||||
{
|
||||
typename TRangeIterator<R>;
|
||||
typename TRangeSentinel<R>;
|
||||
}
|
||||
&& CInputOrOutputIterator<TRangeIterator<R>>
|
||||
&& CSentinelFor<TRangeSentinel<R>, TRangeIterator<R>>;
|
||||
|
||||
/** This is an example of a range type, indicate the traits that define a range type. */
|
||||
template <CInputOrOutputIterator I, CSentinelFor<I> S = ISentinelFor<I>>
|
||||
struct IRange
|
||||
{
|
||||
/**
|
||||
* Get the iterator-sentinel pair.
|
||||
* If the function is const, it means that the const IRange satisfies CRange.
|
||||
*/
|
||||
I Begin() /* const */;
|
||||
S End() /* const */;
|
||||
};
|
||||
|
||||
// Use IRange<...> represents an range type.
|
||||
static_assert(CRange<IRange<IInputOrOutputIterator<int&>>>);
|
||||
|
||||
/**
|
||||
* A concept specifies a type is a borrowed range.
|
||||
* When the range is borrowed range, it means that the iterators and sentinels
|
||||
* of the range remain valid even if the range value (note not object) is destructed.
|
||||
*/
|
||||
template <typename R>
|
||||
concept CBorrowedRange = CRange<R> && (CLValueReference<R> || bEnableBorrowedRange<TRemoveCVRef<R>>);
|
||||
|
||||
/**
|
||||
* A concept specifies a type is a sized range.
|
||||
* Indicates the expression 'Range::Num(Range)' can get the size of the range at constant time
|
||||
* without modifying the range object. Modifying the range usually occurs when the iterator of
|
||||
* the range is an input iterator. Indirect calculation of the range by obtaining the iterator
|
||||
* may cause the range to become invalid, that is, the iterator cannot be obtained again.
|
||||
*/
|
||||
template <typename R>
|
||||
concept CSizedRange = CRange<R>
|
||||
&& requires(R Range)
|
||||
{
|
||||
{ Range::Num(Range) } -> CConvertibleTo<size_t>;
|
||||
};
|
||||
|
||||
/** This is an example of a sized range type, indicate the traits that define a sized range type. */
|
||||
template <CInputOrOutputIterator I, CSizedSentinelFor<I> S = ISizedSentinelFor<I>>
|
||||
struct ISizedRange /* : IRange<I, S> */
|
||||
{
|
||||
// ~Begin CRange.
|
||||
|
||||
I Begin() /* const */;
|
||||
S End() /* const */;
|
||||
|
||||
// ~End CRange.
|
||||
|
||||
/**
|
||||
* Get the number of elements in the range.
|
||||
* The function is optional if the range size can be computed indirectly from the iterator-sentinel pair.
|
||||
* If this function is provided so that types that satisfy CSizedRange but do not satisfy the comments
|
||||
* requirements of CSizedRange are undefined behavior, this should be resolved by specializing bDisableSizedRange.
|
||||
* If the function is const, it means that the const ISizedRange satisfies CSizedRange.
|
||||
*/
|
||||
size_t Num() /* const */;
|
||||
};
|
||||
|
||||
// Use ISizedRange<...> represents a sized range type.
|
||||
static_assert(CSizedRange<ISizedRange<IInputOrOutputIterator<int&>>>);
|
||||
|
||||
/** A concept specifies a type is a range with an input iterator. */
|
||||
template <typename R>
|
||||
concept CInputRange = CRange<R> && CInputIterator<TRangeIterator<R>>;
|
||||
|
||||
// Use IRange<IInputIterator<...>> represents an input range type.
|
||||
static_assert(CInputRange<IRange<IInputIterator<int&>>>);
|
||||
|
||||
/** A concept specifies a type is a range with an output iterator. */
|
||||
template <typename R, typename T>
|
||||
concept COutputRange = CRange<R> && COutputIterator<TRangeIterator<R>, T>;
|
||||
|
||||
// Use IRange<IOutputIterator<...>, int> represents an output range type.
|
||||
static_assert(COutputRange<IRange<IOutputIterator<int&>>, int>);
|
||||
|
||||
/** A concept specifies a type is a range with a forward iterator. */
|
||||
template <typename R>
|
||||
concept CForwardRange = CInputRange<R> && CForwardIterator<TRangeIterator<R>>;
|
||||
|
||||
// Use IRange<IForwardIterator<...>> represents a forward range type.
|
||||
static_assert(CForwardRange<IRange<IForwardIterator<int&>>>);
|
||||
|
||||
/** A concept specifies a type is a range with a bidirectional iterator. */
|
||||
template <typename R>
|
||||
concept CBidirectionalRange = CForwardRange<R> && CBidirectionalIterator<TRangeIterator<R>>;
|
||||
|
||||
// Use IRange<IBidirectionalIterator<...>> represents a bidirectional range type.
|
||||
static_assert(CBidirectionalRange<IRange<IBidirectionalIterator<int&>>>);
|
||||
|
||||
/** A concept specifies a type is a range with a random access iterator. */
|
||||
template <typename R>
|
||||
concept CRandomAccessRange = CBidirectionalRange<R> && CRandomAccessIterator<TRangeIterator<R>>;
|
||||
|
||||
// Use IRange<IRandomAccessIterator<...>> represents a random access range type.
|
||||
static_assert(CRandomAccessRange<IRange<IRandomAccessIterator<int&>>>);
|
||||
|
||||
/** A concept specifies a type is a range with a contiguous iterator. */
|
||||
template <typename R>
|
||||
concept CContiguousRange = CRandomAccessRange<R> && CContiguousIterator<TRangeIterator<R>>
|
||||
&& requires(R& Range)
|
||||
{
|
||||
{ Range::GetData(Range) } -> CSameAs<TAddPointer<TRangeReference<R>>>;
|
||||
};
|
||||
|
||||
/** This is an example of a contiguous range type, indicate the traits that define a contiguous range type. */
|
||||
template <CContiguousIterator I, CSentinelFor<I> S = ISentinelFor<I>>
|
||||
struct IContiguousRange /* : IRange<I, S> */
|
||||
{
|
||||
// ~Begin CRange.
|
||||
|
||||
I Begin() /* const */;
|
||||
S End() /* const */;
|
||||
|
||||
// ~End CRange.
|
||||
|
||||
/**
|
||||
* Get the pointer to the container element storage.
|
||||
* The function is optional if the range size can be computed indirectly from the iterator.
|
||||
* If the function is provided, then the expression 'ToAddress(Range::Begin(Range)) == Range::GetData(Range)'
|
||||
* must be satisfied to always be true.
|
||||
* If the function is const, it means that the const IContiguousRange satisfies CContiguousRange.
|
||||
*/
|
||||
TIteratorPointer<I> GetData() /* const */;
|
||||
};
|
||||
|
||||
// Use IContiguousRange<...> represents a contiguous range type.
|
||||
static_assert(CContiguousRange<IContiguousRange<IContiguousIterator<int&>>>);
|
||||
|
||||
/** A concept specifies a type is a range and its iterator and sentinel types are the same. */
|
||||
template <typename R>
|
||||
concept CCommonRange = CRange<R> && CSameAs<TRangeIterator<R>, TRangeSentinel<R>>;
|
||||
|
||||
/** This is an example of a common range type, indicate the traits that define a common range type. */
|
||||
template <CForwardIterator I>
|
||||
using ICommonRange = IRange<I, I>;
|
||||
|
||||
// Use TCommonRange<...> represents a common range type.
|
||||
static_assert(CCommonRange<ICommonRange<IForwardIterator<int&>>>);
|
||||
|
||||
NAMESPACE_MODULE_END(Utility)
|
||||
NAMESPACE_MODULE_END(Redcraft)
|
||||
NAMESPACE_REDCRAFT_END
|
158
Redcraft.Utility/Source/Public/Ranges/View.h
Normal file
158
Redcraft.Utility/Source/Public/Ranges/View.h
Normal file
@ -0,0 +1,158 @@
|
||||
#pragma once
|
||||
|
||||
#include "CoreTypes.h"
|
||||
#include "TypeTraits/TypeTraits.h"
|
||||
#include "Templates/Utility.h"
|
||||
#include "Iterators/Utility.h"
|
||||
#include "Iterators/Sentinel.h"
|
||||
#include "Iterators/BasicIterator.h"
|
||||
#include "Iterators/ReverseIterator.h"
|
||||
#include "Memory/Address.h"
|
||||
#include "Ranges/Utility.h"
|
||||
|
||||
NAMESPACE_REDCRAFT_BEGIN
|
||||
NAMESPACE_MODULE_BEGIN(Redcraft)
|
||||
NAMESPACE_MODULE_BEGIN(Utility)
|
||||
|
||||
NAMESPACE_BEGIN(Range)
|
||||
|
||||
/** An interface class template for defining a view. Not directly instantiable. */
|
||||
template <CClass T> requires (CSameAs<T, TRemoveCV<T>>)
|
||||
class IBasicViewInterface
|
||||
{
|
||||
public:
|
||||
|
||||
/** @return The pointer to the underlying element storage. */
|
||||
NODISCARD FORCEINLINE constexpr auto GetData() requires (CContiguousIterator<TRangeIterator< T>>) { return ToAddress(Range::Begin(static_cast< T&>(*this))); }
|
||||
NODISCARD FORCEINLINE constexpr auto GetData() const requires (CContiguousIterator<TRangeIterator<const T>>) { return ToAddress(Range::Begin(static_cast<const T&>(*this))); }
|
||||
|
||||
/** @return The reverse iterator to the first or end element. */
|
||||
NODISCARD FORCEINLINE constexpr auto RBegin() requires (CBidirectionalRange< T> && CCommonRange< T>) { return MakeReverseIterator(Range::End (static_cast< T&>(*this))); }
|
||||
NODISCARD FORCEINLINE constexpr auto REnd() requires (CBidirectionalRange< T> && CCommonRange< T>) { return MakeReverseIterator(Range::Begin(static_cast< T&>(*this))); }
|
||||
NODISCARD FORCEINLINE constexpr auto RBegin() const requires (CBidirectionalRange<const T> && CCommonRange<const T>) { return MakeReverseIterator(Range::End (static_cast<const T&>(*this))); }
|
||||
NODISCARD FORCEINLINE constexpr auto REnd() const requires (CBidirectionalRange<const T> && CCommonRange<const T>) { return MakeReverseIterator(Range::Begin(static_cast<const T&>(*this))); }
|
||||
|
||||
/** @return The number of elements in the container. */
|
||||
NODISCARD FORCEINLINE constexpr size_t Num() requires (CForwardRange< T> && CSizedSentinelFor<TRangeSentinel< T>, TRangeIterator< T>>) { T& Derived = static_cast< T&>(*this); return Range::End(Derived) - Range::Begin(Derived); }
|
||||
NODISCARD FORCEINLINE constexpr size_t Num() const requires (CForwardRange<const T> && CSizedSentinelFor<TRangeSentinel<const T>, TRangeIterator<const T>>) { const T& Derived = static_cast<const T&>(*this); return Range::End(Derived) - Range::Begin(Derived); }
|
||||
|
||||
/** @return true if the container is empty, false otherwise. */
|
||||
NODISCARD FORCEINLINE constexpr bool IsEmpty() requires (CSizedRange< T> || CForwardRange< T>) { T& Derived = static_cast< T&>(*this); if constexpr (CSizedRange< T>) return Range::Num(Derived) == 0; else return Range::Begin(Derived) == Range::End(Derived); }
|
||||
NODISCARD FORCEINLINE constexpr bool IsEmpty() const requires (CSizedRange<const T> || CForwardRange<const T>) { const T& Derived = static_cast<const T&>(*this); if constexpr (CSizedRange<const T>) return Range::Num(Derived) == 0; else return Range::Begin(Derived) == Range::End(Derived); }
|
||||
|
||||
/** @return true if the container is empty, false otherwise. */
|
||||
NODISCARD FORCEINLINE constexpr explicit operator bool() requires (requires { Range::IsEmpty(DeclVal< T&>()); }) { return !Range::IsEmpty(static_cast< T&>(*this)); }
|
||||
NODISCARD FORCEINLINE constexpr explicit operator bool() const requires (requires { Range::IsEmpty(DeclVal<const T&>()); }) { return !Range::IsEmpty(static_cast<const T&>(*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<const T>) { return Range::Begin(static_cast<const T&>(*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<const T>) { return *Range::Begin(static_cast<const T&>(*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<const T> && CCommonRange<const T>) { return *Range::RBegin(static_cast<const T&>(*this)); }
|
||||
|
||||
// ~Begin ENABLE_RANGE_BASED_FOR_LOOP_SUPPORT.
|
||||
|
||||
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<const T>) { return Range::Begin(static_cast<const T&>(*this)); }
|
||||
NODISCARD FORCEINLINE constexpr auto end() const requires (CRange<const T>) { return Range::End (static_cast<const T&>(*this)); }
|
||||
|
||||
// ~End ENABLE_RANGE_BASED_FOR_LOOP_SUPPORT.
|
||||
|
||||
private:
|
||||
|
||||
FORCEINLINE constexpr IBasicViewInterface() = default;
|
||||
FORCEINLINE constexpr IBasicViewInterface(const IBasicViewInterface&) = default;
|
||||
FORCEINLINE constexpr IBasicViewInterface(IBasicViewInterface&&) = default;
|
||||
FORCEINLINE constexpr IBasicViewInterface& operator=(const IBasicViewInterface&) = default;
|
||||
FORCEINLINE constexpr IBasicViewInterface& operator=(IBasicViewInterface&&) = default;
|
||||
FORCEINLINE constexpr ~IBasicViewInterface() = default;
|
||||
|
||||
friend T;
|
||||
};
|
||||
|
||||
NAMESPACE_END(Range)
|
||||
|
||||
/**
|
||||
* A concept specifies that a range is a view, that is, it has constant time copy, move and assignment.
|
||||
* Specify, a view can be movable only but not copyable, or it can be both movable and copyable.
|
||||
*/
|
||||
template <typename V>
|
||||
concept CView = CRange<V> && CMovable<V> && CDerivedFrom<V, Range::IBasicViewInterface<TRemoveCVRef<V>>>;
|
||||
|
||||
NAMESPACE_PRIVATE_BEGIN
|
||||
|
||||
template <typename T> struct TIsInitializerList : FFalse { };
|
||||
template <typename T> struct TIsInitializerList<initializer_list<T>> : FTrue { };
|
||||
|
||||
NAMESPACE_PRIVATE_END
|
||||
|
||||
/** A concept specifies that a viewable range that can be converted into a view through Range::All. */
|
||||
template <typename R>
|
||||
concept CViewableRange = CRange<R>
|
||||
&& ((CView<TRemoveCVRef<R>> && CConstructibleFrom<TRemoveCVRef<R>, R>)
|
||||
|| (!CView<TRemoveCVRef<R>> && (CLValueReference<R> || (CMovable<TRemoveReference<R>>
|
||||
&& !NAMESPACE_PRIVATE::TIsInitializerList<TRemoveCVRef<R>>::Value))));
|
||||
|
||||
/** A concept specifies that a view uses the same iterator and sentinel type for both const and non-const views. */
|
||||
template <typename V>
|
||||
concept CSimpleView = CView<V> && CRange<const V>
|
||||
&& CSameAs<TRangeIterator<V>, TRangeIterator<const V>>
|
||||
&& CSameAs<TRangeSentinel<V>, TRangeSentinel<const V>>;
|
||||
|
||||
NAMESPACE_BEGIN(Range)
|
||||
|
||||
/** A simple view that combines an iterator-sentinel pair into a view. */
|
||||
template <CInputOrOutputIterator I, CSentinelFor<I> S = I>
|
||||
class TRangeView : public IBasicViewInterface<TRangeView<I, S>>
|
||||
{
|
||||
public:
|
||||
|
||||
using FElementType = TIteratorElement<I>;
|
||||
|
||||
FORCEINLINE constexpr TRangeView() requires (CDefaultConstructible<I>) = default;
|
||||
|
||||
FORCEINLINE constexpr TRangeView(I InFirst, S InLast) : First(MoveTemp(InFirst)), Last(InLast) { }
|
||||
|
||||
NODISCARD FORCEINLINE constexpr I Begin() requires (!CCopyable<I>) { return MoveTemp(First); }
|
||||
NODISCARD FORCEINLINE constexpr I Begin() const requires ( CCopyable<I>) { return First; }
|
||||
|
||||
NODISCARD FORCEINLINE constexpr S End() const { return Last; }
|
||||
|
||||
NODISCARD FORCEINLINE constexpr size_t Num() const requires (CSizedSentinelFor<S, I>) { return Last - First; }
|
||||
|
||||
NODISCARD FORCEINLINE constexpr bool IsEmpty() const { return First == Last; }
|
||||
|
||||
private:
|
||||
|
||||
NO_UNIQUE_ADDRESS I First;
|
||||
NO_UNIQUE_ADDRESS S Last;
|
||||
|
||||
};
|
||||
|
||||
template <CInputOrOutputIterator I, CSentinelFor<I> S>
|
||||
TRangeView(I, S) -> TRangeView<I, S>;
|
||||
|
||||
NAMESPACE_END(Range)
|
||||
|
||||
template <typename I, typename S>
|
||||
constexpr bool bEnableBorrowedRange<Range::TRangeView<I, S>> = true;
|
||||
|
||||
NAMESPACE_BEGIN(Range)
|
||||
|
||||
/** Creates A simple view that combines an iterator-sentinel pair. */
|
||||
template <CInputOrOutputIterator I, CSentinelFor<I> S = I>
|
||||
NODISCARD FORCEINLINE constexpr TRangeView<I, S> View(I First, S Last)
|
||||
{
|
||||
return TRangeView<I, S>(MoveTemp(First), Last);
|
||||
}
|
||||
|
||||
NAMESPACE_END(Range)
|
||||
|
||||
NAMESPACE_MODULE_END(Utility)
|
||||
NAMESPACE_MODULE_END(Redcraft)
|
||||
NAMESPACE_REDCRAFT_END
|
Reference in New Issue
Block a user