feat(miscellaneous): add TViewInterface with basic view and other range tools

This commit is contained in:
Redstone1024 2024-12-08 20:44:48 +08:00
parent 8113d3b39b
commit ba9d35c1ff

View File

@ -2,6 +2,7 @@
#include "CoreTypes.h"
#include "Memory/Address.h"
#include "Templates/Invoke.h"
#include "Templates/Utility.h"
#include "TypeTraits/TypeTraits.h"
#include "Miscellaneous/Iterator.h"
@ -10,6 +11,8 @@ NAMESPACE_REDCRAFT_BEGIN
NAMESPACE_MODULE_BEGIN(Redcraft)
NAMESPACE_MODULE_BEGIN(Utility)
// NOTE: The range that holds the object is called a container, and the range that only references the object is called a view.
template <typename R>
inline constexpr bool bEnableBorrowedRange = false;
@ -33,7 +36,7 @@ NODISCARD FORCEINLINE constexpr auto Begin(T&& Container)
/** Overloads the Begin algorithm for initializer_list. */
template <typename T>
NODISCARD FORCEINLINE constexpr auto Begin(initializer_list<T> Container)
NODISCARD FORCEINLINE constexpr auto Begin(initializer_list<T>& Container)
{
return Container.begin();
}
@ -63,7 +66,7 @@ NODISCARD FORCEINLINE constexpr auto End(T&& Container)
/** Overloads the End algorithm for initializer_list. */
template <typename T>
NODISCARD FORCEINLINE constexpr auto End(initializer_list<T> Container)
NODISCARD FORCEINLINE constexpr auto End(initializer_list<T>& Container)
{
return Container.end();
}
@ -89,7 +92,7 @@ template <typename T> requires ((CLValueReference<T> || bEnableBorrowedRange<TRe
&& (CSameAs<TRangeIteratorType<T>, TRangeSentinelType<T>> && CBidirectionalIterator<TRangeIteratorType<T>>))
NODISCARD FORCEINLINE constexpr auto RBegin(T&& Container)
{
return MakeReverseIterator(Range::End(Container));
return MakeReverseIterator(Range::End(Forward<T>(Container)));
}
/** @return The reverse iterator to the end of a container. */
@ -106,13 +109,21 @@ template <typename T> requires ((CLValueReference<T> || bEnableBorrowedRange<TRe
&& (CSameAs<TRangeIteratorType<T>, TRangeSentinelType<T>> && CBidirectionalIterator<TRangeIteratorType<T>>))
NODISCARD FORCEINLINE constexpr auto REnd(T&& Container)
{
return MakeReverseIterator(Range::Begin(Container));
return MakeReverseIterator(Range::Begin(Forward<T>(Container)));
}
NAMESPACE_END(Range)
NAMESPACE_PRIVATE_BEGIN
template <typename R> struct TRangeElementType { using Type = typename R::ElementType; };
template <typename T> struct TRangeElementType<T[ ]> { using Type = T; };
template <typename T, size_t N> struct TRangeElementType<T[N]> { using Type = T; };
NAMESPACE_PRIVATE_END
template <typename R>
using TRangeElementType = TIteratorElementType<TRangeIteratorType<R>>;
using TRangeElementType = typename NAMESPACE_PRIVATE::TRangeElementType<TRemoveCVRef<R>>::Type;
template <typename R>
using TRangeReferenceType = TIteratorReferenceType<TRangeIteratorType<R>>;
@ -168,7 +179,33 @@ template <typename T> requires (!bDisableSizedRange<TRemoveCVRef<T>>
&& CSizedSentinelFor<TRangeIteratorType<T>, TRangeSentinelType<T>> && CForwardIterator<TRangeIteratorType<T>>)
NODISCARD FORCEINLINE constexpr size_t Num(T&& Container)
{
return Range::End(Container) - Range::Begin(Container);
return Range::End(Forward<T>(Container)) - Range::Begin(Forward<T>(Container));
}
/** @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<TRangeIteratorType<T>>)
NODISCARD FORCEINLINE constexpr bool IsEmpty(T&& Container)
{
return Range::End(Forward<T>(Container)) == Range::Begin(Forward<T>(Container));
}
NAMESPACE_END(Range)
@ -193,12 +230,6 @@ concept CSizedRange = CRange<R>
{ Range::Num(Range) } -> CConvertibleTo<size_t>;
};
template <typename R>
inline constexpr bool bEnableView = false;
template <typename R>
concept CView = CRange<R> && CMovable<R> && bEnableView<R>;
template <typename R>
concept CInputRange = CRange<R> && CInputIterator<TRangeIteratorType<R>>;
@ -218,12 +249,84 @@ template <typename R>
concept CContiguousRange = CRandomAccessRange<R> && CContiguousIterator<TRangeIteratorType<R>>
&& requires(R& Range)
{
{ Range::GetData(Range) } -> CSameAs<TAddPointer<TRangeElementType<R>>>;
{ Range::GetData(Range) } -> CSameAs<TAddPointer<TRangeReferenceType<R>>>;
};
template <typename R>
concept CCommonRange = CRange<R> && CSameAs<TRangeIteratorType<R>, TRangeSentinelType<R>>;
static_assert(CContiguousRange<int[8]>);
static_assert( CCommonRange<int[8]>);
NAMESPACE_BEGIN(Range)
template <typename T> requires (CClass<T> && CSameAs<T, TRemoveCV<T>>)
class TViewInterface
{
public:
/** @return The pointer to the underlying element storage. */
NODISCARD FORCEINLINE constexpr auto Data() requires (CContiguousRange< T>) { return Range::GetData(static_cast< T&>(*this)); }
NODISCARD FORCEINLINE constexpr auto Data() const requires (CContiguousRange<const T>) { return Range::GetData(static_cast<const T&>(*this)); }
/** @return The reverse iterator to the first or end element. */
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)); }
/** @return The reverse iterator to the first or end element. */
NODISCARD FORCEINLINE constexpr auto RBegin() requires (CBidirectionalRange< T> && CCommonRange< T>) { return Range::RBegin(static_cast< T&>(*this)); }
NODISCARD FORCEINLINE constexpr auto REnd() requires (CBidirectionalRange< T> && CCommonRange< T>) { return Range::REnd (static_cast< T&>(*this)); }
NODISCARD FORCEINLINE constexpr auto RBegin() const requires (CBidirectionalRange<const T> && CCommonRange<const T>) { return Range::RBegin(static_cast<const T&>(*this)); }
NODISCARD FORCEINLINE constexpr auto REnd() const requires (CBidirectionalRange<const T> && CCommonRange<const T>) { return Range::REnd (static_cast<const T&>(*this)); }
/** @return The number of elements in the container. */
NODISCARD FORCEINLINE constexpr size_t Num() requires (CSizedRange< T>) { return Range::Num(static_cast< T&>(*this)); }
NODISCARD FORCEINLINE constexpr size_t Num() const requires (CSizedRange<const T>) { return Range::Num(static_cast<const T&>(*this)); }
/** @return true if the container is empty, false otherwise. */
NODISCARD FORCEINLINE constexpr bool IsEmpty() requires (CSizedRange< T> || CForwardRange< T>) { return Range::IsEmpty(static_cast< T&>(*this)); }
NODISCARD FORCEINLINE constexpr bool IsEmpty() const requires (CSizedRange<const T> || CForwardRange<const T>) { return Range::IsEmpty(static_cast<const T&>(*this)); }
/** @return true if the container is empty, false otherwise. */
NODISCARD FORCEINLINE constexpr explicit operator bool() requires (CSizedRange< T> || CForwardRange< T>) { return !Range::IsEmpty(static_cast< T&>(*this)); }
NODISCARD FORCEINLINE constexpr explicit operator bool() const requires (CSizedRange<const T> || CForwardRange<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)); }
ENABLE_RANGE_BASED_FOR_LOOP_SUPPORT
private:
FORCEINLINE constexpr TViewInterface() = default;
FORCEINLINE constexpr TViewInterface(const TViewInterface&) = default;
FORCEINLINE constexpr TViewInterface(TViewInterface&&) = default;
FORCEINLINE constexpr TViewInterface& operator=(const TViewInterface&) = default;
FORCEINLINE constexpr TViewInterface& operator=(TViewInterface&&) = default;
FORCEINLINE constexpr ~TViewInterface() = default;
friend T;
};
NAMESPACE_END(Range)
template <typename R> requires (bEnableBorrowedRange<R>)
inline constexpr bool bEnableBorrowedRange<Range::TViewInterface<R>> = true;
template <typename V>
concept CView = CRange<V> && CMovable<V> && CDerivedFrom<V, Range::TViewInterface<TRemoveCVRef<V>>>;
NAMESPACE_PRIVATE_BEGIN
template <typename T> struct TIsInitializerList : FFalse { };
@ -237,7 +340,100 @@ concept CViewableRange = CRange<R>
|| (!CView<TRemoveCVRef<R>> && (CLValueReference<R> || CMovable<TRemoveReference<R>>
&& !NAMESPACE_PRIVATE::TIsInitializerList<TRemoveCVRef<R>>::Value)));
static_assert(CRange<int[8]> && CContiguousRange<int[8]> && CCommonRange<int[8]>);
NAMESPACE_BEGIN(Range)
template <CObject T>
class TEmptyView : public TViewInterface<TEmptyView<T>>
{
public:
using ElementType = T;
using Reference = T&;
using Iterator = T*;
using Sentinel = T*;
using ReverseIterator = TReverseIterator<Iterator>;
FORCEINLINE constexpr TEmptyView() = default;
NODISCARD static FORCEINLINE constexpr Iterator Begin() { return nullptr; }
NODISCARD static FORCEINLINE constexpr Sentinel 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( CView<TEmptyView<int>>);
NAMESPACE_END(Range)
template <typename T>
constexpr bool bEnableBorrowedRange<Range::TEmptyView<T>> = true;
NAMESPACE_BEGIN(Range)
template <CObject T> requires (CMoveConstructible<T>)
class TSingleView : public TViewInterface<TSingleView<T>>
{
public:
using ElementType = T;
using Reference = T&;
using ConstReference = const T&;
using Iterator = T*;
using ConstIterator = const T*;
using Sentinel = T*;
using ConstSentinel = const T*;
using ReverseIterator = TReverseIterator< Iterator>;
using ConstReverseIterator = TReverseIterator<ConstIterator>;
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 explicit TSingleView(FInPlace, Ts&&... Args) : Value(Forward<Ts>(Args)...) { }
FORCEINLINE constexpr Iterator Begin() { return GetData(); }
FORCEINLINE constexpr ConstIterator Begin() const { return GetData(); }
FORCEINLINE constexpr Sentinel End() { return GetData() + 1; }
FORCEINLINE constexpr ConstSentinel 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( CView<TSingleView<int>>);
NAMESPACE_END(Range)
template <CRange R, typename T> requires (CRange<TInvokeResult<T, R>>)
NODISCARD FORCEINLINE constexpr auto operator|(R&& Range, T&& View)
{
return Invoke(Forward<T>(View), Forward<R>(Range));
}
NAMESPACE_MODULE_END(Utility)
NAMESPACE_MODULE_END(Redcraft)