feat(algorithms): add more iterator algorithm and the corresponding testing
This commit is contained in:
parent
a68a6d16b6
commit
04bb4be901
@ -3,6 +3,7 @@
|
|||||||
#include "Algorithms/Algorithms.h"
|
#include "Algorithms/Algorithms.h"
|
||||||
#include "Containers/Array.h"
|
#include "Containers/Array.h"
|
||||||
#include "Containers/List.h"
|
#include "Containers/List.h"
|
||||||
|
#include "Ranges/Factory.h"
|
||||||
#include "Miscellaneous/AssertionMacros.h"
|
#include "Miscellaneous/AssertionMacros.h"
|
||||||
|
|
||||||
NAMESPACE_REDCRAFT_BEGIN
|
NAMESPACE_REDCRAFT_BEGIN
|
||||||
@ -15,20 +16,109 @@ NAMESPACE_PRIVATE_BEGIN
|
|||||||
|
|
||||||
void TestBasic()
|
void TestBasic()
|
||||||
{
|
{
|
||||||
TArray<int> Arr = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
|
{
|
||||||
|
TArray<int> Arr = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
|
||||||
|
|
||||||
auto Iter = Arr.Begin();
|
auto Iter = Arr.Begin();
|
||||||
|
|
||||||
Algorithms::Advance(Iter, 5);
|
Algorithms::Advance(Iter, 5);
|
||||||
|
|
||||||
always_check(*Iter == 5);
|
always_check(*Iter == 5);
|
||||||
|
|
||||||
always_check(Algorithms::Distance(Arr.Begin(), Iter) == 5);
|
always_check(Algorithms::Distance(Arr.Begin(), Iter) == 5);
|
||||||
|
|
||||||
always_check(Algorithms::Distance(Arr) == 10);
|
always_check(Algorithms::Distance(Arr) == 10);
|
||||||
|
|
||||||
always_check(*Algorithms::Next(Iter, 2) == 7);
|
always_check(*Algorithms::Next(Iter) == 6);
|
||||||
always_check(*Algorithms::Prev(Iter, 2) == 3);
|
always_check(*Algorithms::Next(Iter, 2) == 7);
|
||||||
|
always_check(*Algorithms::Prev(Iter) == 4);
|
||||||
|
always_check(*Algorithms::Prev(Iter, 2) == 3);
|
||||||
|
|
||||||
|
always_check(Algorithms::Next(Iter, Arr.End()) == Arr.End());
|
||||||
|
always_check(Algorithms::Next(Iter, 16, Arr.End()) == Arr.End());
|
||||||
|
|
||||||
|
always_check(Algorithms::Prev(Iter, 16, Arr.Begin()) == Arr.Begin());
|
||||||
|
|
||||||
|
Iter = Arr.Begin();
|
||||||
|
|
||||||
|
Algorithms::Advance(Iter, Arr.End());
|
||||||
|
|
||||||
|
always_check(Iter == Arr.End());
|
||||||
|
|
||||||
|
Iter = Arr.Begin();
|
||||||
|
|
||||||
|
always_check(Algorithms::Advance(Iter, 16, Arr.End()) == 6);
|
||||||
|
|
||||||
|
always_check(Iter == Arr.End());
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
TList<int> Arr = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
|
||||||
|
|
||||||
|
auto Iter = Arr.Begin();
|
||||||
|
|
||||||
|
Algorithms::Advance(Iter, 5);
|
||||||
|
|
||||||
|
always_check(*Iter == 5);
|
||||||
|
|
||||||
|
always_check(Algorithms::Distance(Arr.Begin(), Iter) == 5);
|
||||||
|
|
||||||
|
always_check(Algorithms::Distance(Arr) == 10);
|
||||||
|
|
||||||
|
always_check(*Algorithms::Next(Iter) == 6);
|
||||||
|
always_check(*Algorithms::Next(Iter, 2) == 7);
|
||||||
|
always_check(*Algorithms::Prev(Iter) == 4);
|
||||||
|
always_check(*Algorithms::Prev(Iter, 2) == 3);
|
||||||
|
|
||||||
|
always_check(Algorithms::Next(Iter, Arr.End()) == Arr.End());
|
||||||
|
always_check(Algorithms::Next(Iter, 16, Arr.End()) == Arr.End());
|
||||||
|
|
||||||
|
always_check(Algorithms::Prev(Iter, 16, Arr.Begin()) == Arr.Begin());
|
||||||
|
|
||||||
|
Iter = Arr.Begin();
|
||||||
|
|
||||||
|
Algorithms::Advance(Iter, Arr.End());
|
||||||
|
|
||||||
|
always_check(Iter == Arr.End());
|
||||||
|
|
||||||
|
Iter = Arr.Begin();
|
||||||
|
|
||||||
|
always_check(Algorithms::Advance(Iter, 16, Arr.End()) == 6);
|
||||||
|
|
||||||
|
always_check(Iter == Arr.End());
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
auto Arr = Ranges::Iota(0, 10);
|
||||||
|
|
||||||
|
auto Iter = Arr.Begin();
|
||||||
|
|
||||||
|
Algorithms::Advance(Iter, 5);
|
||||||
|
|
||||||
|
always_check(*Iter == 5);
|
||||||
|
|
||||||
|
always_check(Algorithms::Distance(Arr.Begin(), Iter) == 5);
|
||||||
|
|
||||||
|
always_check(Algorithms::Distance(Arr) == 10);
|
||||||
|
|
||||||
|
always_check(*Algorithms::Next(Iter) == 6);
|
||||||
|
always_check(*Algorithms::Next(Iter, 2) == 7);
|
||||||
|
|
||||||
|
always_check(Algorithms::Next(Iter, Arr.End()) == Arr.End());
|
||||||
|
always_check(Algorithms::Next(Iter, 16, Arr.End()) == Arr.End());
|
||||||
|
|
||||||
|
Iter = Arr.Begin();
|
||||||
|
|
||||||
|
Algorithms::Advance(Iter, Arr.End());
|
||||||
|
|
||||||
|
always_check(Iter == Arr.End());
|
||||||
|
|
||||||
|
Iter = Arr.Begin();
|
||||||
|
|
||||||
|
always_check(Algorithms::Advance(Iter, 16, Arr.End()) == 6);
|
||||||
|
|
||||||
|
always_check(Iter == Arr.End());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
NAMESPACE_PRIVATE_END
|
NAMESPACE_PRIVATE_END
|
||||||
|
@ -6,6 +6,7 @@
|
|||||||
#include "Iterators/Sentinel.h"
|
#include "Iterators/Sentinel.h"
|
||||||
#include "Iterators/BasicIterator.h"
|
#include "Iterators/BasicIterator.h"
|
||||||
#include "Ranges/Utility.h"
|
#include "Ranges/Utility.h"
|
||||||
|
#include "Numerics/Math.h"
|
||||||
#include "Miscellaneous/AssertionMacros.h"
|
#include "Miscellaneous/AssertionMacros.h"
|
||||||
|
|
||||||
NAMESPACE_REDCRAFT_BEGIN
|
NAMESPACE_REDCRAFT_BEGIN
|
||||||
@ -15,7 +16,7 @@ NAMESPACE_MODULE_BEGIN(Utility)
|
|||||||
NAMESPACE_BEGIN(Algorithms)
|
NAMESPACE_BEGIN(Algorithms)
|
||||||
|
|
||||||
/** Increments given iterator 'Iter' by 'N' elements. */
|
/** Increments given iterator 'Iter' by 'N' elements. */
|
||||||
template <CInputIterator I>
|
template <CInputOrOutputIterator I>
|
||||||
FORCEINLINE constexpr void Advance(I& Iter, ptrdiff N)
|
FORCEINLINE constexpr void Advance(I& Iter, ptrdiff N)
|
||||||
{
|
{
|
||||||
if constexpr (CRandomAccessIterator<I>)
|
if constexpr (CRandomAccessIterator<I>)
|
||||||
@ -32,22 +33,84 @@ FORCEINLINE constexpr void Advance(I& Iter, ptrdiff N)
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
checkf(N >= 0, TEXT("The iterator must satisfy the CBidirectionalIterator in order to be decremented."));
|
checkf(N >= 0, TEXT("The iterator must satisfy the CBidirectionalIterator in order to be decremented."));
|
||||||
|
|
||||||
for (; N > 0; --N) ++Iter;
|
for (; N > 0; --N) ++Iter;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Increments given iterator 'Iter' to the 'Sent' position. */
|
||||||
|
template <CInputOrOutputIterator I, CSentinelFor<I> S>
|
||||||
|
FORCEINLINE constexpr void Advance(I& Iter, S Sent)
|
||||||
|
{
|
||||||
|
if constexpr (CAssignableFrom<I&, S>)
|
||||||
|
{
|
||||||
|
Iter = Sent;
|
||||||
|
}
|
||||||
|
|
||||||
|
else if constexpr (CSizedSentinelFor<S, I>)
|
||||||
|
{
|
||||||
|
Algorithms::Advance(Iter, Sent - Iter);
|
||||||
|
}
|
||||||
|
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for (; Iter != Sent; ++Iter);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Increments given iterator 'Iter' by 'N' elements, up to the 'Sent' position. */
|
||||||
|
template <CInputOrOutputIterator I, CSentinelFor<I> S>
|
||||||
|
FORCEINLINE constexpr ptrdiff Advance(I& Iter, ptrdiff N, S Sent)
|
||||||
|
{
|
||||||
|
if constexpr (CSizedSentinelFor<S, I>)
|
||||||
|
{
|
||||||
|
const ptrdiff Distance = Sent - Iter;
|
||||||
|
|
||||||
|
if (Math::Abs(N) > Math::Abs(Distance))
|
||||||
|
{
|
||||||
|
Algorithms::Advance(Iter, Sent);
|
||||||
|
|
||||||
|
return N - Distance;
|
||||||
|
}
|
||||||
|
|
||||||
|
Algorithms::Advance(Iter, N);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
else if constexpr (CBidirectionalIterator<I>)
|
||||||
|
{
|
||||||
|
for (; N > 0 && Iter != Sent; --N) ++Iter;
|
||||||
|
for (; N < 0 && Iter != Sent; ++N) --Iter;
|
||||||
|
|
||||||
|
return N;
|
||||||
|
}
|
||||||
|
|
||||||
|
else
|
||||||
|
{
|
||||||
|
checkf(N >= 0, TEXT("The iterator must satisfy the CBidirectionalIterator in order to be decremented."));
|
||||||
|
|
||||||
|
for (; N > 0 && Iter != Sent; --N) ++Iter;
|
||||||
|
|
||||||
|
return N;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/** @return The number of hops from 'First' to 'Last'. */
|
/** @return The number of hops from 'First' to 'Last'. */
|
||||||
template <CInputIterator I, CSentinelFor<I> S>
|
template <CInputOrOutputIterator I, CSentinelFor<I> S>
|
||||||
NODISCARD FORCEINLINE constexpr ptrdiff Distance(I First, S Last)
|
NODISCARD FORCEINLINE constexpr ptrdiff Distance(I First, S Last)
|
||||||
{
|
{
|
||||||
if constexpr (CSizedSentinelFor<S, I>)
|
if constexpr (CSizedSentinelFor<S, I>)
|
||||||
{
|
{
|
||||||
return Last - First;
|
return Last - First;
|
||||||
}
|
}
|
||||||
|
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
ptrdiff Result = 0;
|
ptrdiff Result = 0;
|
||||||
|
|
||||||
for (; First != Last; ++First) ++Result;
|
for (; First != Last; ++First) ++Result;
|
||||||
|
|
||||||
return Result;
|
return Result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -60,25 +123,64 @@ NODISCARD FORCEINLINE constexpr ptrdiff Distance(R&& Range)
|
|||||||
{
|
{
|
||||||
return static_cast<ptrdiff>(Ranges::Num(Range));
|
return static_cast<ptrdiff>(Ranges::Num(Range));
|
||||||
}
|
}
|
||||||
|
|
||||||
else return Algorithms::Distance(Ranges::Begin(Range), Ranges::End(Range));
|
else return Algorithms::Distance(Ranges::Begin(Range), Ranges::End(Range));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @return The 1-th successor of iterator 'Iter'. */
|
||||||
|
template <CInputOrOutputIterator I>
|
||||||
|
NODISCARD FORCEINLINE constexpr I Next(I Iter)
|
||||||
|
{
|
||||||
|
return ++Iter;
|
||||||
|
}
|
||||||
|
|
||||||
/** @return The 'N'-th successor of iterator 'Iter'. */
|
/** @return The 'N'-th successor of iterator 'Iter'. */
|
||||||
template <CInputIterator I>
|
template <CInputOrOutputIterator I>
|
||||||
NODISCARD FORCEINLINE constexpr I Next(I Iter, ptrdiff N = 1)
|
NODISCARD FORCEINLINE constexpr I Next(I Iter, ptrdiff N)
|
||||||
{
|
{
|
||||||
Algorithms::Advance(Iter, N);
|
Algorithms::Advance(Iter, N);
|
||||||
return Iter;
|
return Iter;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @return The successor of iterator 'Iter' to the 'Sent' position. */
|
||||||
|
template <CInputOrOutputIterator I, CSentinelFor<I> S>
|
||||||
|
NODISCARD FORCEINLINE constexpr I Next(I Iter, S Sent)
|
||||||
|
{
|
||||||
|
Algorithms::Advance(Iter, Sent);
|
||||||
|
return Iter;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @return The 'N'-th successor of iterator 'Iter', up to the 'Sent' position. */
|
||||||
|
template <CInputOrOutputIterator I, CSentinelFor<I> S>
|
||||||
|
NODISCARD FORCEINLINE constexpr I Next(I Iter, ptrdiff N, S Sent)
|
||||||
|
{
|
||||||
|
Algorithms::Advance(Iter, N, Sent);
|
||||||
|
return Iter;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @return The 1-th predecessor of iterator 'Iter'. */
|
||||||
|
template <CBidirectionalIterator I>
|
||||||
|
NODISCARD FORCEINLINE constexpr I Prev(I Iter)
|
||||||
|
{
|
||||||
|
return --Iter;
|
||||||
|
}
|
||||||
|
|
||||||
/** @return The 'N'-th predecessor of iterator 'Iter'. */
|
/** @return The 'N'-th predecessor of iterator 'Iter'. */
|
||||||
template <CBidirectionalIterator I>
|
template <CBidirectionalIterator I>
|
||||||
NODISCARD FORCEINLINE constexpr I Prev(I Iter, ptrdiff N = 1)
|
NODISCARD FORCEINLINE constexpr I Prev(I Iter, ptrdiff N)
|
||||||
{
|
{
|
||||||
Algorithms::Advance(Iter, -N);
|
Algorithms::Advance(Iter, -N);
|
||||||
return Iter;
|
return Iter;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @return The predecessor of iterator 'Iter', up to the 'First' position. */
|
||||||
|
template <CBidirectionalIterator I>
|
||||||
|
NODISCARD FORCEINLINE constexpr I Prev(I Iter, ptrdiff N, I First)
|
||||||
|
{
|
||||||
|
Algorithms::Advance(Iter, -N, First);
|
||||||
|
return Iter;
|
||||||
|
}
|
||||||
|
|
||||||
NAMESPACE_END(Algorithms)
|
NAMESPACE_END(Algorithms)
|
||||||
|
|
||||||
NAMESPACE_MODULE_END(Utility)
|
NAMESPACE_MODULE_END(Utility)
|
||||||
|
Loading…
Reference in New Issue
Block a user