1756 lines
70 KiB
C++
1756 lines
70 KiB
C++
#pragma once
|
|
|
|
#include "CoreTypes.h"
|
|
#include "TypeTraits/TypeTraits.h"
|
|
#include "Templates/Utility.h"
|
|
#include "Templates/Invoke.h"
|
|
#include "Templates/ReferenceWrapper.h"
|
|
#include "Templates/Optional.h"
|
|
#include "Templates/Tuple.h"
|
|
#include "Iterators/Utility.h"
|
|
#include "Iterators/Sentinel.h"
|
|
#include "Iterators/BasicIterator.h"
|
|
#include "Iterators/ReverseIterator.h"
|
|
#include "Ranges/Utility.h"
|
|
#include "Ranges/View.h"
|
|
#include "Algorithms/Basic.h"
|
|
#include "Miscellaneous/AssertionMacros.h"
|
|
|
|
NAMESPACE_REDCRAFT_BEGIN
|
|
NAMESPACE_MODULE_BEGIN(Redcraft)
|
|
NAMESPACE_MODULE_BEGIN(Utility)
|
|
|
|
NAMESPACE_BEGIN(Algorithms)
|
|
|
|
/**
|
|
* Checks if all elements in the range satisfy the predicate.
|
|
*
|
|
* @param Range - The range to check.
|
|
* @param Predicate - The unary predicate to satisfy.
|
|
* @param Projection - The projection to apply to the elements before checking.
|
|
*
|
|
* @return true if all elements satisfy the predicate, false otherwise.
|
|
*/
|
|
template <CInputRange R,
|
|
CRegularInvocable<TRangeReference<R>> Proj =
|
|
decltype([]<typename T>(T&& A) -> T&& { return Forward<T>(A); }),
|
|
CPredicate<TInvokeResult<Proj, TRangeReference<R>>> Pred>
|
|
NODISCARD constexpr bool AllOf(R&& Range, Pred Predicate, Proj Projection = { })
|
|
{
|
|
if constexpr (CSizedRange<R&>)
|
|
{
|
|
checkf(Algorithms::Distance(Range) >= 0, TEXT("Illegal range. Please check Algorithms::Distance(Range)."));
|
|
}
|
|
|
|
auto Iter = Ranges::Begin(Range);
|
|
auto Sent = Ranges::End (Range);
|
|
|
|
for (; Iter != Sent; ++Iter)
|
|
{
|
|
if (!Invoke(Predicate, Invoke(Projection, *Iter)))
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Checks if all elements in the range satisfy the predicate.
|
|
*
|
|
* @param First - The iterator of the range.
|
|
* @param Last - The sentinel of the range.
|
|
* @param Predicate - The unary predicate to satisfy.
|
|
* @param Projection - The projection to apply to the elements before checking.
|
|
*
|
|
* @return true if all elements satisfy the predicate, false otherwise.
|
|
*/
|
|
template <CInputIterator I, CSentinelFor<I> S,
|
|
CRegularInvocable<TIteratorReference<I>> Proj =
|
|
decltype([]<typename T>(T&& A) -> T&& { return Forward<T>(A); }),
|
|
CPredicate<TInvokeResult<Proj, TIteratorReference<I>>> Pred>
|
|
NODISCARD FORCEINLINE constexpr bool AllOf(I First, S Last, Pred Predicate, Proj Projection = { })
|
|
{
|
|
if constexpr (CSizedSentinelFor<S, I>)
|
|
{
|
|
checkf(First - Last <= 0, TEXT("Illegal range iterator. Please check First <= Last."));
|
|
}
|
|
|
|
return Algorithms::AllOf(Ranges::View(MoveTemp(First), Last), Ref(Predicate), Ref(Projection));
|
|
}
|
|
|
|
/**
|
|
* Checks if any elements in the range satisfy the predicate.
|
|
*
|
|
* @param Range - The range to check.
|
|
* @param Predicate - The unary predicate to satisfy.
|
|
* @param Projection - The projection to apply to the elements before checking.
|
|
*
|
|
* @return true if any elements satisfy the predicate, false otherwise.
|
|
*/
|
|
template <CInputRange R,
|
|
CRegularInvocable<TRangeReference<R>> Proj =
|
|
decltype([]<typename T>(T&& A) -> T&& { return Forward<T>(A); }),
|
|
CPredicate<TInvokeResult<Proj, TRangeReference<R>>> Pred>
|
|
NODISCARD constexpr bool AnyOf(R&& Range, Pred Predicate, Proj Projection = { })
|
|
{
|
|
if constexpr (CSizedRange<R&>)
|
|
{
|
|
checkf(Algorithms::Distance(Range) >= 0, TEXT("Illegal range. Please check Algorithms::Distance(Range)."));
|
|
}
|
|
|
|
auto Iter = Ranges::Begin(Range);
|
|
auto Sent = Ranges::End (Range);
|
|
|
|
for (; Iter != Sent; ++Iter)
|
|
{
|
|
if (Invoke(Predicate, Invoke(Projection, *Iter)))
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* Checks if any elements in the range satisfy the predicate.
|
|
*
|
|
* @param First - The iterator of the range.
|
|
* @param Last - The sentinel of the range.
|
|
* @param Predicate - The unary predicate to satisfy.
|
|
* @param Projection - The projection to apply to the elements before checking.
|
|
*
|
|
* @return true if any elements satisfy the predicate, false otherwise.
|
|
*/
|
|
template <CInputIterator I, CSentinelFor<I> S,
|
|
CRegularInvocable<TIteratorReference<I>> Proj =
|
|
decltype([]<typename T>(T&& A) -> T&& { return Forward<T>(A); }),
|
|
CPredicate<TInvokeResult<Proj, TIteratorReference<I>>> Pred>
|
|
NODISCARD FORCEINLINE constexpr bool AnyOf(I First, S Last, Pred Predicate, Proj Projection = { })
|
|
{
|
|
if constexpr (CSizedSentinelFor<S, I>)
|
|
{
|
|
checkf(First - Last <= 0, TEXT("Illegal range iterator. Please check First <= Last."));
|
|
}
|
|
|
|
return Algorithms::AnyOf(Ranges::View(MoveTemp(First), Last), Ref(Predicate), Ref(Projection));
|
|
}
|
|
|
|
/**
|
|
* Checks if no elements in the range satisfy the predicate.
|
|
*
|
|
* @param Range - The range to check.
|
|
* @param Predicate - The unary predicate to satisfy.
|
|
* @param Projection - The projection to apply to the elements before checking.
|
|
*
|
|
* @return true if no elements satisfy the predicate, false otherwise.
|
|
*/
|
|
template <CInputRange R,
|
|
CRegularInvocable<TRangeReference<R>> Proj =
|
|
decltype([]<typename T>(T&& A) -> T&& { return Forward<T>(A); }),
|
|
CPredicate<TInvokeResult<Proj, TRangeReference<R>>> Pred>
|
|
NODISCARD constexpr bool NoneOf(R&& Range, Pred Predicate, Proj Projection = { })
|
|
{
|
|
if constexpr (CSizedRange<R&>)
|
|
{
|
|
checkf(Algorithms::Distance(Range) >= 0, TEXT("Illegal range. Please check Algorithms::Distance(Range)."));
|
|
}
|
|
|
|
auto Iter = Ranges::Begin(Range);
|
|
auto Sent = Ranges::End (Range);
|
|
|
|
for (; Iter != Sent; ++Iter)
|
|
{
|
|
if (Invoke(Predicate, Invoke(Projection, *Iter)))
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Checks if no elements in the range satisfy the predicate.
|
|
*
|
|
* @param First - The iterator of the range.
|
|
* @param Last - The sentinel of the range.
|
|
* @param Predicate - The unary predicate to satisfy.
|
|
* @param Projection - The projection to apply to the elements before checking.
|
|
*
|
|
* @return true if no elements satisfy the predicate, false otherwise.
|
|
*/
|
|
template <CInputIterator I, CSentinelFor<I> S,
|
|
CRegularInvocable<TIteratorReference<I>> Proj =
|
|
decltype([]<typename T>(T&& A) -> T&& { return Forward<T>(A); }),
|
|
CPredicate<TInvokeResult<Proj, TIteratorReference<I>>> Pred>
|
|
NODISCARD FORCEINLINE constexpr bool NoneOf(I First, S Last, Pred Predicate, Proj Projection = { })
|
|
{
|
|
if constexpr (CSizedSentinelFor<S, I>)
|
|
{
|
|
checkf(First - Last <= 0, TEXT("Illegal range iterator. Please check First <= Last."));
|
|
}
|
|
|
|
return Algorithms::NoneOf(Ranges::View(MoveTemp(First), Last), Ref(Predicate), Ref(Projection));
|
|
}
|
|
|
|
/**
|
|
* Checks if the range contains the given element.
|
|
*
|
|
* @param Range - The range to check.
|
|
* @param Value - The value to check.
|
|
* @param Predicate - The equivalence relation predicate between the projected elements and the value.
|
|
* @param Projection - The projection to apply to the elements before checking.
|
|
*
|
|
* @return true if the range contains the value, false otherwise.
|
|
*/
|
|
template <CInputRange R,
|
|
CRegularInvocable<TRangeReference<R>> Proj =
|
|
decltype([]<typename T>(T&& A) -> T&& { return Forward<T>(A); }),
|
|
CReferenceable T = TRemoveCVRef<TInvokeResult<Proj, TRangeReference<R>>>,
|
|
CEquivalenceRelation<TInvokeResult<Proj, TRangeReference<R>>, const T&> Pred =
|
|
TConditional<CWeaklyEqualityComparable<TInvokeResult<Proj, TRangeReference<R>>, const T&>,
|
|
decltype([]<typename LHS, typename RHS>(const LHS& A, const RHS& B) { return A == B; }), void>>
|
|
NODISCARD FORCEINLINE constexpr bool Contains(R&& Range, const T& Value, Pred Predicate = { }, Proj Projection = { })
|
|
{
|
|
if constexpr (CSizedRange<R&>)
|
|
{
|
|
checkf(Algorithms::Distance(Range) >= 0, TEXT("Illegal range. Please check Algorithms::Distance(Range)."));
|
|
}
|
|
|
|
auto Iter = Ranges::Begin(Range);
|
|
auto Sent = Ranges::End (Range);
|
|
|
|
for (; Iter != Sent; ++Iter)
|
|
{
|
|
if (Invoke(Predicate, Invoke(Projection, *Iter), Value))
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* Checks if the range contains the given element.
|
|
*
|
|
* @param First - The iterator of the range.
|
|
* @param Last - The sentinel of the range.
|
|
* @param Value - The value to check.
|
|
* @param Predicate - The equivalence relation predicate between the projected elements and the value.
|
|
* @param Projection - The projection to apply to the elements before checking.
|
|
*
|
|
* @return true if the range contains the value, false otherwise.
|
|
*/
|
|
template <CInputIterator I, CSentinelFor<I> S,
|
|
CRegularInvocable<TIteratorReference<I>> Proj =
|
|
decltype([]<typename T>(T&& A) -> T&& { return Forward<T>(A); }),
|
|
CReferenceable T = TRemoveCVRef<TInvokeResult<Proj, TIteratorReference<I>>>,
|
|
CEquivalenceRelation<TInvokeResult<Proj, TIteratorReference<I>>, const T&> Pred =
|
|
TConditional<CWeaklyEqualityComparable<TInvokeResult<Proj, TIteratorReference<I>>, const T&>,
|
|
decltype([]<typename LHS, typename RHS>(const LHS& A, const RHS& B) { return A == B; }), void>>
|
|
NODISCARD FORCEINLINE constexpr bool Contains(I First, S Last, const T& Value, Pred Predicate = { }, Proj Projection = { })
|
|
{
|
|
if constexpr (CSizedSentinelFor<S, I>)
|
|
{
|
|
checkf(First - Last <= 0, TEXT("Illegal range iterator. Please check First <= Last."));
|
|
}
|
|
|
|
return Algorithms::Contains(Ranges::View(MoveTemp(First), Last), Value, Ref(Predicate), Ref(Projection));
|
|
}
|
|
|
|
/**
|
|
* Checks if the range contains the given subrange.
|
|
*
|
|
* @param Haystack - The range of elements to examine, aka the haystack.
|
|
* @param Needle - The range of elements to search for, aka the needle.
|
|
* @param Predicate - The equivalence relation predicate between the projected elements.
|
|
* @param HaystackProjection - The projection to apply to the haystack's elements before checking.
|
|
* @param NeedleProjection - The projection to apply to the needle's elements before checking.
|
|
*
|
|
* @return true if the haystack contains the needle, false otherwise.
|
|
*/
|
|
template <CForwardRange R1, CForwardRange R2,
|
|
CRegularInvocable<TRangeReference<R1>> Proj1 =
|
|
decltype([]<typename T>(T&& A) -> T&& { return Forward<T>(A); }),
|
|
CRegularInvocable<TRangeReference<R2>> Proj2 =
|
|
decltype([]<typename T>(T&& A) -> T&& { return Forward<T>(A); }),
|
|
CEquivalenceRelation<TInvokeResult<Proj1, TRangeReference<R1>>, TInvokeResult<Proj2, TRangeReference<R2>>> Pred =
|
|
TConditional<CWeaklyEqualityComparable<TInvokeResult<Proj1, TRangeReference<R1>>, TInvokeResult<Proj2, TRangeReference<R2>>>,
|
|
decltype([]<typename LHS, typename RHS>(const LHS& A, const RHS& B) { return A == B; }), void>>
|
|
NODISCARD constexpr bool Contains(R1&& Haystack, R2&& Needle, Pred Predicate = { }, Proj1 HaystackProjection = { }, Proj2 NeedleProjection = { })
|
|
{
|
|
if constexpr (CSizedRange<R1&>)
|
|
{
|
|
checkf(Algorithms::Distance(Haystack) >= 0, TEXT("Illegal range. Please check Algorithms::Distance(Haystack)."));
|
|
}
|
|
|
|
if constexpr (CSizedRange<R2&>)
|
|
{
|
|
checkf(Algorithms::Distance(Needle) >= 0, TEXT("Illegal range. Please check Algorithms::Distance(Needle)."));
|
|
}
|
|
|
|
auto FirstA = Ranges::Begin(Haystack);
|
|
auto SentA = Ranges::End (Haystack);
|
|
|
|
auto FirstB = Ranges::Begin(Needle);
|
|
auto SentB = Ranges::End (Needle);
|
|
|
|
while (true)
|
|
{
|
|
auto IterA = FirstA;
|
|
auto IterB = FirstB;
|
|
|
|
while (true)
|
|
{
|
|
if (IterB == SentB) return true;
|
|
if (IterA == SentA) return false;
|
|
|
|
if (!Invoke(Predicate, Invoke(HaystackProjection, *IterA), Invoke(NeedleProjection, *IterB))) break;
|
|
|
|
++IterA;
|
|
++IterB;
|
|
}
|
|
|
|
++FirstA;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Checks if the range contains the given subrange.
|
|
*
|
|
* @param HaystackFirst - The iterator of elements to examine, aka the haystack.
|
|
* @param HaystackLast - The sentinel of elements to examine, aka the haystack.
|
|
* @param NeedleFirst - The iterator of elements to search for, aka the needle.
|
|
* @param NeedleLast - The sentinel of elements to search for, aka the needle.
|
|
* @param Predicate - The equivalence relation predicate between the projected elements.
|
|
* @param HaystackProjection - The projection to apply to the haystack's elements before checking.
|
|
* @param NeedleProjection - The projection to apply to the needle's elements before checking.
|
|
*
|
|
* @return true if the haystack contains the needle, false otherwise.
|
|
*/
|
|
template <CForwardIterator I1, CSentinelFor<I1> S1, CForwardIterator I2, CSentinelFor<I2> S2,
|
|
CRegularInvocable<TIteratorReference<I1>> Proj1 =
|
|
decltype([]<typename T>(T&& A) -> T&& { return Forward<T>(A); }),
|
|
CRegularInvocable<TIteratorReference<I2>> Proj2 =
|
|
decltype([]<typename T>(T&& A) -> T&& { return Forward<T>(A); }),
|
|
CEquivalenceRelation<TInvokeResult<Proj1, TIteratorReference<I1>>, TInvokeResult<Proj2, TIteratorReference<I2>>> Pred =
|
|
TConditional<CWeaklyEqualityComparable<TInvokeResult<Proj1, TIteratorReference<I1>>, TInvokeResult<Proj2, TIteratorReference<I2>>>,
|
|
decltype([]<typename LHS, typename RHS>(const LHS& A, const RHS& B) { return A == B; }), void>>
|
|
NODISCARD FORCEINLINE constexpr bool Contains(I1 HaystackFirst, S1 HaystackLast, I2 NeedleFirst, S2 NeedleLast,
|
|
Pred Predicate = { }, Proj1 HaystackProjection = { }, Proj2 NeedleProjection = { })
|
|
{
|
|
if constexpr (CSizedSentinelFor<S1, I1>)
|
|
{
|
|
checkf(HaystackFirst - HaystackLast <= 0, TEXT("Illegal range iterator. Please check HaystackFirst <= HaystackLast."));
|
|
}
|
|
|
|
if constexpr (CSizedSentinelFor<S2, I2>)
|
|
{
|
|
checkf(NeedleFirst - NeedleLast <= 0, TEXT("Illegal range iterator. Please check NeedleFirst <= NeedleLast."));
|
|
}
|
|
|
|
return Algorithms::Contains(
|
|
Ranges::View(MoveTemp(HaystackFirst), HaystackLast),
|
|
Ranges::View(MoveTemp(NeedleFirst), NeedleLast),
|
|
Ref(Predicate), Ref(HaystackProjection), Ref(NeedleProjection));
|
|
}
|
|
|
|
/**
|
|
* Finds the first element in the range that equals the given value.
|
|
*
|
|
* @param Range - The range to check.
|
|
* @param Value - The value to check.
|
|
* @param Predicate - The equivalence relation predicate between the projected elements and the value.
|
|
* @param Projection - The projection to apply to the elements before checking.
|
|
*
|
|
* @return The iterator to the first element that equals the value, or the end iterator if not found.
|
|
*/
|
|
template <CInputRange R,
|
|
CRegularInvocable<TRangeReference<R>> Proj =
|
|
decltype([]<typename T>(T&& A) -> T&& { return Forward<T>(A); }),
|
|
CReferenceable T = TRemoveCVRef<TInvokeResult<Proj, TRangeReference<R>>>,
|
|
CEquivalenceRelation<TInvokeResult<Proj, TRangeReference<R>>, const T&> Pred =
|
|
TConditional<CWeaklyEqualityComparable<TInvokeResult<Proj, TRangeReference<R>>, const T&>,
|
|
decltype([]<typename LHS, typename RHS>(const LHS& A, const RHS& B) { return A == B; }), void>>
|
|
requires (CBorrowedRange<R>)
|
|
NODISCARD constexpr TRangeIterator<R> Find(R&& Range, const T& Value, Pred Predicate = { }, Proj Projection = { })
|
|
{
|
|
if constexpr (CSizedRange<R&>)
|
|
{
|
|
checkf(Algorithms::Distance(Range) >= 0, TEXT("Illegal range. Please check Algorithms::Distance(Range)."));
|
|
}
|
|
|
|
auto Iter = Ranges::Begin(Range);
|
|
auto Sent = Ranges::End (Range);
|
|
|
|
for (; Iter != Sent; ++Iter)
|
|
{
|
|
if (Invoke(Predicate, Invoke(Projection, *Iter), Value))
|
|
{
|
|
return Iter;
|
|
}
|
|
}
|
|
|
|
return Iter;
|
|
}
|
|
|
|
/**
|
|
* Finds the first element in the range that equals the given value.
|
|
*
|
|
* @param First - The iterator of the range.
|
|
* @param Last - The sentinel of the range.
|
|
* @param Value - The value to check.
|
|
* @param Predicate - The equivalence relation predicate between the projected elements and the value.
|
|
* @param Projection - The projection to apply to the elements before checking.
|
|
*
|
|
* @return The iterator to the first element that equals the value, or the end iterator if not found.
|
|
*/
|
|
template <CInputIterator I, CSentinelFor<I> S,
|
|
CRegularInvocable<TIteratorReference<I>> Proj =
|
|
decltype([]<typename T>(T&& A) -> T&& { return Forward<T>(A); }),
|
|
CReferenceable T = TRemoveCVRef<TInvokeResult<Proj, TIteratorReference<I>>>,
|
|
CEquivalenceRelation<TInvokeResult<Proj, TIteratorReference<I>>, const T&> Pred =
|
|
TConditional<CWeaklyEqualityComparable<TInvokeResult<Proj, TIteratorReference<I>>, const T&>,
|
|
decltype([]<typename LHS, typename RHS>(const LHS& A, const RHS& B) { return A == B; }), void>>
|
|
NODISCARD FORCEINLINE constexpr I Find(I First, S Last, const T& Value, Pred Predicate = { }, Proj Projection = { })
|
|
{
|
|
if constexpr (CSizedSentinelFor<S, I>)
|
|
{
|
|
checkf(First - Last <= 0, TEXT("Illegal range iterator. Please check First <= Last."));
|
|
}
|
|
|
|
return Algorithms::Find(Ranges::View(MoveTemp(First), Last), Value, Ref(Predicate), Ref(Projection));
|
|
}
|
|
|
|
/**
|
|
* Finds the first subrange in the range that equals the given subrange.
|
|
*
|
|
* @param Haystack - The range of elements to examine, aka the haystack.
|
|
* @param Needle - The range of elements to search for, aka the needle.
|
|
* @param Predicate - The equivalence relation predicate between the projected elements.
|
|
* @param HaystackProjection - The projection to apply to the haystack's elements before checking.
|
|
* @param NeedleProjection - The projection to apply to the needle's elements before checking.
|
|
*
|
|
* @return The subrange to the first subrange that equals the value, or the empty subrange if not found.
|
|
*/
|
|
template <CForwardRange R1, CForwardRange R2,
|
|
CRegularInvocable<TRangeReference<R1>> Proj1 =
|
|
decltype([]<typename T>(T&& A) -> T&& { return Forward<T>(A); }),
|
|
CRegularInvocable<TRangeReference<R2>> Proj2 =
|
|
decltype([]<typename T>(T&& A) -> T&& { return Forward<T>(A); }),
|
|
CEquivalenceRelation<TInvokeResult<Proj1, TRangeReference<R1>>, TInvokeResult<Proj2, TRangeReference<R2>>> Pred =
|
|
TConditional<CWeaklyEqualityComparable<TInvokeResult<Proj1, TRangeReference<R1>>, TInvokeResult<Proj2, TRangeReference<R2>>>,
|
|
decltype([]<typename LHS, typename RHS>(const LHS& A, const RHS& B) { return A == B; }), void>>
|
|
requires (CBorrowedRange<R1>)
|
|
NODISCARD constexpr Ranges::TRangeView<TRangeIterator<R1>> Find(R1&& Haystack, R2&& Needle,
|
|
Pred Predicate = { }, Proj1 HaystackProjection = { }, Proj2 NeedleProjection = { })
|
|
{
|
|
if constexpr (CSizedRange<R1&>)
|
|
{
|
|
checkf(Algorithms::Distance(Haystack) >= 0, TEXT("Illegal range. Please check Algorithms::Distance(Haystack)."));
|
|
}
|
|
|
|
if constexpr (CSizedRange<R2&>)
|
|
{
|
|
checkf(Algorithms::Distance(Needle) >= 0, TEXT("Illegal range. Please check Algorithms::Distance(Needle)."));
|
|
}
|
|
|
|
auto FirstA = Ranges::Begin(Haystack);
|
|
auto SentA = Ranges::End (Haystack);
|
|
|
|
auto FirstB = Ranges::Begin(Needle);
|
|
auto SentB = Ranges::End (Needle);
|
|
|
|
while (true)
|
|
{
|
|
auto IterA = FirstA;
|
|
auto IterB = FirstB;
|
|
|
|
while (true)
|
|
{
|
|
if (IterB == SentB) return Ranges::View(FirstA, IterA);
|
|
if (IterA == SentA) return Ranges::View(IterA, IterA);
|
|
|
|
if (!Invoke(Predicate, Invoke(HaystackProjection, *IterA), Invoke(NeedleProjection, *IterB))) break;
|
|
|
|
++IterA;
|
|
++IterB;
|
|
}
|
|
|
|
++FirstA;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Finds the first subrange in the range that equals the given subrange.
|
|
*
|
|
* @param HaystackFirst - The iterator of elements to examine, aka the haystack.
|
|
* @param HaystackLast - The sentinel of elements to examine, aka the haystack.
|
|
* @param NeedleFirst - The iterator of elements to search for, aka the needle.
|
|
* @param NeedleLast - The sentinel of elements to search for, aka the needle.
|
|
* @param Predicate - The equivalence relation predicate between the projected elements.
|
|
* @param HaystackProjection - The projection to apply to the haystack's elements before checking.
|
|
* @param NeedleProjection - The projection to apply to the needle's elements before checking.
|
|
*
|
|
* @return The subrange to the first subrange that equals the value, or the empty subrange if not found.
|
|
*/
|
|
template <CForwardIterator I1, CSentinelFor<I1> S1, CForwardIterator I2, CSentinelFor<I2> S2,
|
|
CRegularInvocable<TIteratorReference<I1>> Proj1 =
|
|
decltype([]<typename T>(T&& A) -> T&& { return Forward<T>(A); }),
|
|
CRegularInvocable<TIteratorReference<I2>> Proj2 =
|
|
decltype([]<typename T>(T&& A) -> T&& { return Forward<T>(A); }),
|
|
CEquivalenceRelation<TInvokeResult<Proj1, TIteratorReference<I1>>, TInvokeResult<Proj2, TIteratorReference<I2>>> Pred =
|
|
TConditional<CWeaklyEqualityComparable<TInvokeResult<Proj1, TIteratorReference<I1>>, TInvokeResult<Proj2, TIteratorReference<I2>>>,
|
|
decltype([]<typename LHS, typename RHS>(const LHS& A, const RHS& B) { return A == B; }), void>>
|
|
NODISCARD FORCEINLINE constexpr Ranges::TRangeView<I1> Find(I1 HaystackFirst, S1 HaystackLast, I2 NeedleFirst, S2 NeedleLast,
|
|
Pred Predicate = { }, Proj1 HaystackProjection = { }, Proj2 NeedleProjection = { })
|
|
{
|
|
if constexpr (CSizedSentinelFor<S1, I1>)
|
|
{
|
|
checkf(HaystackFirst - HaystackLast <= 0, TEXT("Illegal range iterator. Please check HaystackFirst <= HaystackLast."));
|
|
}
|
|
|
|
if constexpr (CSizedSentinelFor<S2, I2>)
|
|
{
|
|
checkf(NeedleFirst - NeedleLast <= 0, TEXT("Illegal range iterator. Please check NeedleFirst <= NeedleLast."));
|
|
}
|
|
|
|
return Algorithms::Find(
|
|
Ranges::View(MoveTemp(HaystackFirst), HaystackLast),
|
|
Ranges::View(MoveTemp(NeedleFirst), NeedleLast),
|
|
Ref(Predicate), Ref(HaystackProjection), Ref(NeedleProjection));
|
|
}
|
|
|
|
/**
|
|
* Finds the first element in the range that satisfies the predicate.
|
|
*
|
|
* @param Range - The range to check.
|
|
* @param Predicate - The unary predicate to satisfy.
|
|
* @param Projection - The projection to apply to the elements before checking.
|
|
*
|
|
* @return The iterator to the first element that satisfies the predicate, or the end iterator if not found.
|
|
*/
|
|
template <CInputRange R,
|
|
CRegularInvocable<TRangeReference<R>> Proj =
|
|
decltype([]<typename T>(T&& A) -> T&& { return Forward<T>(A); }),
|
|
CPredicate<TInvokeResult<Proj, TRangeReference<R>>> Pred>
|
|
requires (CBorrowedRange<R>)
|
|
NODISCARD constexpr TRangeIterator<R> FindIf(R&& Range, Pred Predicate, Proj Projection = { })
|
|
{
|
|
if constexpr (CSizedRange<R&>)
|
|
{
|
|
checkf(Algorithms::Distance(Range) >= 0, TEXT("Illegal range. Please check Algorithms::Distance(Range)."));
|
|
}
|
|
|
|
auto Iter = Ranges::Begin(Range);
|
|
auto Sent = Ranges::End (Range);
|
|
|
|
for (; Iter != Sent; ++Iter)
|
|
{
|
|
if (Invoke(Predicate, Invoke(Projection, *Iter)))
|
|
{
|
|
return Iter;
|
|
}
|
|
}
|
|
|
|
return Iter;
|
|
}
|
|
|
|
/**
|
|
* Finds the first element in the range that satisfies the predicate.
|
|
*
|
|
* @param First - The iterator of the range.
|
|
* @param Last - The sentinel of the range.
|
|
* @param Predicate - The unary predicate to satisfy.
|
|
* @param Projection - The projection to apply to the elements before checking.
|
|
*
|
|
* @return The iterator to the first element that satisfies the predicate, or the end iterator if not found.
|
|
*/
|
|
template <CInputIterator I, CSentinelFor<I> S,
|
|
CRegularInvocable<TIteratorReference<I>> Proj =
|
|
decltype([]<typename T>(T&& A) -> T&& { return Forward<T>(A); }),
|
|
CPredicate<TInvokeResult<Proj, TIteratorReference<I>>> Pred>
|
|
NODISCARD FORCEINLINE constexpr I FindIf(I First, S Last, Pred Predicate, Proj Projection = { })
|
|
{
|
|
if constexpr (CSizedSentinelFor<S, I>)
|
|
{
|
|
checkf(First - Last <= 0, TEXT("Illegal range iterator. Please check First <= Last."));
|
|
}
|
|
|
|
return Algorithms::FindIf(Ranges::View(MoveTemp(First), Last), Ref(Predicate), Ref(Projection));
|
|
}
|
|
|
|
/**
|
|
* Finds the first element in the range that does not satisfy the predicate.
|
|
*
|
|
* @param Range - The range to check.
|
|
* @param Predicate - The unary predicate to satisfy.
|
|
* @param Projection - The projection to apply to the elements before checking.
|
|
*
|
|
* @return The iterator to the first element that does not satisfy the predicate, or the end iterator if not found.
|
|
*/
|
|
template <CInputRange R,
|
|
CRegularInvocable<TRangeReference<R>> Proj =
|
|
decltype([]<typename T>(T&& A) -> T&& { return Forward<T>(A); }),
|
|
CPredicate<TInvokeResult<Proj, TRangeReference<R>>> Pred>
|
|
requires (CBorrowedRange<R>)
|
|
NODISCARD FORCEINLINE constexpr TRangeIterator<R> FindIfNot(R&& Range, Pred Predicate, Proj Projection = { })
|
|
{
|
|
if constexpr (CSizedRange<R&>)
|
|
{
|
|
checkf(Algorithms::Distance(Range) >= 0, TEXT("Illegal range. Please check Algorithms::Distance(Range)."));
|
|
}
|
|
|
|
auto NotPredicate = [&Predicate]<typename T>(T&& A) { return !Invoke(Predicate, Forward<T>(A)); };
|
|
|
|
return Algorithms::FindIf(Forward<R>(Range), NotPredicate, Ref(Projection));
|
|
}
|
|
|
|
/**
|
|
* Finds the first element in the range that does not satisfy the predicate.
|
|
*
|
|
* @param First - The iterator of the range.
|
|
* @param Last - The sentinel of the range.
|
|
* @param Predicate - The unary predicate to satisfy.
|
|
* @param Projection - The projection to apply to the elements before checking.
|
|
*
|
|
* @return The iterator to the first element that does not satisfy the predicate, or the end iterator if not found.
|
|
*/
|
|
template <CInputIterator I, CSentinelFor<I> S,
|
|
CRegularInvocable<TIteratorReference<I>> Proj =
|
|
decltype([]<typename T>(T&& A) -> T&& { return Forward<T>(A); }),
|
|
CPredicate<TInvokeResult<Proj, TIteratorReference<I>>> Pred>
|
|
NODISCARD FORCEINLINE constexpr I FindIfNot(I First, S Last, Pred Predicate, Proj Projection = { })
|
|
{
|
|
if constexpr (CSizedSentinelFor<S, I>)
|
|
{
|
|
checkf(First - Last <= 0, TEXT("Illegal range iterator. Please check First <= Last."));
|
|
}
|
|
|
|
return Algorithms::FindIfNot(Ranges::View(MoveTemp(First), Last), Ref(Predicate), Ref(Projection));
|
|
}
|
|
|
|
/**
|
|
* Finds the last element in the range that equals the given value.
|
|
*
|
|
* @param Range - The range to check.
|
|
* @param Value - The value to check.
|
|
* @param Predicate - The equivalence relation predicate between the projected elements and the value.
|
|
* @param Projection - The projection to apply to the elements before checking.
|
|
*
|
|
* @return The iterator to the last element that equals the value, or the end iterator if not found.
|
|
*/
|
|
template <CForwardRange R,
|
|
CRegularInvocable<TRangeReference<R>> Proj =
|
|
decltype([]<typename T>(T&& A) -> T&& { return Forward<T>(A); }),
|
|
CReferenceable T = TRemoveCVRef<TInvokeResult<Proj, TRangeReference<R>>>,
|
|
CEquivalenceRelation<TInvokeResult<Proj, TRangeReference<R>>, const T&> Pred =
|
|
TConditional<CWeaklyEqualityComparable<TInvokeResult<Proj, TRangeReference<R>>, const T&>,
|
|
decltype([]<typename LHS, typename RHS>(const LHS& A, const RHS& B) { return A == B; }), void>>
|
|
requires (CBorrowedRange<R>)
|
|
NODISCARD constexpr TRangeIterator<R> FindLast(R&& Range, const T& Value, Pred Predicate = { }, Proj Projection = { })
|
|
{
|
|
if constexpr (CSizedRange<R&>)
|
|
{
|
|
checkf(Algorithms::Distance(Range) >= 0, TEXT("Illegal range. Please check Algorithms::Distance(Range)."));
|
|
}
|
|
|
|
auto Iter = Ranges::Begin(Range);
|
|
auto Sent = Ranges::End (Range);
|
|
|
|
if constexpr (CBidirectionalRange<R&> && CCommonRange<R&>)
|
|
{
|
|
auto RIter = MakeReverseIterator(Sent);
|
|
auto RSent = MakeReverseIterator(Iter);
|
|
|
|
for (; RIter != RSent; ++RIter)
|
|
{
|
|
if (Invoke(Predicate, Invoke(Projection, *RIter), Value))
|
|
{
|
|
return Algorithms::Prev(RIter.GetBase());
|
|
}
|
|
}
|
|
|
|
return Sent;
|
|
}
|
|
|
|
else if constexpr (CRandomAccessRange<R&> && CSizedRange<R&>)
|
|
{
|
|
const size_t Count = Ranges::Num(Range);
|
|
|
|
auto RIter = MakeReverseIterator(Iter + Count);
|
|
auto RSent = MakeReverseIterator(Iter);
|
|
|
|
for (; RIter != RSent; ++RIter)
|
|
{
|
|
if (Invoke(Predicate, Invoke(Projection, *RIter), Value))
|
|
{
|
|
return Algorithms::Prev(RIter.GetBase());
|
|
}
|
|
}
|
|
|
|
return Iter + Count;
|
|
}
|
|
|
|
else
|
|
{
|
|
TOptional<TRangeIterator<R>> Result;
|
|
|
|
for (; Iter != Sent; ++Iter)
|
|
{
|
|
if (Invoke(Predicate, Invoke(Projection, *Iter), Value))
|
|
{
|
|
Result = Iter;
|
|
}
|
|
}
|
|
|
|
if (!Result) return Iter;
|
|
|
|
return *Result;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Finds the last element in the range that equals the given value.
|
|
*
|
|
* @param First - The iterator of the range.
|
|
* @param Last - The sentinel of the range.
|
|
* @param Value - The value to check.
|
|
* @param Predicate - The equivalence relation predicate between the projected elements and the value.
|
|
* @param Projection - The projection to apply to the elements before checking.
|
|
*
|
|
* @return The iterator to the last element that equals the value, or the end iterator if not found.
|
|
*/
|
|
template <CForwardIterator I, CSentinelFor<I> S,
|
|
CRegularInvocable<TIteratorReference<I>> Proj =
|
|
decltype([]<typename T>(T&& A) -> T&& { return Forward<T>(A); }),
|
|
CReferenceable T = TRemoveCVRef<TInvokeResult<Proj, TIteratorReference<I>>>,
|
|
CEquivalenceRelation<TInvokeResult<Proj, TIteratorReference<I>>, const T&> Pred =
|
|
TConditional<CWeaklyEqualityComparable<TInvokeResult<Proj, TIteratorReference<I>>, const T&>,
|
|
decltype([]<typename LHS, typename RHS>(const LHS& A, const RHS& B) { return A == B; }), void>>
|
|
NODISCARD FORCEINLINE constexpr I FindLast(I First, S Last, const T& Value, Pred Predicate = { }, Proj Projection = { })
|
|
{
|
|
if constexpr (CSizedSentinelFor<S, I>)
|
|
{
|
|
checkf(First - Last <= 0, TEXT("Illegal range iterator. Please check First <= Last."));
|
|
}
|
|
|
|
return Algorithms::FindLast(Ranges::View(MoveTemp(First), Last), Value, Ref(Predicate), Ref(Projection));
|
|
}
|
|
|
|
/**
|
|
* Finds the last subrange in the range that equals the given subrange.
|
|
*
|
|
* @param Haystack - The range of elements to examine, aka the haystack.
|
|
* @param Needle - The range of elements to search for, aka the needle.
|
|
* @param Predicate - The equivalence relation predicate between the projected elements.
|
|
* @param HaystackProjection - The projection to apply to the haystack's elements before checking.
|
|
* @param NeedleProjection - The projection to apply to the needle's elements before checking.
|
|
*
|
|
* @return The subrange to the last subrange that equals the value, or the empty subrange if not found.
|
|
*/
|
|
template <CForwardRange R1, CForwardRange R2,
|
|
CRegularInvocable<TRangeReference<R1>> Proj1 =
|
|
decltype([]<typename T>(T&& A) -> T&& { return Forward<T>(A); }),
|
|
CRegularInvocable<TRangeReference<R2>> Proj2 =
|
|
decltype([]<typename T>(T&& A) -> T&& { return Forward<T>(A); }),
|
|
CEquivalenceRelation<TInvokeResult<Proj1, TRangeReference<R1>>, TInvokeResult<Proj2, TRangeReference<R2>>> Pred =
|
|
TConditional<CWeaklyEqualityComparable<TInvokeResult<Proj1, TRangeReference<R1>>, TInvokeResult<Proj2, TRangeReference<R2>>>,
|
|
decltype([]<typename LHS, typename RHS>(const LHS& A, const RHS& B) { return A == B; }), void>>
|
|
requires (CBorrowedRange<R1>)
|
|
NODISCARD constexpr Ranges::TRangeView<TRangeIterator<R1>> FindLast(R1&& Haystack, R2&& Needle,
|
|
Pred Predicate = { }, Proj1 HaystackProjection = { }, Proj2 NeedleProjection = { })
|
|
{
|
|
if constexpr (CSizedRange<R1&>)
|
|
{
|
|
checkf(Algorithms::Distance(Haystack) >= 0, TEXT("Illegal range. Please check Algorithms::Distance(Haystack)."));
|
|
}
|
|
|
|
if constexpr (CSizedRange<R2&>)
|
|
{
|
|
checkf(Algorithms::Distance(Needle) >= 0, TEXT("Illegal range. Please check Algorithms::Distance(Needle)."));
|
|
}
|
|
|
|
auto FirstA = Ranges::Begin(Haystack);
|
|
auto SentA = Ranges::End (Haystack);
|
|
|
|
auto FirstB = Ranges::Begin(Needle);
|
|
auto SentB = Ranges::End (Needle);
|
|
|
|
if (FirstB == SentB)
|
|
{
|
|
auto LastA = Algorithms::Next(FirstA, SentA);
|
|
|
|
return Ranges::View(LastA, LastA);
|
|
}
|
|
|
|
if constexpr (CBidirectionalRange<R1&> && CCommonRange<R1&>)
|
|
{
|
|
const ptrdiff NeedleCount = Algorithms::Distance(FirstB, SentB);
|
|
|
|
auto Iter = SentA;
|
|
|
|
if (Algorithms::Advance(Iter, -NeedleCount, FirstA) != 0) return Ranges::View(SentA, SentA);
|
|
|
|
for (; Iter != FirstA; --Iter)
|
|
{
|
|
auto IterA = Algorithms::Prev(Iter);
|
|
auto IterB = FirstB;
|
|
|
|
while (true)
|
|
{
|
|
if (IterB == SentB) return Ranges::View(Algorithms::Prev(Iter), IterA);
|
|
|
|
if (!Invoke(Predicate, Invoke(HaystackProjection, *IterA), Invoke(NeedleProjection, *IterB))) break;
|
|
|
|
++IterA;
|
|
++IterB;
|
|
}
|
|
}
|
|
|
|
return Ranges::View(SentA, SentA);
|
|
}
|
|
|
|
else
|
|
{
|
|
auto Result = Algorithms::Find(FirstA, SentA, FirstB, SentB,
|
|
Ref(Predicate), Ref(HaystackProjection), Ref(NeedleProjection));
|
|
|
|
if (Result.IsEmpty()) return Result;
|
|
|
|
while (true)
|
|
{
|
|
auto Next = Algorithms::Find(Algorithms::Next(Result.Begin()), SentA, FirstB, SentB,
|
|
Ref(Predicate), Ref(HaystackProjection), Ref(NeedleProjection));
|
|
|
|
if (Next.IsEmpty()) return Result;
|
|
|
|
Result = Next;
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Finds the last subrange in the range that equals the given subrange.
|
|
*
|
|
* @param HaystackFirst - The iterator of elements to examine, aka the haystack.
|
|
* @param HaystackLast - The sentinel of elements to examine, aka the haystack.
|
|
* @param NeedleFirst - The iterator of elements to search for, aka the needle.
|
|
* @param NeedleLast - The sentinel of elements to search for, aka the needle.
|
|
* @param Predicate - The equivalence relation predicate between the projected elements.
|
|
* @param HaystackProjection - The projection to apply to the haystack's elements before checking.
|
|
* @param NeedleProjection - The projection to apply to the needle's elements before checking.
|
|
*
|
|
* @return The subrange to the last subrange that equals the value, or the empty subrange if not found.
|
|
*/
|
|
template <CForwardIterator I1, CSentinelFor<I1> S1, CForwardIterator I2, CSentinelFor<I2> S2,
|
|
CRegularInvocable<TIteratorReference<I1>> Proj1 =
|
|
decltype([]<typename T>(T&& A) -> T&& { return Forward<T>(A); }),
|
|
CRegularInvocable<TIteratorReference<I2>> Proj2 =
|
|
decltype([]<typename T>(T&& A) -> T&& { return Forward<T>(A); }),
|
|
CEquivalenceRelation<TInvokeResult<Proj1, TIteratorReference<I1>>, TInvokeResult<Proj2, TIteratorReference<I2>>> Pred =
|
|
TConditional<CWeaklyEqualityComparable<TInvokeResult<Proj1, TIteratorReference<I1>>, TInvokeResult<Proj2, TIteratorReference<I2>>>,
|
|
decltype([]<typename LHS, typename RHS>(const LHS& A, const RHS& B) { return A == B; }), void>>
|
|
NODISCARD FORCEINLINE constexpr Ranges::TRangeView<I1> FindLast(I1 HaystackFirst, S1 HaystackLast, I2 NeedleFirst, S2 NeedleLast,
|
|
Pred Predicate = { }, Proj1 HaystackProjection = { }, Proj2 NeedleProjection = { })
|
|
{
|
|
if constexpr (CSizedSentinelFor<S1, I1>)
|
|
{
|
|
checkf(HaystackFirst - HaystackLast <= 0, TEXT("Illegal range iterator. Please check HaystackFirst <= HaystackLast."));
|
|
}
|
|
|
|
if constexpr (CSizedSentinelFor<S2, I2>)
|
|
{
|
|
checkf(NeedleFirst - NeedleLast <= 0, TEXT("Illegal range iterator. Please check NeedleFirst <= NeedleLast."));
|
|
}
|
|
|
|
return Algorithms::FindLast(
|
|
Ranges::View(MoveTemp(HaystackFirst), HaystackLast),
|
|
Ranges::View(MoveTemp(NeedleFirst), NeedleLast),
|
|
Ref(Predicate), Ref(HaystackProjection), Ref(NeedleProjection));
|
|
}
|
|
|
|
/**
|
|
* Finds the last element in the range that satisfies the predicate.
|
|
*
|
|
* @param Range - The range to check.
|
|
* @param Predicate - The unary predicate to satisfy.
|
|
* @param Projection - The projection to apply to the elements before checking.
|
|
*
|
|
* @return The iterator to the last element that satisfies the predicate, or the end iterator if not found.
|
|
*/
|
|
template <CForwardRange R,
|
|
CRegularInvocable<TRangeReference<R>> Proj =
|
|
decltype([]<typename T>(T&& A) -> T&& { return Forward<T>(A); }),
|
|
CPredicate<TInvokeResult<Proj, TRangeReference<R>>> Pred>
|
|
requires (CBorrowedRange<R>)
|
|
NODISCARD constexpr TRangeIterator<R> FindLastIf(R&& Range, Pred Predicate, Proj Projection = { })
|
|
{
|
|
if constexpr (CSizedRange<R&>)
|
|
{
|
|
checkf(Algorithms::Distance(Range) >= 0, TEXT("Illegal range. Please check Algorithms::Distance(Range)."));
|
|
}
|
|
|
|
auto Iter = Ranges::Begin(Range);
|
|
auto Sent = Ranges::End (Range);
|
|
|
|
if constexpr (CBidirectionalRange<R&> && CCommonRange<R&>)
|
|
{
|
|
auto RIter = MakeReverseIterator(Sent);
|
|
auto RSent = MakeReverseIterator(Iter);
|
|
|
|
for (; RIter != RSent; ++RIter)
|
|
{
|
|
if (Invoke(Predicate, Invoke(Projection, *RIter)))
|
|
{
|
|
return Algorithms::Prev(RIter.GetBase());
|
|
}
|
|
}
|
|
|
|
return Sent;
|
|
}
|
|
|
|
else if constexpr (CRandomAccessRange<R&> && CSizedRange<R&>)
|
|
{
|
|
const size_t Count = Ranges::Num(Range);
|
|
|
|
auto RIter = MakeReverseIterator(Iter + Count);
|
|
auto RSent = MakeReverseIterator(Iter);
|
|
|
|
for (; RIter != RSent; ++RIter)
|
|
{
|
|
if (Invoke(Predicate, Invoke(Projection, *RIter)))
|
|
{
|
|
return Algorithms::Prev(RIter.GetBase());
|
|
}
|
|
}
|
|
|
|
return Iter + Count;
|
|
}
|
|
|
|
else
|
|
{
|
|
TOptional<TRangeIterator<R>> Result;
|
|
|
|
for (; Iter != Sent; ++Iter)
|
|
{
|
|
if (Invoke(Predicate, Invoke(Projection, *Iter)))
|
|
{
|
|
Result = Iter;
|
|
}
|
|
}
|
|
|
|
if (!Result) return Iter;
|
|
|
|
return *Result;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Finds the last element in the range that satisfies the predicate.
|
|
*
|
|
* @param First - The iterator of the range.
|
|
* @param Last - The sentinel of the range.
|
|
* @param Predicate - The unary predicate to satisfy.
|
|
* @param Projection - The projection to apply to the elements before checking.
|
|
*
|
|
* @return The iterator to the last element that satisfies the predicate, or the end iterator if not found.
|
|
*/
|
|
template <CForwardIterator I, CSentinelFor<I> S,
|
|
CRegularInvocable<TIteratorReference<I>> Proj =
|
|
decltype([]<typename T>(T&& A) -> T&& { return Forward<T>(A); }),
|
|
CPredicate<TInvokeResult<Proj, TIteratorReference<I>>> Pred>
|
|
NODISCARD FORCEINLINE constexpr I FindLastIf(I First, S Last, Pred Predicate, Proj Projection = { })
|
|
{
|
|
if constexpr (CSizedSentinelFor<S, I>)
|
|
{
|
|
checkf(First - Last <= 0, TEXT("Illegal range iterator. Please check First <= Last."));
|
|
}
|
|
|
|
return Algorithms::FindLastIf(Ranges::View(MoveTemp(First), Last), Ref(Predicate), Ref(Projection));
|
|
}
|
|
|
|
/**
|
|
* Finds the last element in the range that does not satisfy the predicate.
|
|
*
|
|
* @param Range - The range to check.
|
|
* @param Predicate - The unary predicate to satisfy.
|
|
* @param Projection - The projection to apply to the elements before checking.
|
|
*
|
|
* @return The iterator to the last element that does not satisfy the predicate, or the end iterator if not found.
|
|
*/
|
|
template <CForwardRange R,
|
|
CRegularInvocable<TRangeReference<R>> Proj =
|
|
decltype([]<typename T>(T&& A) -> T&& { return Forward<T>(A); }),
|
|
CPredicate<TInvokeResult<Proj, TRangeReference<R>>> Pred>
|
|
requires (CBorrowedRange<R>)
|
|
NODISCARD constexpr TRangeIterator<R> FindLastIfNot(R&& Range, Pred Predicate, Proj Projection = { })
|
|
{
|
|
if constexpr (CSizedRange<R&>)
|
|
{
|
|
checkf(Algorithms::Distance(Range) >= 0, TEXT("Illegal range. Please check Algorithms::Distance(Range)."));
|
|
}
|
|
|
|
auto NotPredicate = [&Predicate]<typename T>(T&& A) { return !Invoke(Predicate, Forward<T>(A)); };
|
|
|
|
return Algorithms::FindLastIf(Forward<R>(Range), NotPredicate, Ref(Projection));
|
|
}
|
|
|
|
/**
|
|
* Finds the last element in the range that does not satisfy the predicate.
|
|
*
|
|
* @param First - The iterator of the range.
|
|
* @param Last - The sentinel of the range.
|
|
* @param Predicate - The unary predicate to satisfy.
|
|
* @param Projection - The projection to apply to the elements before checking.
|
|
*
|
|
* @return The iterator to the last element that does not satisfy the predicate, or the end iterator if not found.
|
|
*/
|
|
template <CForwardIterator I, CSentinelFor<I> S,
|
|
CRegularInvocable<TIteratorReference<I>> Proj =
|
|
decltype([]<typename T>(T&& A) -> T&& { return Forward<T>(A); }),
|
|
CPredicate<TInvokeResult<Proj, TIteratorReference<I>>> Pred>
|
|
NODISCARD FORCEINLINE constexpr I FindLastIfNot(I First, S Last, Pred Predicate, Proj Projection = { })
|
|
{
|
|
if constexpr (CSizedSentinelFor<S, I>)
|
|
{
|
|
checkf(First - Last <= 0, TEXT("Illegal range iterator. Please check First <= Last."));
|
|
}
|
|
|
|
return Algorithms::FindLastIfNot(Ranges::View(MoveTemp(First), Last), Ref(Predicate), Ref(Projection));
|
|
}
|
|
|
|
/**
|
|
* Finds the first element in the range that also contained in another range.
|
|
*
|
|
* @param Haystack - The range of elements to examine, aka the haystack.
|
|
* @param Needle - The range of elements to search for, aka the needle.
|
|
* @param Predicate - The equivalence relation predicate between the projected elements.
|
|
* @param HaystackProjection - The projection to apply to the haystack's elements before checking.
|
|
* @param NeedleProjection - The projection to apply to the needle's elements before checking.
|
|
*
|
|
* @return The iterator to the first element that also contained in the needle, or the end iterator if not found.
|
|
*/
|
|
template <CInputRange R1, CForwardRange R2,
|
|
CRegularInvocable<TRangeReference<R1>> Proj1 =
|
|
decltype([]<typename T>(T&& A) -> T&& { return Forward<T>(A); }),
|
|
CRegularInvocable<TRangeReference<R2>> Proj2 =
|
|
decltype([]<typename T>(T&& A) -> T&& { return Forward<T>(A); }),
|
|
CEquivalenceRelation<TInvokeResult<Proj1, TRangeReference<R1>>, TInvokeResult<Proj2, TRangeReference<R2>>> Pred =
|
|
TConditional<CWeaklyEqualityComparable<TInvokeResult<Proj1, TRangeReference<R1>>, TInvokeResult<Proj2, TRangeReference<R2>>>,
|
|
decltype([]<typename LHS, typename RHS>(const LHS& A, const RHS& B) { return A == B; }), void>>
|
|
requires (CBorrowedRange<R1>)
|
|
NODISCARD FORCEINLINE constexpr TRangeIterator<R1> FindFirstOf(R1&& Haystack, R2&& Needle,
|
|
Pred Predicate = { }, Proj1 HaystackProjection = { }, Proj2 NeedleProjection = { })
|
|
{
|
|
if constexpr (CSizedRange<R1&>)
|
|
{
|
|
checkf(Algorithms::Distance(Haystack) >= 0, TEXT("Illegal range. Please check Algorithms::Distance(Haystack)."));
|
|
}
|
|
|
|
if constexpr (CSizedRange<R2&>)
|
|
{
|
|
checkf(Algorithms::Distance(Needle) >= 0, TEXT("Illegal range. Please check Algorithms::Distance(Needle)."));
|
|
}
|
|
|
|
auto ContainsInNeedle = [&]<typename LHS>(LHS&& A)
|
|
{
|
|
auto ForwardPredicate = [&]<typename RHS>(RHS&& B)
|
|
{
|
|
return Invoke(Predicate, Forward<LHS>(A), Forward<RHS>(B));
|
|
};
|
|
|
|
return Algorithms::FindIf(Needle, ForwardPredicate, Ref(NeedleProjection)) != Ranges::End(Needle);
|
|
};
|
|
|
|
return Algorithms::FindIf(Forward<R1>(Haystack), ContainsInNeedle, Ref(HaystackProjection));
|
|
}
|
|
|
|
/**
|
|
* Finds the first element in the range that also contained in another range.
|
|
*
|
|
* @param HaystackFirst - The iterator of elements to examine, aka the haystack.
|
|
* @param HaystackLast - The sentinel of elements to examine, aka the haystack.
|
|
* @param NeedleFirst - The iterator of elements to search for, aka the needle.
|
|
* @param NeedleLast - The sentinel of elements to search for, aka the needle.
|
|
* @param Predicate - The equivalence relation predicate between the projected elements.
|
|
* @param HaystackProjection - The projection to apply to the haystack's elements before checking.
|
|
* @param NeedleProjection - The projection to apply to the needle's elements before checking.
|
|
*
|
|
* @return The iterator to the first element that also contained in the needle, or the end iterator if not found.
|
|
*/
|
|
template <CInputIterator I1, CSentinelFor<I1> S1, CForwardIterator I2, CSentinelFor<I2> S2,
|
|
CRegularInvocable<TIteratorReference<I1>> Proj1 =
|
|
decltype([]<typename T>(T&& A) -> T&& { return Forward<T>(A); }),
|
|
CRegularInvocable<TIteratorReference<I2>> Proj2 =
|
|
decltype([]<typename T>(T&& A) -> T&& { return Forward<T>(A); }),
|
|
CEquivalenceRelation<TInvokeResult<Proj1, TIteratorReference<I1>>, TInvokeResult<Proj2, TIteratorReference<I2>>> Pred =
|
|
TConditional<CWeaklyEqualityComparable<TInvokeResult<Proj1, TIteratorReference<I1>>, TInvokeResult<Proj2, TIteratorReference<I2>>>,
|
|
decltype([]<typename LHS, typename RHS>(const LHS& A, const RHS& B) { return A == B; }), void>>
|
|
NODISCARD FORCEINLINE constexpr I1 FindFirstOf(I1 HaystackFirst, S1 HaystackLast, I2 NeedleFirst, S2 NeedleLast,
|
|
Pred Predicate = { }, Proj1 HaystackProjection = { }, Proj2 NeedleProjection = { })
|
|
{
|
|
if constexpr (CSizedSentinelFor<S1, I1>)
|
|
{
|
|
checkf(HaystackFirst - HaystackLast <= 0, TEXT("Illegal range iterator. Please check HaystackFirst <= HaystackLast."));
|
|
}
|
|
|
|
if constexpr (CSizedSentinelFor<S2, I2>)
|
|
{
|
|
checkf(NeedleFirst - NeedleLast <= 0, TEXT("Illegal range iterator. Please check NeedleFirst <= NeedleLast."));
|
|
}
|
|
|
|
return Algorithms::FindFirstOf(
|
|
Ranges::View(MoveTemp(HaystackFirst), HaystackLast),
|
|
Ranges::View(MoveTemp(NeedleFirst), NeedleLast),
|
|
Ref(Predicate), Ref(HaystackProjection), Ref(NeedleProjection));
|
|
}
|
|
|
|
/**
|
|
* Finds the last element in the range that also contained in another range.
|
|
*
|
|
* @param Haystack - The range of elements to examine, aka the haystack.
|
|
* @param Needle - The range of elements to search for, aka the needle.
|
|
* @param Predicate - The equivalence relation predicate between the projected elements.
|
|
* @param HaystackProjection - The projection to apply to the haystack's elements before checking.
|
|
* @param NeedleProjection - The projection to apply to the needle's elements before checking.
|
|
*
|
|
* @return The iterator to the last element that also contained in the needle, or the end iterator if not found.
|
|
*/
|
|
template <CForwardRange R1, CForwardRange R2,
|
|
CRegularInvocable<TRangeReference<R1>> Proj1 =
|
|
decltype([]<typename T>(T&& A) -> T&& { return Forward<T>(A); }),
|
|
CRegularInvocable<TRangeReference<R2>> Proj2 =
|
|
decltype([]<typename T>(T&& A) -> T&& { return Forward<T>(A); }),
|
|
CEquivalenceRelation<TInvokeResult<Proj1, TRangeReference<R1>>, TInvokeResult<Proj2, TRangeReference<R2>>> Pred =
|
|
TConditional<CWeaklyEqualityComparable<TInvokeResult<Proj1, TRangeReference<R1>>, TInvokeResult<Proj2, TRangeReference<R2>>>,
|
|
decltype([]<typename LHS, typename RHS>(const LHS& A, const RHS& B) { return A == B; }), void>>
|
|
requires (CBorrowedRange<R1>)
|
|
NODISCARD FORCEINLINE constexpr TRangeIterator<R1> FindLastOf(R1&& Haystack, R2&& Needle,
|
|
Pred Predicate = { }, Proj1 HaystackProjection = { }, Proj2 NeedleProjection = { })
|
|
{
|
|
if constexpr (CSizedRange<R1&>)
|
|
{
|
|
checkf(Algorithms::Distance(Haystack) >= 0, TEXT("Illegal range. Please check Algorithms::Distance(Haystack)."));
|
|
}
|
|
|
|
if constexpr (CSizedRange<R2&>)
|
|
{
|
|
checkf(Algorithms::Distance(Needle) >= 0, TEXT("Illegal range. Please check Algorithms::Distance(Needle)."));
|
|
}
|
|
|
|
auto ContainsInNeedle = [&]<typename LHS>(LHS&& A)
|
|
{
|
|
auto ForwardPredicate = [&]<typename RHS>(RHS&& B)
|
|
{
|
|
return Invoke(Predicate, Forward<LHS>(A), Forward<RHS>(B));
|
|
};
|
|
|
|
return Algorithms::FindIf(Needle, ForwardPredicate, Ref(NeedleProjection)) != Ranges::End(Needle);
|
|
};
|
|
|
|
return Algorithms::FindLastIf(Forward<R1>(Haystack), ContainsInNeedle, Ref(HaystackProjection));
|
|
}
|
|
|
|
/**
|
|
* Finds the last element in the range that also contained in another range.
|
|
*
|
|
* @param HaystackFirst - The iterator of elements to examine, aka the haystack.
|
|
* @param HaystackLast - The sentinel of elements to examine, aka the haystack.
|
|
* @param NeedleFirst - The iterator of elements to search for, aka the needle.
|
|
* @param NeedleLast - The sentinel of elements to search for, aka the needle.
|
|
* @param Predicate - The equivalence relation predicate between the projected elements.
|
|
* @param HaystackProjection - The projection to apply to the haystack's elements before checking.
|
|
* @param NeedleProjection - The projection to apply to the needle's elements before checking.
|
|
*
|
|
* @return The iterator to the last element that also contained in the needle, or the end iterator if not found.
|
|
*/
|
|
template <CForwardIterator I1, CSentinelFor<I1> S1, CForwardIterator I2, CSentinelFor<I2> S2,
|
|
CRegularInvocable<TIteratorReference<I1>> Proj1 =
|
|
decltype([]<typename T>(T&& A) -> T&& { return Forward<T>(A); }),
|
|
CRegularInvocable<TIteratorReference<I2>> Proj2 =
|
|
decltype([]<typename T>(T&& A) -> T&& { return Forward<T>(A); }),
|
|
CEquivalenceRelation<TInvokeResult<Proj1, TIteratorReference<I1>>, TInvokeResult<Proj2, TIteratorReference<I2>>> Pred =
|
|
TConditional<CWeaklyEqualityComparable<TInvokeResult<Proj1, TIteratorReference<I1>>, TInvokeResult<Proj2, TIteratorReference<I2>>>,
|
|
decltype([]<typename LHS, typename RHS>(const LHS& A, const RHS& B) { return A == B; }), void>>
|
|
NODISCARD FORCEINLINE constexpr I1 FindLastOf(I1 HaystackFirst, S1 HaystackLast, I2 NeedleFirst, S2 NeedleLast,
|
|
Pred Predicate = { }, Proj1 HaystackProjection = { }, Proj2 NeedleProjection = { })
|
|
{
|
|
if constexpr (CSizedSentinelFor<S1, I1>)
|
|
{
|
|
checkf(HaystackFirst - HaystackLast <= 0, TEXT("Illegal range iterator. Please check HaystackFirst <= HaystackLast."));
|
|
}
|
|
|
|
if constexpr (CSizedSentinelFor<S2, I2>)
|
|
{
|
|
checkf(NeedleFirst - NeedleLast <= 0, TEXT("Illegal range iterator. Please check NeedleFirst <= NeedleLast."));
|
|
}
|
|
|
|
return Algorithms::FindLastOf(
|
|
Ranges::View(MoveTemp(HaystackFirst), HaystackLast),
|
|
Ranges::View(MoveTemp(NeedleFirst), NeedleLast),
|
|
Ref(Predicate), Ref(HaystackProjection), Ref(NeedleProjection));
|
|
}
|
|
|
|
/**
|
|
* Finds the first pair of equal adjacent elements in the range.
|
|
*
|
|
* @param Range - The range to check.
|
|
* @param Predicate - The equivalence relation predicate between the projected elements and the value.
|
|
* @param Projection - The projection to apply to the elements before checking.
|
|
*
|
|
* @return The iterator to the first of the pair of equal adjacent elements, or the end iterator if not found.
|
|
*/
|
|
template <CForwardRange R,
|
|
CRegularInvocable<TRangeReference<R>> Proj =
|
|
decltype([]<typename T>(T&& A) -> T&& { return Forward<T>(A); }),
|
|
CEquivalenceRelation<TInvokeResult<Proj, TRangeReference<R>>, TInvokeResult<Proj, TRangeReference<R>>> Pred =
|
|
TConditional<CWeaklyEqualityComparable<TInvokeResult<Proj, TRangeReference<R>>>,
|
|
decltype([]<typename LHS, typename RHS>(const LHS& A, const RHS& B) { return A == B; }), void>>
|
|
requires (CBorrowedRange<R>)
|
|
NODISCARD constexpr TRangeIterator<R> FindAdjacent(R&& Range, Pred Predicate = { }, Proj Projection = { })
|
|
{
|
|
if constexpr (CSizedRange<R&>)
|
|
{
|
|
checkf(Algorithms::Distance(Range) >= 0, TEXT("Illegal range. Please check Algorithms::Distance(Range)."));
|
|
}
|
|
|
|
auto Iter = Ranges::Begin(Range);
|
|
auto Sent = Ranges::End (Range);
|
|
|
|
if (Iter == Sent) return Iter;
|
|
|
|
auto Next = Algorithms::Next(Iter);
|
|
|
|
for (; Next != Sent; ++Iter, ++Next)
|
|
{
|
|
if (Invoke(Predicate, Invoke(Projection, *Iter), Invoke(Projection, *Next)))
|
|
{
|
|
return Iter;
|
|
}
|
|
}
|
|
|
|
return Next;
|
|
}
|
|
|
|
/**
|
|
* Finds the first pair of equal adjacent elements in the range.
|
|
*
|
|
* @param First - The iterator of the range.
|
|
* @param Last - The sentinel of the range.
|
|
* @param Predicate - The equivalence relation predicate between the projected elements and the value.
|
|
* @param Projection - The projection to apply to the elements before checking.
|
|
*
|
|
* @return The iterator to the first of the pair of equal adjacent elements, or the end iterator if not found.
|
|
*/
|
|
template <CForwardIterator I, CSentinelFor<I> S,
|
|
CRegularInvocable<TIteratorReference<I>> Proj =
|
|
decltype([]<typename T>(T&& A) -> T&& { return Forward<T>(A); }),
|
|
CEquivalenceRelation<TInvokeResult<Proj, TIteratorReference<I>>, TInvokeResult<Proj, TIteratorReference<I>>> Pred =
|
|
TConditional<CWeaklyEqualityComparable<TInvokeResult<Proj, TIteratorReference<I>>>,
|
|
decltype([]<typename LHS, typename RHS>(const LHS& A, const RHS& B) { return A == B; }), void>>
|
|
NODISCARD FORCEINLINE constexpr I FindAdjacent(I First, S Last, Pred Predicate = { }, Proj Projection = { })
|
|
{
|
|
if constexpr (CSizedSentinelFor<S, I>)
|
|
{
|
|
checkf(First - Last <= 0, TEXT("Illegal range iterator. Please check First <= Last."));
|
|
}
|
|
|
|
return Algorithms::FindAdjacent(Ranges::View(MoveTemp(First), Last), Ref(Predicate), Ref(Projection));
|
|
}
|
|
|
|
/**
|
|
* Counts the number of elements in the range that equals the given value.
|
|
*
|
|
* @param Range - The range of elements to examine.
|
|
* @param Value - The value to search for.
|
|
* @param Predicate - The equivalence relation predicate between the projected elements and the value.
|
|
* @param Projection - The projection to apply to the elements before checking.
|
|
*
|
|
* @return The number of elements that equals the value.
|
|
*/
|
|
template <CInputRange R,
|
|
CRegularInvocable<TRangeReference<R>> Proj =
|
|
decltype([]<typename T>(T&& A) -> T&& { return Forward<T>(A); }),
|
|
CReferenceable T = TRemoveCVRef<TInvokeResult<Proj, TRangeReference<R>>>,
|
|
CEquivalenceRelation<TInvokeResult<Proj, TRangeReference<R>>, T> Pred =
|
|
TConditional<CWeaklyEqualityComparable<TInvokeResult<Proj, TRangeReference<R>>, const T&>,
|
|
decltype([]<typename LHS, typename RHS>(const LHS& A, const RHS& B) { return A == B; }), void>>
|
|
NODISCARD constexpr size_t Count(R&& Range, const T& Value, Pred Predicate = { }, Proj Projection = { })
|
|
{
|
|
if constexpr (CSizedRange<R&>)
|
|
{
|
|
checkf(Algorithms::Distance(Range) >= 0, TEXT("Illegal range. Please check Algorithms::Distance(Range)."));
|
|
}
|
|
|
|
auto Iter = Ranges::Begin(Range);
|
|
auto Sent = Ranges::End (Range);
|
|
|
|
size_t Result = 0;
|
|
|
|
for (; Iter != Sent; ++Iter)
|
|
{
|
|
if (Invoke(Predicate, Invoke(Projection, *Iter), Value))
|
|
{
|
|
++Result;
|
|
}
|
|
}
|
|
|
|
return Result;
|
|
}
|
|
|
|
/**
|
|
* Counts the number of elements in the range that equals the given value.
|
|
*
|
|
* @param First - The iterator of the range.
|
|
* @param Last - The sentinel of the range.
|
|
* @param Value - The value to search for.
|
|
* @param Predicate - The equivalence relation predicate between the projected elements and the value.
|
|
* @param Projection - The projection to apply to the elements before checking.
|
|
*
|
|
* @return The number of elements that equals the value.
|
|
*/
|
|
template <CInputIterator I, CSentinelFor<I> S,
|
|
CRegularInvocable<TIteratorReference<I>> Proj =
|
|
decltype([]<typename T>(T&& A) -> T&& { return Forward<T>(A); }),
|
|
CReferenceable T = TRemoveCVRef<TInvokeResult<Proj, TIteratorReference<I>>>,
|
|
CEquivalenceRelation<TInvokeResult<Proj, TIteratorReference<I>>, T> Pred =
|
|
TConditional<CWeaklyEqualityComparable<TInvokeResult<Proj, TIteratorReference<I>>, const T&>,
|
|
decltype([]<typename LHS, typename RHS>(const LHS& A, const RHS& B) { return A == B; }), void>>
|
|
NODISCARD FORCEINLINE constexpr size_t Count(I First, S Last, const T& Value, Pred Predicate = { }, Proj Projection = { })
|
|
{
|
|
if constexpr (CSizedSentinelFor<S, I>)
|
|
{
|
|
checkf(First - Last <= 0, TEXT("Illegal range iterator. Please check First <= Last."));
|
|
}
|
|
|
|
return Algorithms::Count(Ranges::View(MoveTemp(First), Last), Value, Ref(Predicate), Ref(Projection));
|
|
}
|
|
|
|
/**
|
|
* Counts the number of elements in the range that satisfies the predicate.
|
|
*
|
|
* @param Range - The range of elements to examine.
|
|
* @param Predicate - The unary predicate to satisfy.
|
|
* @param Projection - The projection to apply to the elements before checking.
|
|
*
|
|
* @return The number of elements that satisfies the predicate.
|
|
*/
|
|
template <CInputRange R,
|
|
CRegularInvocable<TRangeReference<R>> Proj =
|
|
decltype([]<typename T>(T&& A) -> T&& { return Forward<T>(A); }),
|
|
CPredicate<TInvokeResult<Proj, TRangeReference<R>>> Pred>
|
|
NODISCARD constexpr size_t CountIf(R&& Range, Pred Predicate, Proj Projection = { })
|
|
{
|
|
if constexpr (CSizedRange<R&>)
|
|
{
|
|
checkf(Algorithms::Distance(Range) >= 0, TEXT("Illegal range. Please check Algorithms::Distance(Range)."));
|
|
}
|
|
|
|
auto Iter = Ranges::Begin(Range);
|
|
auto Sent = Ranges::End (Range);
|
|
|
|
size_t Result = 0;
|
|
|
|
for (; Iter != Sent; ++Iter)
|
|
{
|
|
if (Invoke(Predicate, Invoke(Projection, *Iter)))
|
|
{
|
|
++Result;
|
|
}
|
|
}
|
|
|
|
return Result;
|
|
}
|
|
|
|
/**
|
|
* Counts the number of elements in the range that satisfies the predicate.
|
|
*
|
|
* @param First - The iterator of the range.
|
|
* @param Last - The sentinel of the range.
|
|
* @param Predicate - The unary predicate to satisfy.
|
|
* @param Projection - The projection to apply to the elements before checking.
|
|
*
|
|
* @return The number of elements that satisfies the predicate.
|
|
*/
|
|
template <CInputIterator I, CSentinelFor<I> S,
|
|
CRegularInvocable<TIteratorReference<I>> Proj =
|
|
decltype([]<typename T>(T&& A) -> T&& { return Forward<T>(A); }),
|
|
CPredicate<TInvokeResult<Proj, TIteratorReference<I>>> Pred>
|
|
NODISCARD FORCEINLINE constexpr size_t CountIf(I First, S Last, Pred Predicate, Proj Projection = { })
|
|
{
|
|
if constexpr (CSizedSentinelFor<S, I>)
|
|
{
|
|
checkf(First - Last <= 0, TEXT("Illegal range iterator. Please check First <= Last."));
|
|
}
|
|
|
|
return Algorithms::CountIf(Ranges::View(MoveTemp(First), Last), Ref(Predicate), Ref(Projection));
|
|
}
|
|
|
|
/**
|
|
* Finds the first mismatch between two ranges.
|
|
*
|
|
* @param LHS - The left hand side range of the elements to compare.
|
|
* @param RHS - The right hand side range of the elements to compare.
|
|
* @param Predicate - The equivalence relation predicate between the projected elements.
|
|
* @param LHSProjection - The projection to apply to the left hand side elements before checking.
|
|
* @param RHSProjection - The projection to apply to the right hand side elements before checking.
|
|
*
|
|
* @return The pair of iterators to the first mismatched elements, or the pair of end iterators if not found.
|
|
*/
|
|
template <CInputRange R1, CInputRange R2,
|
|
CRegularInvocable<TRangeReference<R1>> Proj1 =
|
|
decltype([]<typename T>(T&& A) -> T&& { return Forward<T>(A); }),
|
|
CRegularInvocable<TRangeReference<R2>> Proj2 =
|
|
decltype([]<typename T>(T&& A) -> T&& { return Forward<T>(A); }),
|
|
CEquivalenceRelation<TInvokeResult<Proj1, TRangeReference<R1>>, TInvokeResult<Proj2, TRangeReference<R2>>> Pred =
|
|
TConditional<CWeaklyEqualityComparable<TInvokeResult<Proj1, TRangeReference<R1>>, TInvokeResult<Proj2, TRangeReference<R2>>>,
|
|
decltype([]<typename LHS, typename RHS>(const LHS& A, const RHS& B) { return A == B; }), void>>
|
|
requires (CBorrowedRange<R1> && CBorrowedRange<R2>)
|
|
NODISCARD constexpr TTuple<TRangeIterator<R1>, TRangeIterator<R2>> Mismatch(R1&& LHS, R2&& RHS,
|
|
Pred Predicate = { }, Proj1 LHSProjection = { }, Proj2 RHSProjection = { })
|
|
{
|
|
if constexpr (CSizedRange<R1&>)
|
|
{
|
|
checkf(Algorithms::Distance(LHS) >= 0, TEXT("Illegal range. Please check Algorithms::Distance(LHS)."));
|
|
}
|
|
|
|
if constexpr (CSizedRange<R2&>)
|
|
{
|
|
checkf(Algorithms::Distance(RHS) >= 0, TEXT("Illegal range. Please check Algorithms::Distance(RHS)."));
|
|
}
|
|
|
|
auto IterA = Ranges::Begin(LHS);
|
|
auto SentA = Ranges::End (LHS);
|
|
|
|
auto IterB = Ranges::Begin(RHS);
|
|
auto SentB = Ranges::End (RHS);
|
|
|
|
while (IterA != SentA && IterB != SentB)
|
|
{
|
|
if (!Invoke(Predicate, Invoke(LHSProjection, *IterA), Invoke(RHSProjection, *IterB)))
|
|
{
|
|
break;
|
|
}
|
|
|
|
++IterA;
|
|
++IterB;
|
|
}
|
|
|
|
return { IterA, IterB };
|
|
}
|
|
|
|
/**
|
|
* Finds the first mismatch between two ranges.
|
|
*
|
|
* @param LHSFirst - The iterator of the left hand side range.
|
|
* @param LHSLast - The sentinel of the left hand side range.
|
|
* @param RHSFirst - The iterator of the right hand side range.
|
|
* @param RHSLast - The sentinel of the right hand side range.
|
|
* @param Predicate - The equivalence relation predicate between the projected elements.
|
|
* @param LHSProjection - The projection to apply to the left hand side elements before checking.
|
|
* @param RHSProjection - The projection to apply to the right hand side elements before checking.
|
|
*
|
|
* @return The pair of iterators to the first mismatched elements, or the pair of end iterators if not found.
|
|
*/
|
|
template <CInputIterator I1, CSentinelFor<I1> S1, CInputIterator I2, CSentinelFor<I2> S2,
|
|
CRegularInvocable<TIteratorReference<I1>> Proj1 =
|
|
decltype([]<typename T>(T&& A) -> T&& { return Forward<T>(A); }),
|
|
CRegularInvocable<TIteratorReference<I2>> Proj2 =
|
|
decltype([]<typename T>(T&& A) -> T&& { return Forward<T>(A); }),
|
|
CEquivalenceRelation<TInvokeResult<Proj1, TIteratorReference<I1>>, TInvokeResult<Proj2, TIteratorReference<I2>>> Pred =
|
|
TConditional<CWeaklyEqualityComparable<TInvokeResult<Proj1, TIteratorReference<I1>>, TInvokeResult<Proj2, TIteratorReference<I2>>>,
|
|
decltype([]<typename LHS, typename RHS>(const LHS& A, const RHS& B) { return A == B; }), void>>
|
|
NODISCARD FORCEINLINE constexpr TTuple<I1, I2> Mismatch(I1 LHSFirst, S1 LHSLast, I2 RHSFirst, S2 RHSLast,
|
|
Pred Predicate = { }, Proj1 LHSProjection = { }, Proj2 RHSProjection = { })
|
|
{
|
|
if constexpr (CSizedSentinelFor<S1, I1>)
|
|
{
|
|
checkf(LHSFirst - LHSLast <= 0, TEXT("Illegal range iterator. Please check LHSFirst <= LHSLast."));
|
|
}
|
|
|
|
if constexpr (CSizedSentinelFor<S2, I2>)
|
|
{
|
|
checkf(RHSFirst - RHSLast <= 0, TEXT("Illegal range iterator. Please check RHSFirst <= RHSLast."));
|
|
}
|
|
|
|
return Algorithms::Mismatch(
|
|
Ranges::View(MoveTemp(LHSFirst), LHSLast),
|
|
Ranges::View(MoveTemp(RHSFirst), RHSLast),
|
|
Ref(Predicate), Ref(LHSProjection), Ref(RHSProjection));
|
|
}
|
|
|
|
/**
|
|
* Checks if two ranges are equal.
|
|
*
|
|
* @param LHS - The left hand side range of the elements to compare.
|
|
* @param RHS - The right hand side range of the elements to compare.
|
|
* @param Predicate - The equivalence relation predicate between the projected elements.
|
|
* @param LHSProjection - The projection to apply to the left hand side elements before checking.
|
|
* @param RHSProjection - The projection to apply to the right hand side elements before checking.
|
|
*
|
|
* @return true if the ranges are equal, false otherwise.
|
|
*/
|
|
template <CInputRange R1, CInputRange R2,
|
|
CRegularInvocable<TRangeReference<R1>> Proj1 =
|
|
decltype([]<typename T>(T&& A) -> T&& { return Forward<T>(A); }),
|
|
CRegularInvocable<TRangeReference<R2>> Proj2 =
|
|
decltype([]<typename T>(T&& A) -> T&& { return Forward<T>(A); }),
|
|
CEquivalenceRelation<TInvokeResult<Proj1, TRangeReference<R1>>, TInvokeResult<Proj2, TRangeReference<R2>>> Pred =
|
|
TConditional<CWeaklyEqualityComparable<TInvokeResult<Proj1, TRangeReference<R1>>, TInvokeResult<Proj2, TRangeReference<R2>>>,
|
|
decltype([]<typename LHS, typename RHS>(const LHS& A, const RHS& B) { return A == B; }), void>>
|
|
NODISCARD FORCEINLINE constexpr bool Equal(R1&& LHS, R2&& RHS, Pred Predicate = { }, Proj1 LHSProjection = { }, Proj2 RHSProjection = { })
|
|
{
|
|
if constexpr (CSizedRange<R1&>)
|
|
{
|
|
checkf(Algorithms::Distance(LHS) >= 0, TEXT("Illegal range. Please check Algorithms::Distance(LHS)."));
|
|
}
|
|
|
|
if constexpr (CSizedRange<R2&>)
|
|
{
|
|
checkf(Algorithms::Distance(RHS) >= 0, TEXT("Illegal range. Please check Algorithms::Distance(RHS)."));
|
|
}
|
|
|
|
if constexpr (CSizedRange<R1&> && CSizedRange<R2&>)
|
|
{
|
|
if (Ranges::Num(LHS) != Ranges::Num(RHS))
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
|
|
auto FirstA = Ranges::Begin(LHS);
|
|
auto SentA = Ranges::End (LHS);
|
|
|
|
auto FirstB = Ranges::Begin(RHS);
|
|
auto SentB = Ranges::End (RHS);
|
|
|
|
auto [IterA, IterB] = Algorithms::Mismatch(
|
|
MoveTemp(FirstA), SentA, MoveTemp(FirstB), SentB,
|
|
Ref(Predicate), Ref(LHSProjection), Ref(RHSProjection));
|
|
|
|
return IterA == SentA && IterB == SentB;
|
|
}
|
|
|
|
/**
|
|
* Checks if two ranges are equal.
|
|
*
|
|
* @param LHSFirst - The iterator of the left hand side range.
|
|
* @param LHSLast - The sentinel of the left hand side range.
|
|
* @param RHSFirst - The iterator of the right hand side range.
|
|
* @param RHSLast - The sentinel of the right hand side range.
|
|
* @param Predicate - The equivalence relation predicate between the projected elements.
|
|
* @param LHSProjection - The projection to apply to the left hand side elements before checking.
|
|
* @param RHSProjection - The projection to apply to the right hand side elements before checking.
|
|
*
|
|
* @return true if the ranges are equal, false otherwise.
|
|
*/
|
|
template <CInputIterator I1, CSentinelFor<I1> S1, CInputIterator I2, CSentinelFor<I2> S2,
|
|
CRegularInvocable<TIteratorReference<I1>> Proj1 =
|
|
decltype([]<typename T>(T&& A) -> T&& { return Forward<T>(A); }),
|
|
CRegularInvocable<TIteratorReference<I2>> Proj2 =
|
|
decltype([]<typename T>(T&& A) -> T&& { return Forward<T>(A); }),
|
|
CEquivalenceRelation<TInvokeResult<Proj1, TIteratorReference<I1>>, TInvokeResult<Proj2, TIteratorReference<I2>>> Pred =
|
|
TConditional<CWeaklyEqualityComparable<TInvokeResult<Proj1, TIteratorReference<I1>>, TInvokeResult<Proj2, TIteratorReference<I2>>>,
|
|
decltype([]<typename LHS, typename RHS>(const LHS& A, const RHS& B) { return A == B; }), void>>
|
|
NODISCARD FORCEINLINE constexpr bool Equal(I1 LHSFirst, S1 LHSLast, I2 RHSFirst, S2 RHSLast,
|
|
Pred Predicate = { }, Proj1 LHSProjection = { }, Proj2 RHSProjection = { })
|
|
{
|
|
if constexpr (CSizedSentinelFor<S1, I1>)
|
|
{
|
|
checkf(LHSFirst - LHSLast <= 0, TEXT("Illegal range iterator. Please check LHSFirst <= LHSLast."));
|
|
}
|
|
|
|
if constexpr (CSizedSentinelFor<S2, I2>)
|
|
{
|
|
checkf(RHSFirst - RHSLast <= 0, TEXT("Illegal range iterator. Please check RHSFirst <= RHSLast."));
|
|
}
|
|
|
|
return Algorithms::Equal(
|
|
Ranges::View(MoveTemp(LHSFirst), LHSLast),
|
|
Ranges::View(MoveTemp(RHSFirst), RHSLast),
|
|
Ref(Predicate), Ref(LHSProjection), Ref(RHSProjection));
|
|
}
|
|
|
|
/**
|
|
* Checks if the range starts with the given prefix.
|
|
*
|
|
* @param Range - The range of elements to examine.
|
|
* @param Prefix - The range of elements to be used as the prefix.
|
|
* @param Predicate - The equivalence relation predicate between the projected elements.
|
|
* @param Projection - The projection to apply to the elements before checking.
|
|
* @param PrefixProjection - The projection to apply to the prefix elements before checking.
|
|
*
|
|
* @return true if the range starts with the prefix, false otherwise.
|
|
*/
|
|
template <CInputRange R1, CInputRange R2,
|
|
CRegularInvocable<TRangeReference<R1>> Proj1 =
|
|
decltype([]<typename T>(T&& A) -> T&& { return Forward<T>(A); }),
|
|
CRegularInvocable<TRangeReference<R2>> Proj2 =
|
|
decltype([]<typename T>(T&& A) -> T&& { return Forward<T>(A); }),
|
|
CEquivalenceRelation<TInvokeResult<Proj1, TRangeReference<R1>>, TInvokeResult<Proj2, TRangeReference<R2>>> Pred =
|
|
TConditional<CWeaklyEqualityComparable<TInvokeResult<Proj1, TRangeReference<R1>>, TInvokeResult<Proj2, TRangeReference<R2>>>,
|
|
decltype([]<typename LHS, typename RHS>(const LHS& A, const RHS& B) { return A == B; }), void>>
|
|
NODISCARD FORCEINLINE constexpr bool StartsWith(R1&& Range, R2&& Prefix, Pred Predicate = { }, Proj1 Projection = { }, Proj2 PrefixProjection = { })
|
|
{
|
|
if constexpr (CSizedRange<R1&>)
|
|
{
|
|
checkf(Algorithms::Distance(Range) >= 0, TEXT("Illegal range. Please check Algorithms::Distance(Range)."));
|
|
}
|
|
|
|
if constexpr (CSizedRange<R2&>)
|
|
{
|
|
checkf(Algorithms::Distance(Prefix) >= 0, TEXT("Illegal range. Please check Algorithms::Distance(Prefix)."));
|
|
}
|
|
|
|
if constexpr (CSizedRange<R1&> && CSizedRange<R2&>)
|
|
{
|
|
if (Ranges::Num(Range) < Ranges::Num(Prefix))
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
|
|
auto FirstA = Ranges::Begin(Range);
|
|
auto SentA = Ranges::End (Range);
|
|
|
|
auto FirstB = Ranges::Begin(Prefix);
|
|
auto SentB = Ranges::End (Prefix);
|
|
|
|
auto [IterA, IterB] = Algorithms::Mismatch(
|
|
MoveTemp(FirstA), SentA, MoveTemp(FirstB), SentB,
|
|
Ref(Predicate), Ref(Projection), Ref(PrefixProjection));
|
|
|
|
return IterB == SentB;
|
|
}
|
|
|
|
/**
|
|
* Checks if the range starts with the given prefix.
|
|
*
|
|
* @param First - The iterator of the range.
|
|
* @param Last - The sentinel of the range.
|
|
* @param PrefixFirst - The iterator of the prefix range.
|
|
* @param PrefixLast - The sentinel of the prefix range.
|
|
* @param Predicate - The equivalence relation predicate between the projected elements.
|
|
* @param Projection - The projection to apply to the elements before checking.
|
|
* @param PrefixProjection - The projection to apply to the prefix elements before checking.
|
|
*
|
|
* @return true if the range starts with the prefix, false otherwise.
|
|
*/
|
|
template <CInputIterator I1, CSentinelFor<I1> S1, CInputIterator I2, CSentinelFor<I2> S2,
|
|
CRegularInvocable<TIteratorReference<I1>> Proj1 =
|
|
decltype([]<typename T>(T&& A) -> T&& { return Forward<T>(A); }),
|
|
CRegularInvocable<TIteratorReference<I2>> Proj2 =
|
|
decltype([]<typename T>(T&& A) -> T&& { return Forward<T>(A); }),
|
|
CEquivalenceRelation<TInvokeResult<Proj1, TIteratorReference<I1>>, TInvokeResult<Proj2, TIteratorReference<I2>>> Pred =
|
|
TConditional<CWeaklyEqualityComparable<TInvokeResult<Proj1, TIteratorReference<I1>>, TInvokeResult<Proj2, TIteratorReference<I2>>>,
|
|
decltype([]<typename LHS, typename RHS>(const LHS& A, const RHS& B) { return A == B; }), void>>
|
|
NODISCARD FORCEINLINE constexpr bool StartsWith(I1 First, S1 Last, I2 PrefixFirst, S2 PrefixLast,
|
|
Pred Predicate = { }, Proj1 Projection = { }, Proj2 PrefixProjection = { })
|
|
{
|
|
if constexpr (CSizedSentinelFor<S1, I1>)
|
|
{
|
|
checkf(First - Last <= 0, TEXT("Illegal range iterator. Please check First <= Last."));
|
|
}
|
|
|
|
if constexpr (CSizedSentinelFor<S2, I2>)
|
|
{
|
|
checkf(PrefixFirst - PrefixLast <= 0, TEXT("Illegal range iterator. Please check PrefixFirst <= PrefixLast."));
|
|
}
|
|
|
|
return Algorithms::StartsWith(
|
|
Ranges::View(MoveTemp( First), Last),
|
|
Ranges::View(MoveTemp(PrefixFirst), PrefixLast),
|
|
Ref(Predicate), Ref(Projection), Ref(PrefixProjection));
|
|
}
|
|
|
|
/**
|
|
* Checks if the range ends with the given suffix.
|
|
*
|
|
* @param Range - The range of elements to examine.
|
|
* @param Suffix - The range of elements to be used as the suffix.
|
|
* @param Predicate - The equivalence relation predicate between the projected elements.
|
|
* @param Projection - The projection to apply to the elements before checking.
|
|
* @param SuffixProjection - The projection to apply to the suffix elements before checking.
|
|
*
|
|
* @return true if the range ends with the suffix, false otherwise.
|
|
*/
|
|
template <CInputRange R1, CInputRange R2,
|
|
CRegularInvocable<TRangeReference<R1>> Proj1 =
|
|
decltype([]<typename T>(T&& A) -> T&& { return Forward<T>(A); }),
|
|
CRegularInvocable<TRangeReference<R2>> Proj2 =
|
|
decltype([]<typename T>(T&& A) -> T&& { return Forward<T>(A); }),
|
|
CEquivalenceRelation<TInvokeResult<Proj1, TRangeReference<R1>>, TInvokeResult<Proj2, TRangeReference<R2>>> Pred =
|
|
TConditional<CWeaklyEqualityComparable<TInvokeResult<Proj1, TRangeReference<R1>>, TInvokeResult<Proj2, TRangeReference<R2>>>,
|
|
decltype([]<typename LHS, typename RHS>(const LHS& A, const RHS& B) { return A == B; }), void>>
|
|
requires ((CForwardRange<R1> || CSizedRange<R1>) && (CForwardRange<R2> || CSizedRange<R2>))
|
|
NODISCARD FORCEINLINE constexpr bool EndsWith(R1&& Range, R2&& Suffix, Pred Predicate = { }, Proj1 Projection = { }, Proj2 SuffixProjection = { })
|
|
{
|
|
const ptrdiff CountA = Algorithms::Distance(Range);
|
|
const ptrdiff CountB = Algorithms::Distance(Suffix);
|
|
|
|
checkf(CountA >= 0, TEXT("Illegal range. Please check Algorithms::Distance(Range)."));
|
|
checkf(CountB >= 0, TEXT("Illegal range. Please check Algorithms::Distance(Suffix)."));
|
|
|
|
if (CountA < CountB) return false;
|
|
|
|
auto Iter = Ranges::Begin(Range);
|
|
|
|
Algorithms::Advance(Iter, CountA - CountB);
|
|
|
|
return Algorithms::Equal(
|
|
MoveTemp(Iter), Ranges::End(Range), Ranges::Begin(Suffix), Ranges::End(Suffix),
|
|
Ref(Predicate), Ref(Projection), Ref(SuffixProjection));
|
|
}
|
|
|
|
/**
|
|
* Checks if the range ends with the given suffix.
|
|
*
|
|
* @param First - The iterator of the range.
|
|
* @param Last - The sentinel of the range.
|
|
* @param SuffixFirst - The iterator of the suffix range.
|
|
* @param SuffixLast - The sentinel of the suffix range.
|
|
* @param Predicate - The equivalence relation predicate between the projected elements.
|
|
* @param Projection - The projection to apply to the elements before checking.
|
|
* @param SuffixProjection - The projection to apply to the suffix elements before checking.
|
|
*
|
|
* @return true if the range ends with the suffix, false otherwise.
|
|
*/
|
|
template <CInputIterator I1, CSentinelFor<I1> S1, CInputIterator I2, CSentinelFor<I2> S2,
|
|
CRegularInvocable<TIteratorReference<I1>> Proj1 =
|
|
decltype([]<typename T>(T&& A) -> T&& { return Forward<T>(A); }),
|
|
CRegularInvocable<TIteratorReference<I2>> Proj2 =
|
|
decltype([]<typename T>(T&& A) -> T&& { return Forward<T>(A); }),
|
|
CEquivalenceRelation<TInvokeResult<Proj1, TIteratorReference<I1>>, TInvokeResult<Proj2, TIteratorReference<I2>>> Pred =
|
|
TConditional<CWeaklyEqualityComparable<TInvokeResult<Proj1, TIteratorReference<I1>>, TInvokeResult<Proj2, TIteratorReference<I2>>>,
|
|
decltype([]<typename LHS, typename RHS>(const LHS& A, const RHS& B) { return A == B; }), void>>
|
|
requires ((CForwardIterator<I1> || CSizedSentinelFor<S1, I1>) && (CForwardIterator<I2> || CSizedSentinelFor<S2, I2>))
|
|
NODISCARD FORCEINLINE constexpr bool EndsWith(I1 First, S1 Last, I2 SuffixFirst, S2 SuffixLast,
|
|
Pred Predicate = { }, Proj1 Projection = { }, Proj2 SuffixProjection = { })
|
|
{
|
|
if constexpr (CSizedSentinelFor<S1, I1>)
|
|
{
|
|
checkf(First - Last <= 0, TEXT("Illegal range iterator. Please check First <= Last."));
|
|
}
|
|
|
|
if constexpr (CSizedSentinelFor<S2, I2>)
|
|
{
|
|
checkf(SuffixFirst - SuffixLast <= 0, TEXT("Illegal range iterator. Please check SuffixFirst <= SuffixLast."));
|
|
}
|
|
|
|
return Algorithms::EndsWith(
|
|
Ranges::View(MoveTemp( First), Last),
|
|
Ranges::View(MoveTemp(SuffixFirst), SuffixLast),
|
|
Ref(Predicate), Ref(Projection), Ref(SuffixProjection));
|
|
}
|
|
|
|
NAMESPACE_END(Algorithms)
|
|
|
|
NAMESPACE_MODULE_END(Utility)
|
|
NAMESPACE_MODULE_END(Redcraft)
|
|
NAMESPACE_REDCRAFT_END
|