#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 > Proj = decltype([](T&& A) -> T&& { return Forward(A); }), CPredicate>> Pred> NODISCARD constexpr bool AllOf(R&& Range, Pred Predicate, Proj Projection = { }) { if constexpr (CSizedRange) { 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 S, CRegularInvocable> Proj = decltype([](T&& A) -> T&& { return Forward(A); }), CPredicate>> Pred> NODISCARD FORCEINLINE constexpr bool AllOf(I First, S Last, Pred Predicate, Proj Projection = { }) { if constexpr (CSizedSentinelFor) { 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 > Proj = decltype([](T&& A) -> T&& { return Forward(A); }), CPredicate>> Pred> NODISCARD constexpr bool AnyOf(R&& Range, Pred Predicate, Proj Projection = { }) { if constexpr (CSizedRange) { 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 S, CRegularInvocable> Proj = decltype([](T&& A) -> T&& { return Forward(A); }), CPredicate>> Pred> NODISCARD FORCEINLINE constexpr bool AnyOf(I First, S Last, Pred Predicate, Proj Projection = { }) { if constexpr (CSizedSentinelFor) { 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 > Proj = decltype([](T&& A) -> T&& { return Forward(A); }), CPredicate>> Pred> NODISCARD constexpr bool NoneOf(R&& Range, Pred Predicate, Proj Projection = { }) { if constexpr (CSizedRange) { 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 S, CRegularInvocable> Proj = decltype([](T&& A) -> T&& { return Forward(A); }), CPredicate>> Pred> NODISCARD FORCEINLINE constexpr bool NoneOf(I First, S Last, Pred Predicate, Proj Projection = { }) { if constexpr (CSizedSentinelFor) { 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 > Proj = decltype([](T&& A) -> T&& { return Forward(A); }), CReferenceable T = TRemoveCVRef>>, CEquivalenceRelation>, const T&> Pred = TConditional>, const T&>, decltype([](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) { 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 S, CRegularInvocable> Proj = decltype([](T&& A) -> T&& { return Forward(A); }), CReferenceable T = TRemoveCVRef>>, CEquivalenceRelation>, const T&> Pred = TConditional>, const T&>, decltype([](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) { 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 > Proj1 = decltype([](T&& A) -> T&& { return Forward(A); }), CRegularInvocable> Proj2 = decltype([](T&& A) -> T&& { return Forward(A); }), CEquivalenceRelation>, TInvokeResult>> Pred = TConditional>, TInvokeResult>>, decltype([](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) { checkf(Algorithms::Distance(Haystack) >= 0, TEXT("Illegal range. Please check Algorithms::Distance(Haystack).")); } if constexpr (CSizedRange) { 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 S1, CForwardIterator I2, CSentinelFor S2, CRegularInvocable> Proj1 = decltype([](T&& A) -> T&& { return Forward(A); }), CRegularInvocable> Proj2 = decltype([](T&& A) -> T&& { return Forward(A); }), CEquivalenceRelation>, TInvokeResult>> Pred = TConditional>, TInvokeResult>>, decltype([](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) { checkf(HaystackFirst - HaystackLast <= 0, TEXT("Illegal range iterator. Please check HaystackFirst <= HaystackLast.")); } if constexpr (CSizedSentinelFor) { 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 > Proj = decltype([](T&& A) -> T&& { return Forward(A); }), CReferenceable T = TRemoveCVRef>>, CEquivalenceRelation>, const T&> Pred = TConditional>, const T&>, decltype([](const LHS& A, const RHS& B) { return A == B; }), void>> requires (CBorrowedRange) NODISCARD constexpr TRangeIterator Find(R&& Range, const T& Value, Pred Predicate = { }, Proj Projection = { }) { if constexpr (CSizedRange) { 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 S, CRegularInvocable> Proj = decltype([](T&& A) -> T&& { return Forward(A); }), CReferenceable T = TRemoveCVRef>>, CEquivalenceRelation>, const T&> Pred = TConditional>, const T&>, decltype([](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) { 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 > Proj1 = decltype([](T&& A) -> T&& { return Forward(A); }), CRegularInvocable> Proj2 = decltype([](T&& A) -> T&& { return Forward(A); }), CEquivalenceRelation>, TInvokeResult>> Pred = TConditional>, TInvokeResult>>, decltype([](const LHS& A, const RHS& B) { return A == B; }), void>> requires (CBorrowedRange) NODISCARD constexpr Ranges::TRangeView> Find(R1&& Haystack, R2&& Needle, Pred Predicate = { }, Proj1 HaystackProjection = { }, Proj2 NeedleProjection = { }) { if constexpr (CSizedRange) { checkf(Algorithms::Distance(Haystack) >= 0, TEXT("Illegal range. Please check Algorithms::Distance(Haystack).")); } if constexpr (CSizedRange) { 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 S1, CForwardIterator I2, CSentinelFor S2, CRegularInvocable> Proj1 = decltype([](T&& A) -> T&& { return Forward(A); }), CRegularInvocable> Proj2 = decltype([](T&& A) -> T&& { return Forward(A); }), CEquivalenceRelation>, TInvokeResult>> Pred = TConditional>, TInvokeResult>>, decltype([](const LHS& A, const RHS& B) { return A == B; }), void>> NODISCARD FORCEINLINE constexpr Ranges::TRangeView Find(I1 HaystackFirst, S1 HaystackLast, I2 NeedleFirst, S2 NeedleLast, Pred Predicate = { }, Proj1 HaystackProjection = { }, Proj2 NeedleProjection = { }) { if constexpr (CSizedSentinelFor) { checkf(HaystackFirst - HaystackLast <= 0, TEXT("Illegal range iterator. Please check HaystackFirst <= HaystackLast.")); } if constexpr (CSizedSentinelFor) { 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 > Proj = decltype([](T&& A) -> T&& { return Forward(A); }), CPredicate>> Pred> requires (CBorrowedRange) NODISCARD constexpr TRangeIterator FindIf(R&& Range, Pred Predicate, Proj Projection = { }) { if constexpr (CSizedRange) { 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 S, CRegularInvocable> Proj = decltype([](T&& A) -> T&& { return Forward(A); }), CPredicate>> Pred> NODISCARD FORCEINLINE constexpr I FindIf(I First, S Last, Pred Predicate, Proj Projection = { }) { if constexpr (CSizedSentinelFor) { 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 > Proj = decltype([](T&& A) -> T&& { return Forward(A); }), CPredicate>> Pred> requires (CBorrowedRange) NODISCARD FORCEINLINE constexpr TRangeIterator FindIfNot(R&& Range, Pred Predicate, Proj Projection = { }) { if constexpr (CSizedRange) { checkf(Algorithms::Distance(Range) >= 0, TEXT("Illegal range. Please check Algorithms::Distance(Range).")); } auto NotPredicate = [&Predicate](T&& A) { return !Invoke(Predicate, Forward(A)); }; return Algorithms::FindIf(Forward(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 S, CRegularInvocable> Proj = decltype([](T&& A) -> T&& { return Forward(A); }), CPredicate>> Pred> NODISCARD FORCEINLINE constexpr I FindIfNot(I First, S Last, Pred Predicate, Proj Projection = { }) { if constexpr (CSizedSentinelFor) { 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 > Proj = decltype([](T&& A) -> T&& { return Forward(A); }), CReferenceable T = TRemoveCVRef>>, CEquivalenceRelation>, const T&> Pred = TConditional>, const T&>, decltype([](const LHS& A, const RHS& B) { return A == B; }), void>> requires (CBorrowedRange) NODISCARD constexpr TRangeIterator FindLast(R&& Range, const T& Value, Pred Predicate = { }, Proj Projection = { }) { if constexpr (CSizedRange) { 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 && CCommonRange) { 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 && CSizedRange) { 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> 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 S, CRegularInvocable> Proj = decltype([](T&& A) -> T&& { return Forward(A); }), CReferenceable T = TRemoveCVRef>>, CEquivalenceRelation>, const T&> Pred = TConditional>, const T&>, decltype([](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) { 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 > Proj1 = decltype([](T&& A) -> T&& { return Forward(A); }), CRegularInvocable> Proj2 = decltype([](T&& A) -> T&& { return Forward(A); }), CEquivalenceRelation>, TInvokeResult>> Pred = TConditional>, TInvokeResult>>, decltype([](const LHS& A, const RHS& B) { return A == B; }), void>> requires (CBorrowedRange) NODISCARD constexpr Ranges::TRangeView> FindLast(R1&& Haystack, R2&& Needle, Pred Predicate = { }, Proj1 HaystackProjection = { }, Proj2 NeedleProjection = { }) { if constexpr (CSizedRange) { checkf(Algorithms::Distance(Haystack) >= 0, TEXT("Illegal range. Please check Algorithms::Distance(Haystack).")); } if constexpr (CSizedRange) { 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 && CCommonRange) { 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 S1, CForwardIterator I2, CSentinelFor S2, CRegularInvocable> Proj1 = decltype([](T&& A) -> T&& { return Forward(A); }), CRegularInvocable> Proj2 = decltype([](T&& A) -> T&& { return Forward(A); }), CEquivalenceRelation>, TInvokeResult>> Pred = TConditional>, TInvokeResult>>, decltype([](const LHS& A, const RHS& B) { return A == B; }), void>> NODISCARD FORCEINLINE constexpr Ranges::TRangeView FindLast(I1 HaystackFirst, S1 HaystackLast, I2 NeedleFirst, S2 NeedleLast, Pred Predicate = { }, Proj1 HaystackProjection = { }, Proj2 NeedleProjection = { }) { if constexpr (CSizedSentinelFor) { checkf(HaystackFirst - HaystackLast <= 0, TEXT("Illegal range iterator. Please check HaystackFirst <= HaystackLast.")); } if constexpr (CSizedSentinelFor) { 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 > Proj = decltype([](T&& A) -> T&& { return Forward(A); }), CPredicate>> Pred> requires (CBorrowedRange) NODISCARD constexpr TRangeIterator FindLastIf(R&& Range, Pred Predicate, Proj Projection = { }) { if constexpr (CSizedRange) { 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 && CCommonRange) { 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 && CSizedRange) { 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> 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 S, CRegularInvocable> Proj = decltype([](T&& A) -> T&& { return Forward(A); }), CPredicate>> Pred> NODISCARD FORCEINLINE constexpr I FindLastIf(I First, S Last, Pred Predicate, Proj Projection = { }) { if constexpr (CSizedSentinelFor) { 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 > Proj = decltype([](T&& A) -> T&& { return Forward(A); }), CPredicate>> Pred> requires (CBorrowedRange) NODISCARD constexpr TRangeIterator FindLastIfNot(R&& Range, Pred Predicate, Proj Projection = { }) { if constexpr (CSizedRange) { checkf(Algorithms::Distance(Range) >= 0, TEXT("Illegal range. Please check Algorithms::Distance(Range).")); } auto NotPredicate = [&Predicate](T&& A) { return !Invoke(Predicate, Forward(A)); }; return Algorithms::FindLastIf(Forward(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 S, CRegularInvocable> Proj = decltype([](T&& A) -> T&& { return Forward(A); }), CPredicate>> Pred> NODISCARD FORCEINLINE constexpr I FindLastIfNot(I First, S Last, Pred Predicate, Proj Projection = { }) { if constexpr (CSizedSentinelFor) { 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 > Proj1 = decltype([](T&& A) -> T&& { return Forward(A); }), CRegularInvocable> Proj2 = decltype([](T&& A) -> T&& { return Forward(A); }), CEquivalenceRelation>, TInvokeResult>> Pred = TConditional>, TInvokeResult>>, decltype([](const LHS& A, const RHS& B) { return A == B; }), void>> requires (CBorrowedRange) NODISCARD FORCEINLINE constexpr TRangeIterator FindFirstOf(R1&& Haystack, R2&& Needle, Pred Predicate = { }, Proj1 HaystackProjection = { }, Proj2 NeedleProjection = { }) { if constexpr (CSizedRange) { checkf(Algorithms::Distance(Haystack) >= 0, TEXT("Illegal range. Please check Algorithms::Distance(Haystack).")); } if constexpr (CSizedRange) { checkf(Algorithms::Distance(Needle) >= 0, TEXT("Illegal range. Please check Algorithms::Distance(Needle).")); } auto ContainsInNeedle = [&](LHS&& A) { auto ForwardPredicate = [&](RHS&& B) { return Invoke(Predicate, Forward(A), Forward(B)); }; return Algorithms::FindIf(Needle, ForwardPredicate, Ref(NeedleProjection)) != Ranges::End(Needle); }; return Algorithms::FindIf(Forward(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 S1, CForwardIterator I2, CSentinelFor S2, CRegularInvocable> Proj1 = decltype([](T&& A) -> T&& { return Forward(A); }), CRegularInvocable> Proj2 = decltype([](T&& A) -> T&& { return Forward(A); }), CEquivalenceRelation>, TInvokeResult>> Pred = TConditional>, TInvokeResult>>, decltype([](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) { checkf(HaystackFirst - HaystackLast <= 0, TEXT("Illegal range iterator. Please check HaystackFirst <= HaystackLast.")); } if constexpr (CSizedSentinelFor) { 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 > Proj1 = decltype([](T&& A) -> T&& { return Forward(A); }), CRegularInvocable> Proj2 = decltype([](T&& A) -> T&& { return Forward(A); }), CEquivalenceRelation>, TInvokeResult>> Pred = TConditional>, TInvokeResult>>, decltype([](const LHS& A, const RHS& B) { return A == B; }), void>> requires (CBorrowedRange) NODISCARD FORCEINLINE constexpr TRangeIterator FindLastOf(R1&& Haystack, R2&& Needle, Pred Predicate = { }, Proj1 HaystackProjection = { }, Proj2 NeedleProjection = { }) { if constexpr (CSizedRange) { checkf(Algorithms::Distance(Haystack) >= 0, TEXT("Illegal range. Please check Algorithms::Distance(Haystack).")); } if constexpr (CSizedRange) { checkf(Algorithms::Distance(Needle) >= 0, TEXT("Illegal range. Please check Algorithms::Distance(Needle).")); } auto ContainsInNeedle = [&](LHS&& A) { auto ForwardPredicate = [&](RHS&& B) { return Invoke(Predicate, Forward(A), Forward(B)); }; return Algorithms::FindIf(Needle, ForwardPredicate, Ref(NeedleProjection)) != Ranges::End(Needle); }; return Algorithms::FindLastIf(Forward(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 S1, CForwardIterator I2, CSentinelFor S2, CRegularInvocable> Proj1 = decltype([](T&& A) -> T&& { return Forward(A); }), CRegularInvocable> Proj2 = decltype([](T&& A) -> T&& { return Forward(A); }), CEquivalenceRelation>, TInvokeResult>> Pred = TConditional>, TInvokeResult>>, decltype([](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) { checkf(HaystackFirst - HaystackLast <= 0, TEXT("Illegal range iterator. Please check HaystackFirst <= HaystackLast.")); } if constexpr (CSizedSentinelFor) { 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 > Proj = decltype([](T&& A) -> T&& { return Forward(A); }), CEquivalenceRelation>, TInvokeResult>> Pred = TConditional>, TInvokeResult>>, decltype([](const LHS& A, const RHS& B) { return A == B; }), void>> requires (CBorrowedRange) NODISCARD constexpr TRangeIterator FindAdjacent(R&& Range, Pred Predicate = { }, Proj Projection = { }) { if constexpr (CSizedRange) { 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 S, CRegularInvocable> Proj = decltype([](T&& A) -> T&& { return Forward(A); }), CEquivalenceRelation>, TInvokeResult>> Pred = TConditional>, TInvokeResult>>, decltype([](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) { 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 > Proj = decltype([](T&& A) -> T&& { return Forward(A); }), CReferenceable T = TRemoveCVRef>>, CEquivalenceRelation>, T> Pred = TConditional>, const T&>, decltype([](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) { 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 S, CRegularInvocable> Proj = decltype([](T&& A) -> T&& { return Forward(A); }), CReferenceable T = TRemoveCVRef>>, CEquivalenceRelation>, T> Pred = TConditional>, const T&>, decltype([](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) { 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 > Proj = decltype([](T&& A) -> T&& { return Forward(A); }), CPredicate>> Pred> NODISCARD constexpr size_t CountIf(R&& Range, Pred Predicate, Proj Projection = { }) { if constexpr (CSizedRange) { 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 S, CRegularInvocable> Proj = decltype([](T&& A) -> T&& { return Forward(A); }), CPredicate>> Pred> NODISCARD FORCEINLINE constexpr size_t CountIf(I First, S Last, Pred Predicate, Proj Projection = { }) { if constexpr (CSizedSentinelFor) { 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 > Proj1 = decltype([](T&& A) -> T&& { return Forward(A); }), CRegularInvocable> Proj2 = decltype([](T&& A) -> T&& { return Forward(A); }), CEquivalenceRelation>, TInvokeResult>> Pred = TConditional>, TInvokeResult>>, decltype([](const LHS& A, const RHS& B) { return A == B; }), void>> requires (CBorrowedRange && CBorrowedRange) NODISCARD constexpr TTuple, TRangeIterator> Mismatch(R1&& LHS, R2&& RHS, Pred Predicate = { }, Proj1 LHSProjection = { }, Proj2 RHSProjection = { }) { if constexpr (CSizedRange) { checkf(Algorithms::Distance(LHS) >= 0, TEXT("Illegal range. Please check Algorithms::Distance(LHS).")); } if constexpr (CSizedRange) { 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 S1, CInputIterator I2, CSentinelFor S2, CRegularInvocable> Proj1 = decltype([](T&& A) -> T&& { return Forward(A); }), CRegularInvocable> Proj2 = decltype([](T&& A) -> T&& { return Forward(A); }), CEquivalenceRelation>, TInvokeResult>> Pred = TConditional>, TInvokeResult>>, decltype([](const LHS& A, const RHS& B) { return A == B; }), void>> NODISCARD FORCEINLINE constexpr TTuple Mismatch(I1 LHSFirst, S1 LHSLast, I2 RHSFirst, S2 RHSLast, Pred Predicate = { }, Proj1 LHSProjection = { }, Proj2 RHSProjection = { }) { if constexpr (CSizedSentinelFor) { checkf(LHSFirst - LHSLast <= 0, TEXT("Illegal range iterator. Please check LHSFirst <= LHSLast.")); } if constexpr (CSizedSentinelFor) { 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 > Proj1 = decltype([](T&& A) -> T&& { return Forward(A); }), CRegularInvocable> Proj2 = decltype([](T&& A) -> T&& { return Forward(A); }), CEquivalenceRelation>, TInvokeResult>> Pred = TConditional>, TInvokeResult>>, decltype([](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) { checkf(Algorithms::Distance(LHS) >= 0, TEXT("Illegal range. Please check Algorithms::Distance(LHS).")); } if constexpr (CSizedRange) { checkf(Algorithms::Distance(RHS) >= 0, TEXT("Illegal range. Please check Algorithms::Distance(RHS).")); } if constexpr (CSizedRange && CSizedRange) { 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 S1, CInputIterator I2, CSentinelFor S2, CRegularInvocable> Proj1 = decltype([](T&& A) -> T&& { return Forward(A); }), CRegularInvocable> Proj2 = decltype([](T&& A) -> T&& { return Forward(A); }), CEquivalenceRelation>, TInvokeResult>> Pred = TConditional>, TInvokeResult>>, decltype([](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) { checkf(LHSFirst - LHSLast <= 0, TEXT("Illegal range iterator. Please check LHSFirst <= LHSLast.")); } if constexpr (CSizedSentinelFor) { 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 > Proj1 = decltype([](T&& A) -> T&& { return Forward(A); }), CRegularInvocable> Proj2 = decltype([](T&& A) -> T&& { return Forward(A); }), CEquivalenceRelation>, TInvokeResult>> Pred = TConditional>, TInvokeResult>>, decltype([](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) { checkf(Algorithms::Distance(Range) >= 0, TEXT("Illegal range. Please check Algorithms::Distance(Range).")); } if constexpr (CSizedRange) { checkf(Algorithms::Distance(Prefix) >= 0, TEXT("Illegal range. Please check Algorithms::Distance(Prefix).")); } if constexpr (CSizedRange && CSizedRange) { 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 S1, CInputIterator I2, CSentinelFor S2, CRegularInvocable> Proj1 = decltype([](T&& A) -> T&& { return Forward(A); }), CRegularInvocable> Proj2 = decltype([](T&& A) -> T&& { return Forward(A); }), CEquivalenceRelation>, TInvokeResult>> Pred = TConditional>, TInvokeResult>>, decltype([](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) { checkf(First - Last <= 0, TEXT("Illegal range iterator. Please check First <= Last.")); } if constexpr (CSizedSentinelFor) { 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 > Proj1 = decltype([](T&& A) -> T&& { return Forward(A); }), CRegularInvocable> Proj2 = decltype([](T&& A) -> T&& { return Forward(A); }), CEquivalenceRelation>, TInvokeResult>> Pred = TConditional>, TInvokeResult>>, decltype([](const LHS& A, const RHS& B) { return A == B; }), void>> requires ((CForwardRange || CSizedRange) && (CForwardRange || CSizedRange)) 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 S1, CInputIterator I2, CSentinelFor S2, CRegularInvocable> Proj1 = decltype([](T&& A) -> T&& { return Forward(A); }), CRegularInvocable> Proj2 = decltype([](T&& A) -> T&& { return Forward(A); }), CEquivalenceRelation>, TInvokeResult>> Pred = TConditional>, TInvokeResult>>, decltype([](const LHS& A, const RHS& B) { return A == B; }), void>> requires ((CForwardIterator || CSizedSentinelFor) && (CForwardIterator || CSizedSentinelFor)) NODISCARD FORCEINLINE constexpr bool EndsWith(I1 First, S1 Last, I2 SuffixFirst, S2 SuffixLast, Pred Predicate = { }, Proj1 Projection = { }, Proj2 SuffixProjection = { }) { if constexpr (CSizedSentinelFor) { checkf(First - Last <= 0, TEXT("Illegal range iterator. Please check First <= Last.")); } if constexpr (CSizedSentinelFor) { 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