Compare commits

...

5 Commits

12 changed files with 429 additions and 23 deletions

View File

@ -0,0 +1,226 @@
#include "Testing/IteratorTesting.h"
#include "Iterator/Iterator.h"
#include "Containers/List.h"
#include "Miscellaneous/AssertionMacros.h"
NAMESPACE_REDCRAFT_BEGIN
NAMESPACE_MODULE_BEGIN(Redcraft)
NAMESPACE_MODULE_BEGIN(Utility)
NAMESPACE_BEGIN(Testing)
void TestIterator()
{
TestMoveIterator();
TestReverseIterator();
TestCountedIterator();
TestInsertIterator();
}
void TestMoveIterator()
{
{
struct FTracker
{
FTracker() = default;
FTracker(const FTracker&) { always_check_no_entry(); }
FTracker(FTracker&&) = default;
~FTracker() = default;
FTracker& operator=(const FTracker&) { always_check_no_entry(); }
FTracker& operator=(FTracker&&) = default;
};
FTracker Arr[2];
auto First = MakeMoveIterator(&Arr[0]);
auto Last = MakeMoveIterator(&Arr[2]);
FTracker Temp(*First++);
Temp = *First++;
always_check(First == Last);
}
{
int Arr[8] = { 0, 1, 2, 3, 4, 5, 6, 7 };
auto First = MakeMoveIterator(&Arr[0]);
auto Last = MakeMoveIterator(&Arr[8]);
auto ConstFirst = MakeMoveIterator(&AsConst(Arr)[0]);
auto ConstLast = MakeMoveIterator(&AsConst(Arr)[8]);
always_check(First == ConstFirst);
always_check(Last == ConstLast );
always_check(ConstLast - First == 8);
auto Iter = ConstFirst;
auto Jter = ConstLast;
++Iter;
--Jter;
always_check(*Iter++ == 1);
always_check(*Jter-- == 7);
Iter += 2;
Jter -= 2;
always_check(Iter[-1] == 3);
always_check(Jter[ 1] == 5);
Iter = Iter - 2;
Jter = Jter + 2;
always_check(*Iter == 2);
always_check(*Jter == 6);
Iter = 2 + Iter;
Jter = Jter - 2;
always_check(Iter - Jter == 0);
}
}
void TestReverseIterator()
{
int Arr[8] = { 7, 6, 5, 4, 3, 2, 1, 0 };
auto First = MakeReverseIterator(&Arr[8]);
auto Last = MakeReverseIterator(&Arr[0]);
auto ConstFirst = MakeReverseIterator(&AsConst(Arr)[8]);
auto ConstLast = MakeReverseIterator(&AsConst(Arr)[0]);
always_check(First == ConstFirst);
always_check(Last == ConstLast );
always_check(ConstLast - First == 8);
auto Iter = ConstFirst;
auto Jter = ConstLast;
++Iter;
--Jter;
always_check(*Iter++ == 1);
always_check(*Jter-- == 7);
Iter += 2;
Jter -= 2;
always_check(Iter[-1] == 3);
always_check(Jter[ 1] == 5);
Iter = Iter - 2;
Jter = Jter + 2;
always_check(*Iter == 2);
always_check(*Jter == 6);
Iter = 2 + Iter;
Jter = Jter - 2;
always_check(Iter - Jter == 0);
}
void TestCountedIterator()
{
int Arr[16] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 };
auto First = MakeCountedIterator(&Arr[0], 8);
auto Last = First + 8;
auto ConstFirst = MakeCountedIterator(&AsConst(Arr)[0], 8);
auto ConstLast = ConstFirst + 8;
always_check(First == ConstFirst);
always_check(Last == ConstLast );
always_check(ConstLast - First == 8);
always_check(Last == DefaultSentinel);
always_check(DefaultSentinel == Last);
always_check(DefaultSentinel - First == 8);
always_check(First - DefaultSentinel == -8);
always_check(First == ConstFirst);
always_check(Last == ConstLast );
always_check(Last - First == 8);
auto Iter = ConstFirst;
auto Jter = ConstLast;
++Iter;
--Jter;
always_check(*Iter++ == 1);
always_check(*Jter-- == 7);
Iter += 2;
Jter -= 2;
always_check(Iter[-1] == 3);
always_check(Jter[ 1] == 5);
Iter = Iter - 2;
Jter = Jter + 2;
always_check(*Iter == 2);
always_check(*Jter == 6);
Iter = 2 + Iter;
Jter = Jter - 2;
always_check(Iter - Jter == 0);
}
void TestInsertIterator()
{
{
TList<int> List = { 1, 2, 3 };
auto Iter = MakeFrontInserter(List);
*Iter++ = 1;
*Iter++ = 2;
*Iter++ = 3;
always_check(List == TList<int>({ 3, 2, 1, 1, 2, 3 }));
}
{
TList<int> List = { 1, 2, 3 };
auto Iter = MakeBackInserter(List);
*Iter++ = 1;
*Iter++ = 2;
*Iter++ = 3;
always_check(List == TList<int>({ 1, 2, 3, 1, 2, 3 }));
}
{
TList<int> List = { 1, 2, 3 };
auto Iter = MakeInserter(List, ++++List.Begin());
*Iter++ = 1;
*Iter++ = 2;
*Iter++ = 3;
always_check(List == TList<int>({ 1, 2, 1, 2, 3, 3 }));
}
}
NAMESPACE_END(Testing)
NAMESPACE_MODULE_END(Utility)
NAMESPACE_MODULE_END(Redcraft)
NAMESPACE_REDCRAFT_END

View File

@ -67,14 +67,12 @@ public:
}
template <CInputOrOutputIterator J> requires (CCommonType<I, J>)
NODISCARD friend FORCEINLINE constexpr bool operator==(const TCountedIterator& LHS, const TCountedIterator<J>& RHS) { return LHS.Length == RHS.Length; }
NODISCARD friend FORCEINLINE constexpr bool operator==(const TCountedIterator& LHS, const TCountedIterator<J>& RHS) { return LHS.Num() == RHS.Num(); }
template <CInputOrOutputIterator J> requires (CCommonType<I, J>)
NODISCARD friend FORCEINLINE constexpr strong_ordering operator<=>(const TCountedIterator& LHS, const TCountedIterator<J>& RHS) { return LHS.Length <=> RHS.Length; }
NODISCARD friend FORCEINLINE constexpr strong_ordering operator<=>(const TCountedIterator& LHS, const TCountedIterator<J>& RHS) { return LHS.Num() <=> RHS.Num(); }
NODISCARD FORCEINLINE constexpr bool operator==(FDefaultSentinel) const& { return Length == static_cast<ptrdiff>(0); }
NODISCARD FORCEINLINE constexpr strong_ordering operator<=>(FDefaultSentinel) const& { return static_cast<ptrdiff>(0) <=> Length; }
NODISCARD FORCEINLINE constexpr bool operator==(FDefaultSentinel) const& { return Num() == static_cast<ptrdiff>(0); }
NODISCARD FORCEINLINE constexpr TIteratorReference<I> operator*() { CheckThis(true); return *GetBase(); }
NODISCARD FORCEINLINE constexpr TIteratorReference<I> operator*() const requires (CDereferenceable<const I>) { CheckThis(true); return *GetBase(); }
@ -99,7 +97,7 @@ public:
NODISCARD friend FORCEINLINE constexpr TCountedIterator operator+(ptrdiff Offset, TCountedIterator Iter) requires (CRandomAccessIterator<I>) { return Iter + Offset; }
template <CInputOrOutputIterator J> requires (CCommonType<I, J>)
NODISCARD friend FORCEINLINE constexpr ptrdiff operator-(const TCountedIterator& LHS, const TCountedIterator<J>& RHS) { LHS.CheckThis(); RHS.CheckThis(); return LHS.Length - RHS.Length; }
NODISCARD friend FORCEINLINE constexpr ptrdiff operator-(const TCountedIterator& LHS, const TCountedIterator<J>& RHS) { return RHS.Num() - LHS.Num(); }
NODISCARD friend FORCEINLINE constexpr ptrdiff operator-(const TCountedIterator& LHS, FDefaultSentinel) { LHS.CheckThis(); return -LHS.Num(); }
NODISCARD friend FORCEINLINE constexpr ptrdiff operator-(FDefaultSentinel, const TCountedIterator& RHS) { RHS.CheckThis(); return RHS.Num(); }
@ -123,9 +121,6 @@ private:
checkf(!(bExceptEnd && Length == static_cast<ptrdiff>(0)), TEXT("Read access violation. Please check Num()."));
}
template <CInputOrOutputIterator J>
friend class TCountedIterator;
};
static_assert( CInputIterator<TCountedIterator< IInputIterator<int&>>>);

View File

@ -1,10 +1,12 @@
#pragma once
#include "CoreTypes.h"
#include "Iterator/Utility.h"
#include "TypeTraits/TypeTraits.h"
#include "Templates/Noncopyable.h"
#include "Iterator/Utility.h"
#include "Templates/Utility.h"
#include "Templates/Noncopyable.h"
#include "Templates/Invoke.h"
#include "Miscellaneous/AssertionMacros.h"
NAMESPACE_REDCRAFT_BEGIN
NAMESPACE_MODULE_BEGIN(Redcraft)
@ -142,7 +144,7 @@ NODISCARD FORCEINLINE constexpr auto MakeBackInserter(C& Container)
template <typename C>
NODISCARD FORCEINLINE constexpr auto MakeInserter(C& Container, const typename C::FConstIterator& InIter)
{
return NAMESPACE_PRIVATE::TInsertIterator([&Container, Iter = InIter]<typename T>(T&& A) mutable { Iter = Container.Insert(Iter, Forward<T>(A)); });
return NAMESPACE_PRIVATE::TInsertIterator([&Container, Iter = InIter]<typename T>(T&& A) mutable { Iter = Container.Insert(Iter, Forward<T>(A)); ++Iter; });
}
NAMESPACE_MODULE_END(Utility)

View File

@ -47,7 +47,7 @@ public:
NODISCARD friend FORCEINLINE constexpr bool operator==(const TMoveIterator& LHS, const TMoveIterator<J>& RHS) { return LHS.GetBase() == RHS.GetBase(); }
template <CInputIterator J> requires (CThreeWayComparable<I, J>)
NODISCARD friend FORCEINLINE constexpr TCompareThreeWayResult<I, J> operator<=>(const TMoveIterator& LHS, const TMoveIterator<J>& RHS) { return RHS.GetBase() <=> LHS.GetBase(); }
NODISCARD friend FORCEINLINE constexpr TCompareThreeWayResult<I, J> operator<=>(const TMoveIterator& LHS, const TMoveIterator<J>& RHS) { return LHS.GetBase() <=> RHS.GetBase(); }
NODISCARD FORCEINLINE constexpr TIteratorRValueReference<I> operator*() const { return MoveTemp(*GetBase()); }

View File

@ -63,8 +63,8 @@ public:
FORCEINLINE constexpr TReverseIterator& operator+=(ptrdiff Offset) requires (CRandomAccessIterator<I>) { Current -= Offset; return *this; }
FORCEINLINE constexpr TReverseIterator& operator-=(ptrdiff Offset) requires (CRandomAccessIterator<I>) { Current += Offset; return *this; }
NODISCARD FORCEINLINE constexpr TReverseIterator operator+(ptrdiff Offset) const requires (CRandomAccessIterator<I>) { TReverseIterator Temp = *this; Temp -= Offset; return Temp; }
NODISCARD FORCEINLINE constexpr TReverseIterator operator-(ptrdiff Offset) const requires (CRandomAccessIterator<I>) { TReverseIterator Temp = *this; Temp += Offset; return Temp; }
NODISCARD FORCEINLINE constexpr TReverseIterator operator+(ptrdiff Offset) const requires (CRandomAccessIterator<I>) { TReverseIterator Temp = *this; Temp += Offset; return Temp; }
NODISCARD FORCEINLINE constexpr TReverseIterator operator-(ptrdiff Offset) const requires (CRandomAccessIterator<I>) { TReverseIterator Temp = *this; Temp -= Offset; return Temp; }
NODISCARD friend FORCEINLINE constexpr TReverseIterator operator+(ptrdiff Offset, const TReverseIterator& Iter) requires (CRandomAccessIterator<I>) { return Iter + Offset; }

View File

@ -34,9 +34,17 @@ public:
FORCEINLINE constexpr explicit TMoveView(V InBase) : Base(MoveTemp(InBase)) { }
NODISCARD FORCEINLINE constexpr auto Begin() { return MakeMoveIterator(Range::Begin(Base)); }
NODISCARD FORCEINLINE constexpr auto Begin() requires (!CSimpleView<V>)
{
return MakeMoveIterator(Range::Begin(Base));
}
NODISCARD FORCEINLINE constexpr auto End()
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>)
{
@ -45,9 +53,7 @@ public:
else return MakeMoveSentinel(Range::End(Base));
}
NODISCARD FORCEINLINE constexpr auto Begin() const requires (CRange<const V>) { return MakeMoveIterator(Range::Begin(Base)); }
NODISCARD FORCEINLINE constexpr auto End() const requires (CRange<const V>)
NODISCARD FORCEINLINE constexpr auto End() const requires (CRange<const V>)
{
if constexpr (CCommonRange<V>)
{

View File

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

View File

@ -36,7 +36,7 @@ public:
FORCEINLINE constexpr TTakeView(V InBase, size_t InCount) : Base(MoveTemp(InBase)), Count(InCount) { }
NODISCARD FORCEINLINE constexpr auto Begin()
NODISCARD FORCEINLINE constexpr auto Begin() requires (!CSimpleView<V>)
{
if constexpr (CSizedRange<V>)
{
@ -62,7 +62,7 @@ public:
else return MakeCountedIterator(Range::Begin(Base), Count);
}
NODISCARD FORCEINLINE constexpr auto End()
NODISCARD FORCEINLINE constexpr auto End() requires (!CSimpleView<V>)
{
if constexpr (CSizedRange<V>)
{

View File

@ -0,0 +1,149 @@
#pragma once
#include "CoreTypes.h"
#include "TypeTraits/TypeTraits.h"
#include "Templates/Utility.h"
#include "Iterator/Utility.h"
#include "Iterator/BasicIterator.h"
#include "Iterator/CountedIterator.h"
#include "Numeric/Math.h"
#include "Range/Utility.h"
#include "Range/Pipe.h"
#include "Range/View.h"
#include "Range/AllView.h"
NAMESPACE_REDCRAFT_BEGIN
NAMESPACE_MODULE_BEGIN(Redcraft)
NAMESPACE_MODULE_BEGIN(Utility)
NAMESPACE_BEGIN(Range)
/**
* A view adapter that includes elements that satisfy the predicate from the beginning of the range.
* When based on an input view, the take while view satisfies at least an input view up to a contiguous view.
* When based on a forward and output view, the take while view satisfies an output view.
*/
template <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

View File

@ -175,7 +175,7 @@ private:
NODISCARD friend FORCEINLINE constexpr ptrdiff operator-(const FSentinelImpl& LHS, const FIteratorImpl<bConst>& RHS)
requires CSizedSentinelFor<TRangeSentinel<FBase>, TRangeIterator<FBase>>
{
return RHS.GetBase() - LHS.GetBase();
return LHS.GetBase() - RHS.GetBase();
}
NODISCARD FORCEINLINE constexpr TRangeSentinel<FBase> GetBase() const { return Current; }

View File

@ -98,6 +98,12 @@ concept CViewableRange = CRange<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. */

View File

@ -0,0 +1,21 @@
#pragma once
#include "CoreTypes.h"
NAMESPACE_REDCRAFT_BEGIN
NAMESPACE_MODULE_BEGIN(Redcraft)
NAMESPACE_MODULE_BEGIN(Utility)
NAMESPACE_BEGIN(Testing)
REDCRAFTUTILITY_API void TestIterator();
REDCRAFTUTILITY_API void TestMoveIterator();
REDCRAFTUTILITY_API void TestReverseIterator();
REDCRAFTUTILITY_API void TestCountedIterator();
REDCRAFTUTILITY_API void TestInsertIterator();
NAMESPACE_END(Testing)
NAMESPACE_MODULE_END(Utility)
NAMESPACE_MODULE_END(Redcraft)
NAMESPACE_REDCRAFT_END