8#include "Stroika/Foundation/Containers/Adapters/Adder.h"
15namespace Stroika::Foundation::Traversal {
17 constexpr bool kIterableUsesStroikaSharedPtr [[deprecated (
"Since Stroika v3.0d1 - not used")]] =
false;
19 struct [[deprecated (
"Since Stroika v3.0d1")]] IterableBase {
20 template <
typename SHARED_T>
21 using PtrImplementationTemplate [[deprecated (
"Since Stroika v3.0d1 - use shared_ptr directly")]] = shared_ptr<SHARED_T>;
22 template <
typename SHARED_T,
typename... ARGS_TYPE>
23 [[deprecated (
"Since Stroika v3.0d1 - use Memory::MakeSharedPtr directly")]]
static shared_ptr<SHARED_T> MakeSmartPtr (ARGS_TYPE&&... args)
25 return Memory::MakeSharedPtr<SHARED_T> (forward<ARGS_TYPE> (args)...);
27 template <
typename SHARED_T>
28 using enable_shared_from_this_PtrImplementationTemplate [[deprecated (
"Since Stroika v3.0d1")]] = std::enable_shared_from_this<SHARED_T>;
111 template <
typename T>
122 template <
typename T>
123 template <
typename REP_SUB_TYPE>
125 : fConstRef_{Debug::UncheckedDynamicCast<const REP_SUB_TYPE*> (
it->_fRep.cget ())}
126 , fIterableEnvelope_{
it}
127#if qStroika_Foundation_Debug_AssertionsChecked
134 template <
typename T>
135 template <
typename REP_SUB_TYPE>
136 inline Iterable<T>::_SafeReadRepAccessor<REP_SUB_TYPE>::_SafeReadRepAccessor (_SafeReadRepAccessor&&
src) noexcept
137 : fConstRef_{
src.fConstRef_}
138 , fIterableEnvelope_{
src.fIterableEnvelope_}
139#if qStroika_Foundation_Debug_AssertionsChecked
145 src.fConstRef_ =
nullptr;
147 template <
typename T>
148 template <
typename REP_SUB_TYPE>
149 inline auto Iterable<T>::_SafeReadRepAccessor<REP_SUB_TYPE>::operator= (_SafeReadRepAccessor&&
rhs)
noexcept -> _SafeReadRepAccessor&
151 fConstRef_ =
rhs.fConstRef_;
152 this->fIterableEnvelope_ =
rhs.fIterableEnvelope_;
153#if qStroika_Foundation_Debug_AssertionsChecked
158 template <
typename T>
159 template <
typename REP_SUB_TYPE>
160 inline const REP_SUB_TYPE& Iterable<T>::_SafeReadRepAccessor<REP_SUB_TYPE>::_ConstGetRep ()
const noexcept
165 template <
typename T>
166 template <
typename REP_SUB_TYPE>
167 inline auto Iterable<T>::_SafeReadRepAccessor<REP_SUB_TYPE>::_ConstGetRepSharedPtr ()
const noexcept -> shared_ptr<
REP_SUB_TYPE>
169 return Debug::UncheckedDynamicPointerCast<REP_SUB_TYPE> (this->fIterableEnvelope_->_fRep.cget_ptr ());
177 template <
typename T>
178 template <
typename REP_SUB_TYPE>
188 template <
typename T>
189 template <
typename REP_SUB_TYPE>
190 inline Iterable<T>::_SafeReadWriteRepAccessor<REP_SUB_TYPE>::_SafeReadWriteRepAccessor (_SafeReadWriteRepAccessor&&
from)
191 : fRepReference_{
from.fRepReference_}
194 , fIterableEnvelope_{
from.fIterableEnvelope_}
199#if qStroika_Foundation_Debug_AssertionsChecked
200 from.fIterableEnvelope_ =
nullptr;
202 from.fRepReference_ =
nullptr;
204 template <
typename T>
205 template <
typename REP_SUB_TYPE>
206 inline auto Iterable<T>::_SafeReadWriteRepAccessor<REP_SUB_TYPE>::operator= (_SafeReadWriteRepAccessor&&
rhs)
noexcept -> _SafeReadWriteRepAccessor&
208 fRepReference_ =
rhs.fRepReference_;
210#if qStroika_Foundation_Debug_AssertionsChecked
212 this->fIterableEnvelope_ =
rhs.fIterableEnvelope_;
213 rhs.fIterableEnvelope_ =
nullptr;
217 template <
typename T>
218 template <
typename REP_SUB_TYPE>
219 inline const REP_SUB_TYPE& Iterable<T>::_SafeReadWriteRepAccessor<REP_SUB_TYPE>::_ConstGetRep ()
const
222 return *fRepReference_;
224 template <
typename T>
225 template <
typename REP_SUB_TYPE>
226 inline REP_SUB_TYPE& Iterable<T>::_SafeReadWriteRepAccessor<REP_SUB_TYPE>::_GetWriteableRep ()
229#if qStroika_Foundation_Debug_AssertionsChecked
232 Ensure (fIterableEnvelope_->_fRep.use_count () == 1);
234 return *fRepReference_;
242 template <
typename T>
248 template <
typename T>
253 Require (rep ==
nullptr);
255#if !qCompilerAndStdLib_RequiresNotMatchInlineOutOfLineForTemplateClassBeingDefined_Buggy
256 template <
typename T>
257 template <IIterableOfTo<T> CONTAINER_OF_T>
265 template <
typename T>
270 template <
typename T>
275 template <
typename T>
280 template <
typename T>
281 template <
typename CONTAINER_OF_T>
282 Iterable<T> Iterable<T>::mk_ (CONTAINER_OF_T&& from)
283 requires (copyable<remove_cvref_t<CONTAINER_OF_T>> or same_as<remove_cvref_t<CONTAINER_OF_T>, initializer_list<T>>)
285 using DECAYED_CONTAINER = remove_cvref_t<CONTAINER_OF_T>;
287 using USE_CONTAINER_TYPE =
288 conditional_t<copy_constructible<DECAYED_CONTAINER> and not same_as<DECAYED_CONTAINER, initializer_list<T>>, DECAYED_CONTAINER, vector<T>>;
289 auto sharedCopyOfContainer = Memory::MakeSharedPtr<USE_CONTAINER_TYPE> (forward<CONTAINER_OF_T> (from));
291 function<optional<T> ()> getNext = [sharedCopyOfContainer, i = sharedCopyOfContainer->begin ()] ()
mutable -> optional<T> {
292 if (i != sharedCopyOfContainer->end ()) {
297 return CreateGenerator (getNext);
299 template <
typename T>
302 return _fRep.GetSharingState ();
304 template <
typename T>
308 return accessor._ConstGetRep ().MakeIterator ();
310 template <
typename T>
313 _SafeReadRepAccessor<> accessor{
this};
314 return accessor._ConstGetRep ().size ();
316 template <
typename T>
320 return accessor._ConstGetRep ().empty ();
322 template <
typename T>
323 template <Common::IPotentiallyComparer<T> EQUALS_COMPARER>
344 _SafeReadRepAccessor<> accessor{
this};
345 if (
auto s = accessor._ConstGetRep ().PeekContiguousStorage ()) {
346 if constexpr (same_as<remove_cvref_t<EQUALS_COMPARER>, equal_to<T>> or same_as<remove_cvref_t<EQUALS_COMPARER>, equal_to<>>) {
347 return std::find (s->begin (), s->end (), element) != s->end ();
350 return std::find_if (s->begin (), s->end (), [&] (
const T& i) { return equalsComparer (i, element); }) != s->end ();
355 return static_cast<bool> (
356 this->Find ([&element, &equalsComparer] (ArgByValueType<T> i) ->
bool {
return equalsComparer (i, element); }));
358 template <
typename T>
359 template <ranges::range LHS_CONTAINER_TYPE, ranges::range RHS_CONTAINER_TYPE, Common::IEqualsComparer<T> EQUALS_COMPARER>
360 bool Iterable<T>::SetEquals (
const LHS_CONTAINER_TYPE& lhs,
const RHS_CONTAINER_TYPE& rhs, EQUALS_COMPARER&& equalsComparer)
367 for (
const auto& ti : lhs) {
368 bool contained =
false;
369 for (
const auto& ri : rhs) {
370 if (equalsComparer (ti, ri)) {
379 for (
const auto& ri : rhs) {
380 bool contained =
false;
381 for (
const auto& ti : lhs) {
382 if (equalsComparer (ti, ri)) {
393 template <
typename T>
394 template <ranges::range RHS_CONTAINER_TYPE, Common::IEqualsComparer<T> EQUALS_COMPARER>
395 inline bool Iterable<T>::SetEquals (
const RHS_CONTAINER_TYPE& rhs, EQUALS_COMPARER&& equalsComparer)
const
397 return SetEquals (*
this, rhs, forward<EQUALS_COMPARER> (equalsComparer));
399 template <
typename T>
400 template <ranges::range LHS_CONTAINER_TYPE, ranges::range RHS_CONTAINER_TYPE, Common::IEqualsComparer<T> EQUALS_COMPARER>
403 auto tallyOf = [&equalsComparer] (
const auto& c, ArgByValueType<T> item) ->
size_t {
405 for (
const auto& ti : c) {
406 if (equalsComparer (ti, item)) {
416 for (
const auto& ti : lhs) {
417 if (tallyOf (lhs, ti) != tallyOf (rhs, ti)) {
421 for (
const auto& ti : rhs) {
422 if (tallyOf (lhs, ti) != tallyOf (rhs, ti)) {
428 template <
typename T>
429 template <ranges::range RHS_CONTAINER_TYPE, Common::IEqualsComparer<T> EQUALS_COMPARER>
432 return MultiSetEquals (*
this, rhs, equalsComparer);
434 template <
typename T>
435 template <ranges::range LHS_CONTAINER_TYPE, ranges::range RHS_CONTAINER_TYPE, Common::IEqualsComparer<T> EQUALS_COMPARER>
460 using LHS_ = remove_cvref_t<LHS_CONTAINER_TYPE>;
461 using RHS_ = remove_cvref_t<RHS_CONTAINER_TYPE>;
462 constexpr bool kLHSIsIterable_ = derived_from<LHS_, Iterable<T>>;
463 constexpr bool kRHSIsIterable_ = derived_from<RHS_, Iterable<T>>;
464 constexpr bool kLHSIsContiguous_ =
465 not kLHSIsIterable_ and ranges::contiguous_range<LHS_> and same_as<remove_cvref_t<ranges::range_value_t<LHS_>>, T>;
466 constexpr bool kRHSIsContiguous_ =
467 not kRHSIsIterable_ and ranges::contiguous_range<RHS_> and same_as<remove_cvref_t<ranges::range_value_t<RHS_>>, T>;
468 if constexpr ((kLHSIsIterable_ or kLHSIsContiguous_) and (kRHSIsIterable_ or kRHSIsContiguous_)) {
469 auto spansEqual_ = [&] (span<const T> l, span<const T> r) ->
bool {
470 if (l.size () != r.size ()) {
475 if constexpr (same_as<remove_cvref_t<EQUALS_COMPARER>, equal_to<T>> or same_as<remove_cvref_t<EQUALS_COMPARER>, equal_to<>>) {
476 return std::equal (l.begin (), l.end (), r.begin ());
479 return std::equal (l.begin (), l.end (), r.begin (), equalsComparer);
484 auto withLHSSpan_ = [&] (span<const T> l) -> optional<bool> {
485 if constexpr (kRHSIsIterable_) {
486 _SafeReadRepAccessor<> rhsAccessor{&rhs};
487 if (
auto rs = rhsAccessor._ConstGetRep ().PeekContiguousStorage ()) {
488 return spansEqual_ (l, *rs);
493 return spansEqual_ (l, span<const T>{ranges::data (rhs), ranges::size (rhs)});
496 if constexpr (kLHSIsIterable_) {
497 _SafeReadRepAccessor<> lhsAccessor{&lhs};
498 if (
auto ls = lhsAccessor._ConstGetRep ().PeekContiguousStorage ()) {
499 if (
auto result = withLHSSpan_ (*ls)) {
505 if (
auto result = withLHSSpan_ (span<const T>{ranges::data (lhs), ranges::size (lhs)})) {
511 auto li{lhs.begin ()};
512 auto ri{rhs.begin ()};
515 for (; li != le and ri != re; ++ri, ++li) {
516 if (not equalsComparer (*li, *ri)) {
521 Assert (li == le or ri == re);
523 return li == le and ri == re;
525 template <
typename T>
526 template <ranges::range RHS_CONTAINER_TYPE, Common::IEqualsComparer<T> EQUALS_COMPARER>
529 return SequentialEquals (*
this, rhs, forward<EQUALS_COMPARER> (equalsComparer));
531 DISABLE_COMPILER_MSC_WARNING_START (4996)
532 DISABLE_COMPILER_CLANG_WARNING_START ("clang diagnostic ignored \"-Wdeprecated-declarations\"")
533 DISABLE_COMPILER_GCC_WARNING_START ("GCC diagnostic ignored \"-Wdeprecated-declarations\"")
534 template <typename T>
535 template <ranges::range LHS_CONTAINER_TYPE, ranges::range RHS_CONTAINER_TYPE, Common::IEqualsComparer<T> EQUALS_COMPARER>
536 inline
bool Iterable<T>::SequentialEquals (const LHS_CONTAINER_TYPE& lhs, const RHS_CONTAINER_TYPE& rhs,
537 EQUALS_COMPARER&& equalsComparer, [[maybe_unused]]
bool useIterableSize)
541 return SequentialEquals (lhs, rhs, forward<EQUALS_COMPARER> (equalsComparer));
543 template <
typename T>
544 template <ranges::range RHS_CONTAINER_TYPE, Common::IEqualsComparer<T> EQUALS_COMPARER>
545 inline bool Iterable<T>::SequentialEquals (
const RHS_CONTAINER_TYPE& rhs, EQUALS_COMPARER&& equalsComparer, [[maybe_unused]]
bool useIterableSize)
const
547 return SequentialEquals (*
this, rhs, forward<EQUALS_COMPARER> (equalsComparer));
549 DISABLE_COMPILER_GCC_WARNING_END (
"GCC diagnostic ignored \"-Wdeprecated-declarations\"")
550 DISABLE_COMPILER_CLANG_WARNING_END ("clang diagnostic ignored \"-Wdeprecated-declarations\"")
551 DISABLE_COMPILER_MSC_WARNING_END (4996)
552 template <typename T>
553#if qCompilerAndStdLib_RequiresNotMatchInlineOutOfLineForTemplateClassBeingDefined_Buggy
554 template <
typename RESULT_CONTAINER, predicate<T> INCLUDE_PREDICATE>
556 template <derived_from<Iterable<T>> RESULT_CONTAINER, predicate<T> INCLUDE_PREDICATE>
563 if constexpr (same_as<RESULT_CONTAINER, Iterable<T>>) {
565 auto sharedContext = Memory::MakeSharedPtr<Iterable<T>> (*this);
568 function<optional<T> ()> getNext = [sharedContext, i = sharedContext->MakeIterator (), includeIfTrue] ()
mutable -> optional<T> {
569 while (i and not includeIfTrue (*i)) {
582 return Where<RESULT_CONTAINER> (forward<INCLUDE_PREDICATE> (includeIfTrue), RESULT_CONTAINER{});
585 template <
typename T>
586#if qCompilerAndStdLib_RequiresNotMatchInlineOutOfLineForTemplateClassBeingDefined_Buggy
587 template <
typename RESULT_CONTAINER, predicate<T> INCLUDE_PREDICATE>
589 template <derived_from<Iterable<T>> RESULT_CONTAINER, predicate<T> INCLUDE_PREDICATE>
591 RESULT_CONTAINER
Iterable<T>::Where (INCLUDE_PREDICATE&& includeIfTrue, [[maybe_unused]] RESULT_CONTAINER&& emptyResult)
const
593 if constexpr (same_as<RESULT_CONTAINER, Iterable<T>>) {
595 return Where<RESULT_CONTAINER> (forward<INCLUDE_PREDICATE> (includeIfTrue));
598 Require (emptyResult.empty ());
599 RESULT_CONTAINER result = forward<RESULT_CONTAINER> (emptyResult);
600 this->Apply ([&result, &includeIfTrue] (ArgByValueType<T> arg) {
601 if (includeIfTrue (arg)) {
608 template <
typename T>
609 template <Common::IPotentiallyComparer<T> EQUALS_COMPARER>
613 if constexpr (same_as<equal_to<T>, EQUALS_COMPARER> and is_invocable_v<less<T>>) {
614 set<T> t1{begin (), end ()};
615 tmp = vector<T>{t1.
begin (), t1.end ()};
618 for (
const auto& i : *this) {
619 if (find_if (tmp.begin (), tmp.end (), [&] (ArgByValueType<T> n) { return equalsComparer (n, i); }) == tmp.end ()) {
624 function<optional<T> ()> getNext = [container = move (tmp), idx =
size_t{0}] ()
mutable -> optional<T> {
625 if (idx < container.size ()) {
626 return container[idx++];
632 return CreateGenerator (getNext);
634 template <
typename T>
635 template <
typename RESULT, Common::IPotentiallyComparer<T> EQUALS_COMPARER>
636 Iterable<RESULT>
Iterable<T>::Distinct (
const function<RESULT (ArgByValueType<T>)>& extractElt, EQUALS_COMPARER&& equalsComparer)
const
640 if constexpr (same_as<equal_to<T>, EQUALS_COMPARER> and is_invocable_v<less<T>>) {
642 for (
const T& i : *this) {
643 t1.add (extractElt (i));
645 tmp = vector<RESULT>{t1.begin (), t1.end ()};
648 for (
const T& i : *this) {
649 RESULT item2Test = extractElt (i);
650 if (find_if (tmp.begin (), tmp.end (), [&] (ArgByValueType<T> n) { return equalsComparer (n, item2Test); }) == tmp.end ()) {
651 tmp.push_back (item2Test);
655 function<optional<RESULT> ()> getNext = [container = move (tmp), idx =
size_t{0}] ()
mutable -> optional<RESULT> {
656 if (idx < container.size ()) {
657 return container[idx++];
665 template <
typename T>
666 template <ranges::range RESULT_CONTAINER, invocable<T> ELEMENT_MAPPER>
668 requires (convertible_to<invoke_result_t<ELEMENT_MAPPER, T>,
typename RESULT_CONTAINER::value_type> or
669 convertible_to<invoke_result_t<ELEMENT_MAPPER, T>, optional<typename RESULT_CONTAINER::value_type>>)
671 using RESULT_ELEMENT =
typename RESULT_CONTAINER::value_type;
672 constexpr bool kLazyEvaluateIteration_ = same_as<RESULT_CONTAINER, Iterable<RESULT_ELEMENT>>;
673 [[maybe_unused]]
constexpr bool kOptionalExtractor_ =
674 not convertible_to<invoke_result_t<ELEMENT_MAPPER, T>,
typename RESULT_CONTAINER::value_type> and
675 convertible_to<invoke_result_t<ELEMENT_MAPPER, T>, optional<typename RESULT_CONTAINER::value_type>>;
676 if constexpr (kLazyEvaluateIteration_) {
678 auto sharedContext = Memory::MakeSharedPtr<Iterable<T>> (*this);
680 function<optional<RESULT_ELEMENT> ()> getNext = [sharedContext, i = sharedContext->MakeIterator (),
681 elementMapper] ()
mutable -> optional<RESULT_ELEMENT> {
684 if constexpr (kOptionalExtractor_) {
686 optional<RESULT_ELEMENT> t = elementMapper (*i);
696 RESULT_ELEMENT result = elementMapper (*i);
698 return move (result);
707 return this->Map<RESULT_CONTAINER> (forward<ELEMENT_MAPPER> (elementMapper), RESULT_CONTAINER{});
710 template <
typename T>
711 template <ranges::range RESULT_CONTAINER, invocable<T> ELEMENT_MAPPER>
712 RESULT_CONTAINER
Iterable<T>::Map (ELEMENT_MAPPER&& elementMapper, RESULT_CONTAINER&& emptyResult)
const
713 requires (convertible_to<invoke_result_t<ELEMENT_MAPPER, T>,
typename RESULT_CONTAINER::value_type> or
714 convertible_to<invoke_result_t<ELEMENT_MAPPER, T>, optional<typename RESULT_CONTAINER::value_type>>)
716 using RESULT_ELEMENT =
typename RESULT_CONTAINER::value_type;
717 constexpr bool kLazyEvaluateIteration_ = same_as<RESULT_CONTAINER, Iterable<RESULT_ELEMENT>>;
718 constexpr bool kOptionalExtractor_ = not convertible_to<invoke_result_t<ELEMENT_MAPPER, T>,
typename RESULT_CONTAINER::value_type> and
719 convertible_to<invoke_result_t<ELEMENT_MAPPER, T>, optional<typename RESULT_CONTAINER::value_type>>;
720 if constexpr (kLazyEvaluateIteration_) {
721 return this->Map<RESULT_CONTAINER> (forward<ELEMENT_MAPPER> (elementMapper));
724 RESULT_CONTAINER c = forward<RESULT_CONTAINER> (emptyResult);
739 if constexpr (not kOptionalExtractor_ and
requires (RESULT_CONTAINER p) { p.reserve (3u); }) {
740 c.reserve (this->size ());
742 this->Apply ([&c, &elementMapper] (ArgByValueType<T> arg) {
743 if constexpr (kOptionalExtractor_) {
744 if (
auto oarg = elementMapper (arg)) {
745 Containers::Adapters::Adder<RESULT_CONTAINER>::Add (&c, *oarg);
749 Containers::Adapters::Adder<RESULT_CONTAINER>::Add (&c, elementMapper (arg));
755 template <
typename T>
756 template <
typename RESULT_T, invocable<T> CONVERT_TO_RESULT, invocable<RESULT_T, RESULT_T,
bool> COMBINER>
757 RESULT_T
Iterable<T>::Join (
const CONVERT_TO_RESULT& convertToResult,
const COMBINER& combiner)
const
758 requires (convertible_to<invoke_result_t<CONVERT_TO_RESULT, T>, RESULT_T> and
759 convertible_to<invoke_result_t<COMBINER, RESULT_T, RESULT_T, bool>, RESULT_T>)
763 size_t cnt = this->size ();
764 for (
auto i : *this) {
766 result = convertToResult (i);
769 result = combiner (result, convertToResult (i), idx + 1 == cnt);
775 template <
typename T>
779 auto sharedContext = Memory::MakeSharedPtr<Iterable<T>> (*this);
783 function<optional<T> ()> getNext = [sharedContext, i = sharedContext->MakeIterator (),
784 perIteratorContextNItemsToSkip = nItems] ()
mutable -> optional<T> {
785 while (i and perIteratorContextNItemsToSkip > 0) {
786 --perIteratorContextNItemsToSkip;
792 return move (result);
798 template <
typename T>
802 auto sharedContext = Memory::MakeSharedPtr<Iterable<T>> (*this);
806 function<optional<T> ()> getNext = [sharedContext, i = sharedContext->MakeIterator (),
807 perIteratorContextNItemsToTake = nItems] ()
mutable -> optional<T> {
808 if (perIteratorContextNItemsToTake == 0) {
811 perIteratorContextNItemsToTake--;
815 return move (result);
821 template <
typename T>
825 auto sharedContext = Memory::MakeSharedPtr<Iterable<T>> (*this);
830 function<optional<T> ()> getNext = [sharedContext, i = sharedContext->MakeIterator (), perIteratorContextNItemsToSkip = from,
831 perIteratorContextNItemsToTake = to - from] ()
mutable -> optional<T> {
832 while (i and perIteratorContextNItemsToSkip > 0) {
833 --perIteratorContextNItemsToSkip;
836 if (perIteratorContextNItemsToTake == 0) {
839 perIteratorContextNItemsToTake--;
843 return move (result);
849 template <
typename T>
850 template <Common::IPotentiallyComparer<T> COMPARER>
870 auto i = min_element (begin (), endI, forward<COMPARER> (cmp));
876 template <
typename T>
877 template <Common::IPotentiallyComparer<T> COMPARER>
880 vector<T> tmp = this->As<vector<T>> ();
883 n = min (n, tmp.size ());
884 partial_sort (tmp.begin (), tmp.begin () + n, tmp.end (), forward<COMPARER> (cmp));
886 tmp.erase (tmp.begin () + n, tmp.end ());
887 function<optional<T> ()> getNext = [tmp, idx] ()
mutable -> optional<T> {
888 if (idx < tmp.size ()) {
897 template <
typename T>
900 return Top (std::greater<T>{});
902 template <
typename T>
905 return Top (n, std::greater<T>{});
907 template <
typename T>
908 template <Common::IPotentiallyComparer<T> INORDER_COMPARER_TYPE>
914 template <
typename T>
915 template <Common::IPotentiallyComparer<T> INORDER_COMPARER_TYPE>
918 vector<T> tmp = this->As<vector<T>> ();
920#if __cpp_lib_execution >= 201603L
924 stable_sort (execution::par, tmp.begin (), tmp.end (), forward<INORDER_COMPARER_TYPE> (inorderComparer));
929 stable_sort (tmp.begin (), tmp.end (), forward<INORDER_COMPARER_TYPE> (inorderComparer));
947 struct SortedRep_ : Iterable<T>::_IRep, Memory::UseBlockAllocationIfAppropriate<SortedRep_> {
948 shared_ptr<const vector<T>> fData_;
949 SortedRep_ (vector<T>&& data)
953 virtual Iterator<T> MakeIterator ()
const override
956 return CreateGeneratorIterator<T> ([data = fData_, idx =
size_t{0}] ()
mutable -> optional<T> {
957 return idx < data->size () ? optional<T>{(*data)[idx++]} : nullopt;
960 virtual size_t size ()
const override
962 return fData_->size ();
964 virtual bool empty ()
const override
966 return fData_->empty ();
968 virtual optional<span<const T>> PeekContiguousStorage ()
const override
970 return span<const T>{*fData_};
972 virtual shared_ptr<typename Iterable<T>::_IRep> Clone ()
const override
974 return Memory::MakeSharedPtr<SortedRep_> (*
this);
977 return Iterable<T>{Memory::MakeSharedPtr<SortedRep_> (move (tmp))};
979 template <
typename T>
980 template <Common::IPotentiallyComparer<T> INORDER_COMPARER_TYPE>
984 for (
const T& i : *this) {
985 if (last.has_value ()) [[likely]] {
987 if (inorderComparer (i, *last)) [[unlikely]] {
995 template <
typename T>
999 return i ? *i : optional<T>{};
1001 template <
typename T>
1002 template <invocable<T> F>
1004 requires (convertible_to<invoke_result_t<F, T>,
bool>)
1006 constexpr bool kUseIterableRepIteration_ =
true;
1007 if (kUseIterableRepIteration_) {
1009 return t ? optional<T>{*t} : optional<T>{};
1012 for (
const auto& i : *this) {
1020 template <
typename T>
1021 template <
typename RESULT_T>
1022 inline optional<RESULT_T>
Iterable<T>::First (
const function<optional<RESULT_T> (ArgByValueType<T>)>& that)
const
1025 constexpr bool kUseIterableRepIteration_ =
true;
1026 if (kUseIterableRepIteration_) {
1027 optional<RESULT_T> result;
1028 auto f = [&that, &result] (ArgByValueType<T> i) {
return (result = that (i)).has_value (); };
1029 _SafeReadRepAccessor<_IRep> accessor{
this};
1031 return t ? result : optional<RESULT_T>{};
1034 for (
const auto& i : *this) {
1035 if (
auto r = that (i)) {
1042 template <
typename T>
1045 return this->First ().value_or (defaultValue);
1047 template <
typename T>
1048 template <invocable<T> F>
1050 requires (convertible_to<invoke_result_t<F, T>,
bool>)
1052 return this->First (forward<F> (that)).value_or (defaultValue);
1054 template <
typename T>
1068 template <
typename T>
1069 template <invocable<T> F>
1071 requires (convertible_to<invoke_result_t<F, T>,
bool>)
1074 for (
const auto& i : *this) {
1081 template <
typename T>
1082 template <
typename RESULT_T>
1083 inline optional<RESULT_T>
Iterable<T>::Last (
const function<optional<RESULT_T> (ArgByValueType<T>)>& that)
const
1087 for (
const auto& i : *this) {
1088 if (
auto o = that (i)) {
1094 template <
typename T>
1097 return this->Last ().value_or (defaultValue);
1099 template <
typename T>
1100 template <invocable<T> F>
1102 requires (convertible_to<invoke_result_t<F, T>,
bool>)
1104 return this->Last (forward<F> (that)).value_or (defaultValue);
1106 template <
typename T>
1110 for (
const auto& i : *
this) {
1111 if (not testEachElt (i)) {
1117 template <
typename T>
1118 template <
typename REDUCED_TYPE>
1119 optional<REDUCED_TYPE>
Iterable<T>::Reduce (
const function<REDUCED_TYPE (ArgByValueType<T>, ArgByValueType<T>)>& op)
const
1121 optional<REDUCED_TYPE> result;
1122 for (
const auto& i : *
this) {
1127 result = op (*result, i);
1135 template <
typename T>
1136 template <
typename REDUCED_TYPE>
1137 inline REDUCED_TYPE
Iterable<T>::ReduceValue (
const function<REDUCED_TYPE (ArgByValueType<T>, ArgByValueType<T>)>& op,
1138 ArgByValueType<REDUCED_TYPE> defaultValue)
const
1140 return Reduce<REDUCED_TYPE> (op).value_or (defaultValue);
1142 template <
typename T>
1151 if (
auto s = accessor._ConstGetRep ().PeekContiguousStorage ()) {
1152 if (s->empty ()) [[unlikely]] {
1155 return *min_element (s->begin (), s->end ());
1158 return Reduce<T> ([] (ArgByValueType<T> lhs, ArgByValueType<T> rhs) -> T {
return min (lhs, rhs); });
1160 template <
typename T>
1161 template <
typename RESULT_TYPE>
1164 return Min ().value_or (defaultValue);
1166 template <
typename T>
1182 if (
auto s = accessor._ConstGetRep ().PeekContiguousStorage ()) {
1183 if (s->empty ()) [[unlikely]] {
1186 return *max_element (s->begin (), s->end ());
1189 return Reduce<T> ([] (ArgByValueType<T> lhs, ArgByValueType<T> rhs) -> T {
return max (lhs, rhs); });
1191 template <
typename T>
1192 template <
typename RESULT_TYPE>
1195 return Max ().value_or (defaultValue);
1197 template <
typename T>
1198 template <
typename RESULT_TYPE>
1202 if (i == end ()) [[unlikely]] {
1205 return Math::Mean (i, end ());
1207 template <
typename T>
1208 template <
typename RESULT_TYPE>
1211 return Mean ().value_or (defaultValue);
1213 template <
typename T>
1214 template <
typename RESULT_TYPE>
1225 if constexpr (same_as<RESULT_TYPE, T>) {
1226 _SafeReadRepAccessor<> accessor{
this};
1227 if (
auto s = accessor._ConstGetRep ().PeekContiguousStorage ()) {
1228 if (s->empty ()) [[unlikely]] {
1231 T total = *s->begin ();
1232 for (
auto i = s->begin () + 1; i != s->end (); ++i) {
1238 return Reduce<RESULT_TYPE> ([] (ArgByValueType<T> lhs, ArgByValueType<T> rhs) {
return lhs + rhs; });
1240 template <
typename T>
1241 template <
typename RESULT_TYPE>
1244 return Sum ().value_or (defaultValue);
1246 template <
typename T>
1247 template <constructible_from<T> RESULT_TYPE, Common::IPotentiallyComparer<RESULT_TYPE> INORDER_COMPARE_FUNCTION>
1248 inline optional<RESULT_TYPE>
Iterable<T>::Median (
const INORDER_COMPARE_FUNCTION& compare)
const
1250 Iterator<T> i = begin ();
1251 if (i == end ()) [[unlikely]] {
1254 return Math::Median<RESULT_TYPE> (i, end (), compare);
1256 template <
typename T>
1257 template <constructible_from<T> RESULT_TYPE>
1260 return Median ().value_or (defaultValue);
1262 template <
typename T>
1272 vector<T> origList = this->As<vector<T>> ();
1273 size_t repeatCountIndex{1};
1274 size_t innerIndex{0};
1275 function<optional<T> ()> getNext = [origList, repeatCountIndex, innerIndex, count] ()
mutable -> optional<T> {
1277 if (innerIndex < origList.size ()) [[likely]] {
1278 return origList[innerIndex++];
1280 if (repeatCountIndex < count) [[likely]] {
1291 template <
typename T>
1294 return not empty ();
1296 template <
typename T>
1297 inline bool Iterable<T>::Any (
const function<
bool (ArgByValueType<T>)>& includeIfTrue)
const
1299 return static_cast<bool> (Find (includeIfTrue));
1301 template <
typename T>
1306 template <
typename T>
1307 inline size_t Iterable<T>::Count (
const function<
bool (ArgByValueType<T>)>& includeIfTrue)
const
1310 Apply ([&] (ArgByValueType<T> a) {
1311 if (includeIfTrue (a))
1314 Ensure (cnt == Where (includeIfTrue).size ());
1317 template <
typename T>
1322 template <
typename T>
1325 return MakeIterator ();
1327 template <
typename T>
1332 template <
typename T>
1338 template <
typename T>
1342 _SafeReadRepAccessor<> accessor{
this};
1343 accessor._ConstGetRep ().Apply (doToElement, seq);
1345 template <
typename T>
1346 template <predicate<T> THAT_FUNCTION>
1352 template <
typename T>
1353 template <predicate<T> THAT_FUNCTION>
1358 _SafeReadRepAccessor<> accessor{
this};
1359 return accessor._ConstGetRep ().Find (
false, forward<THAT_FUNCTION> (that), seq);
1361 template <
typename T>
1362 template <Common::IPotentiallyComparer<T> EQUALS_COMPARER>
1363 inline Iterator<T>
Iterable<T>::Find (ArgByValueType<T> v, EQUALS_COMPARER&& equalsComparer)
const
1368 template <
typename T>
1369 template <Common::IPotentiallyComparer<T> EQUALS_COMPARER>
1386 _SafeReadRepAccessor<> accessor{
this};
1387 return accessor._ConstGetRep ().Find_equal_to (v, seq);
1390 return Find ([v, equalsComparer] (ArgByValueType<T> arg) {
return equalsComparer (v, arg); }, seq);
1393 template <
typename T>
1394 template <predicate<T> THAT_FUNCTION>
1395 inline Iterator<T>
Iterable<T>::Find (
const Iterator<T>& startAt, THAT_FUNCTION&& that)
const
1400 template <
typename T>
1401 template <predicate<T> THAT_FUNCTION>
1404 for (Iterator<T> i = startAt; i != end (); ++i) {
1405 if (forward<THAT_FUNCTION> (that) (*i)) [[unlikely]] {
1411 template <
typename T>
1412 template <Common::IPotentiallyComparer<T> EQUALS_COMPARER>
1418 template <
typename T>
1419 template <Common::IPotentiallyComparer<T> EQUALS_COMPARER>
1420 Iterator<T>
Iterable<T>::Find (
const Iterator<T>& startAt, ArgByValueType<T> v, EQUALS_COMPARER&& equalsComparer,
1423 for (Iterator<T> i = startAt; i != end (); ++i) {
1424 if (forward<EQUALS_COMPARER> (equalsComparer) (v, *i)) [[unlikely]] {
1430 template <
typename T>
1431 template <IIterableOfFrom<T> CONTAINER_OF_T,
typename... CONTAINER_OF_T_CONSTRUCTOR_ARGS>
1454 using ContiguousIterator_ =
typename span<const T>::iterator;
1455 if constexpr (constructible_from<CONTAINER_OF_T, CONTAINER_OF_T_CONSTRUCTOR_ARGS..., ContiguousIterator_, ContiguousIterator_>) {
1456 _SafeReadRepAccessor<> accessor{
this};
1457 if (
auto s = accessor._ConstGetRep ().PeekContiguousStorage ()) {
1458 return CONTAINER_OF_T (forward<CONTAINER_OF_T_CONSTRUCTOR_ARGS> (args)..., s->begin (), s->end ());
1463 if constexpr (derived_from<CONTAINER_OF_T, Iterable<T>>) {
1464 return CONTAINER_OF_T (forward<CONTAINER_OF_T_CONSTRUCTOR_ARGS> (args)..., begin (), end ());
1467 return CONTAINER_OF_T (forward<CONTAINER_OF_T_CONSTRUCTOR_ARGS> (args)..., begin (), Iterator<T>{end ()});
1470 template <
typename T>
1473 Require (n <
static_cast<ptrdiff_t
> (size ()));
1474 Require (n > -
static_cast<ptrdiff_t
> (size ()));
1475 size_t useIndex = n >= 0 ?
static_cast<size_t> (n) :
static_cast<size_t> (n +
static_cast<ptrdiff_t
> (size ()));
1476 size_t idx = useIndex;
1477 for (
const T& i : *
this) {
1486 template <
typename T>
1489 size_t useIndex = n >= 0 ?
static_cast<size_t> (n) :
static_cast<size_t> (n +
static_cast<ptrdiff_t
> (size ()));
1490 size_t idx = useIndex;
1491 for (
const T& i : *
this) {
1497 return defaultValue;
1505 template <
typename T>
1506 template <qCompilerAndStdLib_Constra
intDiffersInTemplateRedeclaration_BWA (IEqualsComparer<T>) T_EQUALS_COMPARER>
1508 : fElementComparer{elementEqualsComparer}
1511 DISABLE_COMPILER_MSC_WARNING_START (4996)
1512 DISABLE_COMPILER_CLANG_WARNING_START ("clang diagnostic ignored \"-Wdeprecated-declarations\"")
1513 DISABLE_COMPILER_GCC_WARNING_START ("GCC diagnostic ignored \"-Wdeprecated-declarations\"")
1514 template <typename T>
1515 template <qCompilerAndStdLib_ConstraintDiffersInTemplateRedeclaration_BWA (IEqualsComparer<T>) T_EQUALS_COMPARER>
1516 constexpr Iterable<T>::SequentialEqualsComparer<T_EQUALS_COMPARER>::SequentialEqualsComparer (const T_EQUALS_COMPARER& elementEqualsComparer,
1517 [[maybe_unused]]
bool useIterableSize)
1518 : fElementComparer{elementEqualsComparer}
1521 DISABLE_COMPILER_GCC_WARNING_END (
"GCC diagnostic ignored \"-Wdeprecated-declarations\"")
1522 DISABLE_COMPILER_CLANG_WARNING_END ("clang diagnostic ignored \"-Wdeprecated-declarations\"")
1523 DISABLE_COMPILER_MSC_WARNING_END (4996)
1524 template <typename T>
1525 template <qCompilerAndStdLib_ConstraintDiffersInTemplateRedeclaration_BWA (IEqualsComparer<T>) T_EQUALS_COMPARER>
1526 inline
bool Iterable<T>::SequentialEqualsComparer<T_EQUALS_COMPARER>::operator() (const Iterable& lhs, const Iterable& rhs)
const
1528 return SequentialEquals (lhs, rhs, fElementComparer);
1536 template <
typename T>
1537 template <qCompilerAndStdLib_Constra
intDiffersInTemplateRedeclaration_BWA (IThreeWayComparer<T>) T_THREEWAY_COMPARER>
1539 : fElementComparer{elementComparer}
1542 DISABLE_COMPILER_MSC_WARNING_START (4701)
1543 template <typename T>
1544 template <qCompilerAndStdLib_ConstraintDiffersInTemplateRedeclaration_BWA (IThreeWayComparer<T>) T_THREEWAY_COMPARER>
1545 inline auto
Iterable<T>::SequentialThreeWayComparer<T_THREEWAY_COMPARER>::operator() (const
Iterable& lhs, const
Iterable& rhs)
const
1547 auto li = lhs.
begin ();
1548 auto le = lhs.end ();
1549 auto ri = rhs.begin ();
1550 auto re = rhs.end ();
1551 DISABLE_COMPILER_MSC_WARNING_START (6001)
1552 DISABLE_COMPILER_GCC_WARNING_START ("GCC diagnostic ignored \"-Wmaybe-uninitialized\"")
1555 optional<strong_ordering> c;
1556 while ((li != le) and (ri != re) and (c = fElementComparer (*li, *ri)) == strong_ordering::equal) {
1562 return strong_ordering::equal;
1565 return strong_ordering::less;
1568 else if (ri == re) {
1569 return strong_ordering::greater;
1572 Assert (li != le and ri != re);
1573 Assert (c == fElementComparer (*li, *ri));
1576 DISABLE_COMPILER_GCC_WARNING_END (
"GCC diagnostic ignored \"-Wmaybe-uninitialized\"")
1577 DISABLE_COMPILER_MSC_WARNING_END (6001)
1579 DISABLE_COMPILER_MSC_WARNING_END (4701)
#define RequireNotReached()
#define qStroika_Foundation_Debug_AssertionsChecked
The qStroika_Foundation_Debug_AssertionsChecked flag determines if assertions are checked and validat...
#define RequireNotNull(p)
#define RequireExpression(c)
#define AssertNotReached()
#define EnsureMember(p, c)
auto MakeSharedPtr(ARGS_TYPE &&... args) -> shared_ptr< T >
same as make_shared, but if type T has block allocation, then use block allocation for the 'shared pa...
T UncheckedDynamicCast(T1 &&arg) noexcept
return the same value as dynamic_cast<T> would have, except instead of checking nullptr,...
Iterable< T > CreateGenerator(const function< optional< T >()> &getNext)
Create an Iterable<T> from a function that returns optional<T> - treating nullopt as meaning the END ...
RESULT_TYPE Median(const ITERATOR_OF_T &start, ITERATOR_OF_T2 &&end, INORDER_COMPARE_FUNCTION &&compare={})
Median of a collection of numbers computed.
nonvirtual SharingState GetSharingState() const
virtual Iterator< value_type > MakeIterator() const =0
virtual bool empty() const
virtual void Apply(const function< void(ArgByValueType< T > item)> &doToElement, Execution::SequencePolicy seq) const
virtual optional< span< const value_type > > PeekContiguousStorage() const
Hand back this backend's elements as one contiguous, in-iteration-order block - or nullopt if it has ...
virtual Iterator< value_type > Find_equal_to(const ArgByValueType< T > &v, Execution::SequencePolicy seq) const
virtual size_t size() const
Iterable<T> is a base class for containers which easily produce an Iterator<T> to traverse them.
nonvirtual RESULT_T Join(const CONVERT_TO_RESULT &convertToResult=kDefaultToStringConverter<>, const COMBINER &combiner=Characters::kDefaultStringCombiner) const
ape the JavaScript/python 'join' function - take the parts of 'this' iterable and combine them into a...
nonvirtual RESULT_TYPE MaxValue(ArgByValueType< RESULT_TYPE > defaultValue={}) const
nonvirtual Iterable< T > Slice(size_t from, size_t to) const
static bool SetEquals(const LHS_CONTAINER_TYPE &lhs, const RHS_CONTAINER_TYPE &rhs, EQUALS_COMPARER &&equalsComparer=EQUALS_COMPARER{})
nonvirtual bool Any() const
Any() same as not empty (); Any (includeIfTrue) returns true iff includeIfTrue returns true on any va...
_SharedByValueRepType _fRep
nonvirtual optional< T > Max() const
nonvirtual RESULT_TYPE MedianValue(ArgByValueType< RESULT_TYPE > defaultValue={}) const
nonvirtual optional< RESULT_TYPE > Mean() const
nonvirtual Iterator< T > Find(THAT_FUNCTION &&that) const
Run the argument bool-returning function (or lambda) on the elements of the container,...
nonvirtual size_t length() const
STL-ish alias for size() - really in STL only used in string, I think, but still makes sense as an al...
nonvirtual CONTAINER_OF_T As(CONTAINER_OF_T_CONSTRUCTOR_ARGS... args) const
nonvirtual Iterable< T > Distinct(EQUALS_COMPARER &&equalsComparer=EQUALS_COMPARER{}) const
nonvirtual RESULT_CONTAINER Map(ELEMENT_MAPPER &&elementMapper) const
functional API which iterates over all members of an Iterable, applies a map function to each element...
nonvirtual size_t Count() const
with no args, same as size, with function filter arg, returns number of items that pass.
nonvirtual bool IsOrderedBy(INORDER_COMPARER_TYPE &&inorderComparer=INORDER_COMPARER_TYPE{}) const
nonvirtual Iterable< T > Repeat(size_t count) const
nonvirtual optional< T > First() const
return first element in iterable, or if 'that' specified, first where 'that' is true,...
T value_type
value_type is an alias for the type iterated over - like vector<T>::value_type
nonvirtual RESULT_TYPE MinValue(ArgByValueType< RESULT_TYPE > defaultValue={}) const
nonvirtual bool All(const function< bool(ArgByValueType< T >)> &testEachElt) const
return true iff argument predicate returns true for each element of the iterable
nonvirtual bool Contains(ArgByValueType< T > element, EQUALS_COMPARER &&equalsComparer=EQUALS_COMPARER{}) const
nonvirtual optional< T > Min() const
nonvirtual T NthValue(ptrdiff_t n, ArgByValueType< T > defaultValue={}) const
Find the Nth element of the Iterable<>, but allow for n to be out of range, and just return argument ...
nonvirtual size_t size() const
Returns the number of items contained.
nonvirtual RESULT_CONTAINER Where(INCLUDE_PREDICATE &&includeIfTrue) const
produce a subset of this iterable where argument function returns true
nonvirtual void Apply(const function< void(ArgByValueType< T > item)> &doToElement) const
Run the argument function (or lambda) on each element of the container.
nonvirtual T Nth(ptrdiff_t n) const
Find the Nth element of the Iterable<>
nonvirtual Iterable< T > Take(size_t nItems) const
nonvirtual RESULT_TYPE MeanValue(ArgByValueType< RESULT_TYPE > defaultValue={}) const
nonvirtual optional< RESULT_TYPE > Median(const INORDER_COMPARE_FUNCTION &compare={}) const
nonvirtual Iterable< T > Skip(size_t nItems) const
nonvirtual RESULT_TYPE SumValue(ArgByValueType< RESULT_TYPE > defaultValue={}) const
nonvirtual optional< REDUCED_TYPE > Reduce(const function< REDUCED_TYPE(ArgByValueType< T >, ArgByValueType< T >)> &op) const
Walk the entire list of items, and use the argument 'op' to combine (reduce) items to a resulting sin...
nonvirtual Iterator< T > begin() const
Support for ranged for, and STL syntax in general.
nonvirtual optional< T > Top() const
return the top/largest value (or the top N values) from this Iterable<T>
Iterable(const Iterable &) noexcept=default
Iterable are safely copyable (by value). Since Iterable uses COW, this just copies the underlying poi...
nonvirtual optional< RESULT_TYPE > Sum() const
nonvirtual Memory::SharedByValueSupport::SharingState _GetSharingState() const
static bool SequentialEquals(const LHS_CONTAINER_TYPE &lhs, const RHS_CONTAINER_TYPE &rhs, EQUALS_COMPARER &&equalsComparer=EQUALS_COMPARER{})
nonvirtual bool empty() const
Returns true iff size() == 0.
nonvirtual T LastValue(ArgByValueType< T > defaultValue={}) const
static bool MultiSetEquals(const LHS_CONTAINER_TYPE &lhs, const RHS_CONTAINER_TYPE &rhs, EQUALS_COMPARER &&equalsComparer=EQUALS_COMPARER{})
nonvirtual optional< T > Last() const
return last element in iterable, or if 'that' specified, last where 'that' is true,...
nonvirtual T FirstValue(ArgByValueType< T > defaultValue={}) const
return first element in iterable provided default
static constexpr default_sentinel_t end() noexcept
Support for ranged for, and STL syntax in general.
nonvirtual REDUCED_TYPE ReduceValue(const function< REDUCED_TYPE(ArgByValueType< T >, ArgByValueType< T >)> &op, ArgByValueType< REDUCED_TYPE > defaultValue={}) const
nonvirtual Iterable< T > OrderBy(INORDER_COMPARER_TYPE &&inorderComparer=INORDER_COMPARER_TYPE{}) const
nonvirtual Iterator< T > MakeIterator() const
Create an iterator object which can be used to traverse the 'Iterable'.
An Iterator<T> is a copyable object which allows traversing the contents of some container.
static constexpr default_sentinel_t GetEmptyIterator() noexcept
Used by someContainer::end ()
SequencePolicy
equivalent which of 4 types being used std::execution::sequenced_policy, parallel_policy,...
@ ePar
must synchronize shared data, can use mutex (or atomics), cuz each parallel execution in real thread
@ eSeq
default case - not parallelized
utility for generic code that wishes to add something to a somewhat arbitrary container,...