7#include "Stroika/Foundation/Containers/Adapters/Adder.h"
13namespace Stroika::Foundation::Traversal {
15 constexpr bool kIterableUsesStroikaSharedPtr [[deprecated (
"Since Stroika v3.0d1 - not used")]] =
false;
17 struct [[deprecated (
"Since Stroika v3.0d1")]] IterableBase {
18 template <
typename SHARED_T>
19 using PtrImplementationTemplate [[deprecated (
"Since Stroika v3.0d1 - use shared_ptr directly")]] = shared_ptr<SHARED_T>;
20 template <
typename SHARED_T,
typename... ARGS_TYPE>
21 [[deprecated (
"Since Stroika v3.0d1 - use Memory::MakeSharedPtr directly")]]
static shared_ptr<SHARED_T> MakeSmartPtr (ARGS_TYPE&&... args)
23 return Memory::MakeSharedPtr<SHARED_T> (forward<ARGS_TYPE> (args)...);
25 template <
typename SHARED_T>
26 using enable_shared_from_this_PtrImplementationTemplate [[deprecated (
"Since Stroika v3.0d1")]] = std::enable_shared_from_this<SHARED_T>;
42 this->
Apply ([&sz] (
const T&) { ++sz; }, Execution::SequencePolicy::eDEFAULT);
91 return Find ([&v] (
const T& rhs) {
return equal_to<T>{}(v, rhs); }, seq);
95 if (equal_to<T>{}(v, *i)) {
113 template <
typename T>
114 template <
typename REP_SUB_TYPE>
116 : fConstRef_{Debug::UncheckedDynamicCast<const REP_SUB_TYPE*> (it->_fRep.cget ())}
117 , fIterableEnvelope_{it}
118#if qStroika_Foundation_Debug_AssertionsChecked
119 , fAssertReadLock_{it->_fThisAssertExternallySynchronized}
125 template <
typename T>
126 template <
typename REP_SUB_TYPE>
127 inline Iterable<T>::_SafeReadRepAccessor<REP_SUB_TYPE>::_SafeReadRepAccessor (_SafeReadRepAccessor&& src) noexcept
128 : fConstRef_{src.fConstRef_}
129 , fIterableEnvelope_{src.fIterableEnvelope_}
130#if qStroika_Foundation_Debug_AssertionsChecked
131 , fAssertReadLock_{move (src.fAssertReadLock_)}
136 src.fConstRef_ =
nullptr;
138 template <
typename T>
139 template <
typename REP_SUB_TYPE>
140 inline auto Iterable<T>::_SafeReadRepAccessor<REP_SUB_TYPE>::operator= (_SafeReadRepAccessor&& rhs)
noexcept -> _SafeReadRepAccessor&
142 fConstRef_ = rhs.fConstRef_;
143 this->fIterableEnvelope_ = rhs.fIterableEnvelope_;
144#if qStroika_Foundation_Debug_AssertionsChecked
145 this->fAssertReadLock_ = move (rhs.fAssertReadLock_);
149 template <
typename T>
150 template <
typename REP_SUB_TYPE>
151 inline const REP_SUB_TYPE& Iterable<T>::_SafeReadRepAccessor<REP_SUB_TYPE>::_ConstGetRep () const noexcept
156 template <
typename T>
157 template <
typename REP_SUB_TYPE>
158 inline auto Iterable<T>::_SafeReadRepAccessor<REP_SUB_TYPE>::_ConstGetRepSharedPtr () const noexcept -> shared_ptr<REP_SUB_TYPE>
160 return Debug::UncheckedDynamicPointerCast<REP_SUB_TYPE> (this->fIterableEnvelope_->_fRep.cget_ptr ());
168 template <
typename T>
169 template <
typename REP_SUB_TYPE>
170 inline Iterable<T>::_SafeReadWriteRepAccessor<REP_SUB_TYPE>::_SafeReadWriteRepAccessor (Iterable<T>* iterableEnvelope)
173 , fAssertWriteLock_{iterableEnvelope->_fThisAssertExternallySynchronized}
174 , fIterableEnvelope_{iterableEnvelope}
179 template <
typename T>
180 template <
typename REP_SUB_TYPE>
181 inline Iterable<T>::_SafeReadWriteRepAccessor<REP_SUB_TYPE>::_SafeReadWriteRepAccessor (_SafeReadWriteRepAccessor&& from)
182 : fRepReference_{from.fRepReference_}
184 , fAssertWriteLock_{move (from.fAssertWriteLock_)}
185 , fIterableEnvelope_{from.fIterableEnvelope_}
190#if qStroika_Foundation_Debug_AssertionsChecked
191 from.fIterableEnvelope_ =
nullptr;
193 from.fRepReference_ =
nullptr;
195 template <
typename T>
196 template <
typename REP_SUB_TYPE>
197 inline auto Iterable<T>::_SafeReadWriteRepAccessor<REP_SUB_TYPE>::operator= (_SafeReadWriteRepAccessor&& rhs)
noexcept -> _SafeReadWriteRepAccessor&
199 fRepReference_ = rhs.fRepReference_;
201#if qStroika_Foundation_Debug_AssertionsChecked
202 this->fAssertWriteLock_ = move (rhs.fAssertWriteLock_);
203 this->fIterableEnvelope_ = rhs.fIterableEnvelope_;
204 rhs.fIterableEnvelope_ =
nullptr;
208 template <
typename T>
209 template <
typename REP_SUB_TYPE>
210 inline const REP_SUB_TYPE& Iterable<T>::_SafeReadWriteRepAccessor<REP_SUB_TYPE>::_ConstGetRep ()
const
213 return *fRepReference_;
215 template <
typename T>
216 template <
typename REP_SUB_TYPE>
217 inline REP_SUB_TYPE& Iterable<T>::_SafeReadWriteRepAccessor<REP_SUB_TYPE>::_GetWriteableRep ()
220#if qStroika_Foundation_Debug_AssertionsChecked
223 Ensure (fIterableEnvelope_->_fRep.use_count () == 1);
225 return *fRepReference_;
233 template <
typename T>
239 template <
typename T>
244 Require (rep ==
nullptr);
246#if !qCompilerAndStdLib_RequiresNotMatchInlineOutOfLineForTemplateClassBeingDefined_Buggy
247 template <
typename T>
248 template <IIterableOfTo<T> CONTAINER_OF_T>
250 requires (not derived_from<remove_cvref_t<CONTAINER_OF_T>,
Iterable<T>>)
251 :
_fRep{mk_ (forward<CONTAINER_OF_T> (from)).
_fRep}
255 template <
typename T>
260 template <
typename T>
265 template <
typename T>
270 template <
typename T>
271 template <
typename CONTAINER_OF_T>
272 Iterable<T> Iterable<T>::mk_ (CONTAINER_OF_T&& from)
274 using DECAYED_CONTAINER = remove_cvref_t<CONTAINER_OF_T>;
276 using USE_CONTAINER_TYPE =
277 conditional_t<copy_constructible<DECAYED_CONTAINER> and not same_as<DECAYED_CONTAINER, initializer_list<T>>, DECAYED_CONTAINER, vector<T>>;
278 auto sharedCopyOfContainer = make_shared<USE_CONTAINER_TYPE> (forward<CONTAINER_OF_T> (from));
280 function<optional<T> ()> getNext = [sharedCopyOfContainer, i = sharedCopyOfContainer->begin ()] ()
mutable -> optional<T> {
281 if (i != sharedCopyOfContainer->end ()) {
286 return CreateGenerator (getNext);
288 template <
typename T>
291 return _fRep.GetSharingState ();
293 template <
typename T>
297 return accessor._ConstGetRep ().MakeIterator ();
299 template <
typename T>
303 return accessor._ConstGetRep ().size ();
305 template <
typename T>
309 return accessor._ConstGetRep ().empty ();
311 template <
typename T>
312 template <Common::IPotentiallyComparer<T> EQUALS_COMPARER>
316 return static_cast<bool> (this->Find ([&element, &equalsComparer] (T i) ->
bool {
return equalsComparer (i, element); }));
318 template <
typename T>
319 template <ranges::range LHS_CONTAINER_TYPE, ranges::range RHS_CONTAINER_TYPE, Common::IEqualsComparer<T> EQUALS_COMPARER>
320 bool Iterable<T>::SetEquals (
const LHS_CONTAINER_TYPE& lhs,
const RHS_CONTAINER_TYPE& rhs, EQUALS_COMPARER&& equalsComparer)
327 for (
const auto& ti : lhs) {
328 bool contained =
false;
329 for (
const auto& ri : rhs) {
330 if (equalsComparer (ti, ri)) {
339 for (
const auto& ri : rhs) {
340 bool contained =
false;
341 for (
const auto& ti : lhs) {
342 if (equalsComparer (ti, ri)) {
353 template <
typename T>
354 template <ranges::range RHS_CONTAINER_TYPE, Common::IEqualsComparer<T> EQUALS_COMPARER>
355 inline bool Iterable<T>::SetEquals (
const RHS_CONTAINER_TYPE& rhs, EQUALS_COMPARER&& equalsComparer)
const
357 return SetEquals (*
this, rhs, forward<EQUALS_COMPARER> (equalsComparer));
359 template <
typename T>
360 template <ranges::range LHS_CONTAINER_TYPE, ranges::range RHS_CONTAINER_TYPE, Common::IEqualsComparer<T> EQUALS_COMPARER>
365 for (
const auto& ti : c) {
366 if (equalsComparer (ti, item)) {
376 for (
const auto& ti : lhs) {
377 if (tallyOf (lhs, ti) != tallyOf (rhs, ti)) {
381 for (
const auto& ti : rhs) {
382 if (tallyOf (lhs, ti) != tallyOf (rhs, ti)) {
388 template <
typename T>
389 template <ranges::range RHS_CONTAINER_TYPE, Common::IEqualsComparer<T> EQUALS_COMPARER>
392 return MultiSetEquals (*
this, rhs, equalsComparer);
394 template <
typename T>
395 template <ranges::range LHS_CONTAINER_TYPE, ranges::range RHS_CONTAINER_TYPE, Common::IEqualsComparer<T> EQUALS_COMPARER>
398 if (useIterableSize) {
399 if (lhs.size () != rhs.size ()) {
403 auto li{lhs.begin ()};
404 auto ri{rhs.begin ()};
406 if (useIterableSize) {
407#if qStroika_Foundation_Debug_AssertionsChecked
409 Assert ((li != le) == (ri != re));
412 if (not equalsComparer (*li, *ri)) {
417#if qStroika_Foundation_Debug_AssertionsChecked
418 Assert ((li != le) == (ri != re));
421#if qStroika_Foundation_Debug_AssertionsChecked
422 Assert (li == le and ri == re);
428 for (; li != le and ri != re; ++ri, ++li) {
429 if (not equalsComparer (*li, *ri)) {
434 Assert (li == le or ri == re);
436 return li == le and ri == re;
439 template <
typename T>
440 template <ranges::range RHS_CONTAINER_TYPE, Common::IEqualsComparer<T> EQUALS_COMPARER>
443 return SequentialEquals (*
this, rhs, forward<EQUALS_COMPARER> (equalsComparer), useIterableSize);
445 template <
typename T>
446#if qCompilerAndStdLib_RequiresNotMatchInlineOutOfLineForTemplateClassBeingDefined_Buggy
447 template <
typename RESULT_CONTAINER, predicate<T> INCLUDE_PREDICATE>
449 template <derived_from<Iterable<T>> RESULT_CONTAINER, predicate<T> INCLUDE_PREDICATE>
456 if constexpr (same_as<RESULT_CONTAINER, Iterable<T>>) {
458 auto sharedContext = make_shared<Iterable<T>> (*this);
461 function<optional<T> ()> getNext = [sharedContext, i = sharedContext->MakeIterator (), includeIfTrue] ()
mutable -> optional<T> {
462 while (i and not includeIfTrue (*i)) {
475 return Where<RESULT_CONTAINER> (forward<INCLUDE_PREDICATE> (includeIfTrue), RESULT_CONTAINER{});
478 template <
typename T>
479#if qCompilerAndStdLib_RequiresNotMatchInlineOutOfLineForTemplateClassBeingDefined_Buggy
480 template <
typename RESULT_CONTAINER, predicate<T> INCLUDE_PREDICATE>
482 template <derived_from<Iterable<T>> RESULT_CONTAINER, predicate<T> INCLUDE_PREDICATE>
484 RESULT_CONTAINER
Iterable<T>::Where (INCLUDE_PREDICATE&& includeIfTrue, [[maybe_unused]] RESULT_CONTAINER&& emptyResult)
const
486 if constexpr (same_as<RESULT_CONTAINER, Iterable<T>>) {
488 return Where<RESULT_CONTAINER> (forward<INCLUDE_PREDICATE> (includeIfTrue));
491 Require (emptyResult.empty ());
492 RESULT_CONTAINER result = forward<RESULT_CONTAINER> (emptyResult);
493 this->Apply ([&result, &includeIfTrue] (Common::ArgByValueType<T> arg) {
494 if (includeIfTrue (arg)) {
495 Containers::Adapters::Adder<RESULT_CONTAINER>::Add (&result, arg);
501 template <
typename T>
502 template <Common::IPotentiallyComparer<T> EQUALS_COMPARER>
506 if constexpr (same_as<equal_to<T>, EQUALS_COMPARER> and is_invocable_v<less<T>>) {
507 set<T> t1{begin (), end ()};
508 tmp = vector<T>{t1.begin (), t1.end ()};
511 for (
const auto& i : *this) {
512 if (find_if (tmp.begin (), tmp.end (), [&] (ArgByValueType<T> n) { return equalsComparer (n, i); }) == tmp.end ()) {
517 function<optional<T> ()> getNext = [container = move (tmp), idx =
size_t{0}] ()
mutable -> optional<T> {
518 if (idx < container.size ()) {
519 return container[idx++];
527 template <
typename T>
528 template <
typename RESULT, Common::IPotentiallyComparer<T> EQUALS_COMPARER>
529 Iterable<RESULT>
Iterable<T>::Distinct (
const function<RESULT (ArgByValueType<T>)>& extractElt, EQUALS_COMPARER&& equalsComparer)
const
533 if constexpr (same_as<equal_to<T>, EQUALS_COMPARER> and is_invocable_v<less<T>>) {
535 for (
const T& i : *this) {
536 t1.add (extractElt (i));
538 tmp = vector<RESULT>{t1.begin (), t1.end ()};
541 for (
const T& i : *this) {
542 RESULT item2Test = extractElt (i);
543 if (find_if (tmp.begin (), tmp.end (), [&] (ArgByValueType<T> n) { return equalsComparer (n, item2Test); }) == tmp.end ()) {
544 tmp.push_back (item2Test);
548 function<optional<RESULT> ()> getNext = [container = move (tmp), idx =
size_t{0}] ()
mutable -> optional<RESULT> {
549 if (idx < container.size ()) {
550 return container[idx++];
556 return CreateGenerator (getNext);
558 template <
typename T>
559 template <ranges::range RESULT_CONTAINER, invocable<T> ELEMENT_MAPPER>
561 requires (convertible_to<invoke_result_t<ELEMENT_MAPPER, T>,
typename RESULT_CONTAINER::value_type> or
562 convertible_to<invoke_result_t<ELEMENT_MAPPER, T>, optional<typename RESULT_CONTAINER::value_type>>)
564 using RESULT_ELEMENT =
typename RESULT_CONTAINER::value_type;
565 constexpr bool kLazyEvaluateIteration_ = same_as<RESULT_CONTAINER, Iterable<RESULT_ELEMENT>>;
566 constexpr bool kOptionalExtractor_ = not convertible_to<invoke_result_t<ELEMENT_MAPPER, T>,
typename RESULT_CONTAINER::value_type> and
567 convertible_to<invoke_result_t<ELEMENT_MAPPER, T>, optional<typename RESULT_CONTAINER::value_type>>;
568 if constexpr (kLazyEvaluateIteration_) {
570 auto sharedContext = make_shared<Iterable<T>> (*this);
572 function<optional<RESULT_ELEMENT> ()> getNext = [sharedContext, i = sharedContext->MakeIterator (),
573 elementMapper] ()
mutable -> optional<RESULT_ELEMENT> {
576 if constexpr (kOptionalExtractor_) {
578 optional<RESULT_ELEMENT> t = elementMapper (*i);
588 RESULT_ELEMENT result = elementMapper (*i);
590 return move (result);
599 return this->Map<RESULT_CONTAINER> (forward<ELEMENT_MAPPER> (elementMapper), RESULT_CONTAINER{});
602 template <
typename T>
603 template <ranges::range RESULT_CONTAINER, invocable<T> ELEMENT_MAPPER>
604 RESULT_CONTAINER
Iterable<T>::Map (ELEMENT_MAPPER&& elementMapper, RESULT_CONTAINER&& emptyResult)
const
605 requires (convertible_to<invoke_result_t<ELEMENT_MAPPER, T>,
typename RESULT_CONTAINER::value_type> or
606 convertible_to<invoke_result_t<ELEMENT_MAPPER, T>, optional<typename RESULT_CONTAINER::value_type>>)
608 using RESULT_ELEMENT =
typename RESULT_CONTAINER::value_type;
609 constexpr bool kLazyEvaluateIteration_ = same_as<RESULT_CONTAINER, Iterable<RESULT_ELEMENT>>;
610 constexpr bool kOptionalExtractor_ = not convertible_to<invoke_result_t<ELEMENT_MAPPER, T>,
typename RESULT_CONTAINER::value_type> and
611 convertible_to<invoke_result_t<ELEMENT_MAPPER, T>, optional<typename RESULT_CONTAINER::value_type>>;
612 if constexpr (kLazyEvaluateIteration_) {
613 return this->Map<RESULT_CONTAINER> (forward<ELEMENT_MAPPER> (elementMapper));
616 RESULT_CONTAINER c = forward<RESULT_CONTAINER> (emptyResult);
618 if constexpr (not kOptionalExtractor_ and
requires (RESULT_CONTAINER p) { p.reserve (3u); }) {
619 c.reserve (this->size ());
621 this->Apply ([&c, &elementMapper] (Common::ArgByValueType<T> arg) {
622 if constexpr (kOptionalExtractor_) {
623 if (
auto oarg = elementMapper (arg)) {
624 Containers::Adapters::Adder<RESULT_CONTAINER>::Add (&c, *oarg);
628 Containers::Adapters::Adder<RESULT_CONTAINER>::Add (&c, elementMapper (arg));
634 template <
typename T>
635 template <
typename RESULT_T, invocable<T> CONVERT_TO_RESULT, invocable<RESULT_T, RESULT_T,
bool> COMBINER>
636 RESULT_T
Iterable<T>::Join (
const CONVERT_TO_RESULT& convertToResult,
const COMBINER& combiner)
const
637 requires (convertible_to<invoke_result_t<CONVERT_TO_RESULT, T>, RESULT_T> and
638 convertible_to<invoke_result_t<COMBINER, RESULT_T, RESULT_T, bool>, RESULT_T>)
642 size_t cnt = this->size ();
643 for (
auto i : *this) {
645 result = convertToResult (i);
648 result = combiner (result, convertToResult (i), idx + 1 == cnt);
654 template <
typename T>
658 auto sharedContext = make_shared<Iterable<T>> (*this);
662 function<optional<T> ()> getNext = [sharedContext, i = sharedContext->MakeIterator (),
663 perIteratorContextNItemsToSkip = nItems] ()
mutable -> optional<T> {
664 while (i and perIteratorContextNItemsToSkip > 0) {
665 --perIteratorContextNItemsToSkip;
671 return move (result);
677 template <
typename T>
681 auto sharedContext = make_shared<Iterable<T>> (*this);
685 function<optional<T> ()> getNext = [sharedContext, i = sharedContext->MakeIterator (),
686 perIteratorContextNItemsToTake = nItems] ()
mutable -> optional<T> {
687 if (perIteratorContextNItemsToTake == 0) {
690 perIteratorContextNItemsToTake--;
694 return move (result);
700 template <
typename T>
704 auto sharedContext = make_shared<Iterable<T>> (*this);
709 function<optional<T> ()> getNext = [sharedContext, i = sharedContext->MakeIterator (), perIteratorContextNItemsToSkip = from,
710 perIteratorContextNItemsToTake = to - from] ()
mutable -> optional<T> {
711 while (i and perIteratorContextNItemsToSkip > 0) {
712 --perIteratorContextNItemsToSkip;
715 if (perIteratorContextNItemsToTake == 0) {
718 perIteratorContextNItemsToTake--;
722 return move (result);
728 template <
typename T>
729 template <Common::IPotentiallyComparer<T> COMPARER>
733 vector<T> tmp{this->begin (),
Iterator<T>{this->end ()}};
734#if __cpp_lib_execution >= 201603L
735 sort (std::execution::par, tmp.begin (), tmp.end (), forward<COMPARER> (cmp));
737 sort (tmp.begin (), tmp.end (), forward<COMPARER> (cmp));
740 function<optional<T> ()> getNext = [tmp, idx] ()
mutable -> optional<T> {
741 if (idx < tmp.size ()) {
750 template <
typename T>
751 template <Common::IPotentiallyComparer<T> COMPARER>
755 return Top (forward<COMPARER> (cmp));
758 vector<T> tmp{this->begin (), Iterator<T>{this->end ()}};
759#if __cpp_lib_execution >= 201603L
760 partial_sort (std::execution::par, tmp.begin (), tmp.begin () + n, tmp.end (), forward<COMPARER> (cmp));
762 partial_sort (tmp.begin (), tmp.begin () + n, tmp.end (), forward<COMPARER> (cmp));
765 tmp.erase (tmp.begin () + n, tmp.end ());
766 function<optional<T> ()> getNext = [tmp, idx] ()
mutable -> optional<T> {
767 if (idx < tmp.size ()) {
776 template <
typename T>
779 return Top (std::greater<T>{});
781 template <
typename T>
784 return Top (n, std::greater<int>{});
786 template <
typename T>
787 template <Common::IPotentiallyComparer<T> INORDER_COMPARER_TYPE>
791 vector<T> tmp{begin (), Iterator<T>{end ()}};
792#if __cpp_lib_execution >= 201603L
794 stable_sort (tmp.begin (), tmp.end (), inorderComparer);
797 stable_sort (std::execution::par, tmp.begin (), tmp.end (), inorderComparer);
800 stable_sort (tmp.begin (), tmp.end (), inorderComparer);
802 function<optional<T> ()> getNext = [tmp, idx =
size_t{0}] ()
mutable -> optional<T> {
803 if (idx < tmp.size ()) {
812 template <
typename T>
813 template <Common::IPotentiallyComparer<T> INORDER_COMPARER_TYPE>
817 for (
const T& i : *this) {
818 if (last.has_value ()) {
820 if (inorderComparer (i, *last)) {
828 template <
typename T>
832 return i ? *i : optional<T>{};
834 template <
typename T>
835 template <invocable<T> F>
837 requires (convertible_to<invoke_result_t<F, T>,
bool>)
839 constexpr bool kUseIterableRepIteration_ =
true;
840 if (kUseIterableRepIteration_) {
842 return t ? optional<T>{*t} : optional<T>{};
845 for (
const auto& i : *this) {
853 template <
typename T>
854 template <
typename RESULT_T>
855 inline optional<RESULT_T>
Iterable<T>::First (
const function<optional<RESULT_T> (ArgByValueType<T>)>& that)
const
858 constexpr bool kUseIterableRepIteration_ =
true;
859 if (kUseIterableRepIteration_) {
860 optional<RESULT_T> result;
861 auto f = [&that, &result] (ArgByValueType<T> i) {
return (result = that (i)).has_value (); };
862 _SafeReadRepAccessor<_IRep> accessor{
this};
864 return t ? result : optional<RESULT_T>{};
867 for (
const auto& i : *this) {
868 if (
auto r = that (i)) {
875 template <
typename T>
878 return this->First ().value_or (defaultValue);
880 template <
typename T>
881 template <invocable<T> F>
883 requires (convertible_to<invoke_result_t<F, T>,
bool>)
885 return this->First (forward<F> (that)).value_or (defaultValue);
887 template <
typename T>
901 template <
typename T>
902 template <invocable<T> F>
904 requires (convertible_to<invoke_result_t<F, T>,
bool>)
907 for (
const auto& i : *this) {
914 template <
typename T>
915 template <
typename RESULT_T>
916 inline optional<RESULT_T>
Iterable<T>::Last (
const function<optional<RESULT_T> (ArgByValueType<T>)>& that)
const
920 for (
const auto& i : *this) {
921 if (
auto o = that (i)) {
927 template <
typename T>
930 return this->Last ().value_or (defaultValue);
932 template <
typename T>
933 template <invocable<T> F>
935 requires (convertible_to<invoke_result_t<F, T>,
bool>)
937 return this->Last (forward<F> (that)).value_or (defaultValue);
939 template <
typename T>
943 for (
const auto& i : *
this) {
944 if (not testEachElt (i)) {
950 template <
typename T>
951 template <
typename REDUCED_TYPE>
952 optional<REDUCED_TYPE>
Iterable<T>::Reduce (
const function<REDUCED_TYPE (ArgByValueType<T>, ArgByValueType<T>)>& op)
const
954 optional<REDUCED_TYPE> result;
955 for (
const auto& i : *this) {
957 result = op (i, *result);
965 template <
typename T>
966 template <
typename REDUCED_TYPE>
967 inline REDUCED_TYPE
Iterable<T>::ReduceValue (
const function<REDUCED_TYPE (ArgByValueType<T>, ArgByValueType<T>)>& op,
968 ArgByValueType<REDUCED_TYPE> defaultValue)
const
970 return Reduce<REDUCED_TYPE> (op).value_or (defaultValue);
972 template <
typename T>
975 return Reduce<T> ([] (T lhs, T rhs) -> T {
return min (lhs, rhs); });
977 template <
typename T>
978 template <
typename RESULT_TYPE>
981 return Min ().value_or (defaultValue);
983 template <
typename T>
986 return Reduce<T> ([] (T lhs, T rhs) -> T {
return max (lhs, rhs); });
988 template <
typename T>
989 template <
typename RESULT_TYPE>
992 return Max ().value_or (defaultValue);
994 template <
typename T>
995 template <
typename RESULT_TYPE>
999 if (i == end ()) [[unlikely]] {
1002 return Math::Mean (i, end ());
1004 template <
typename T>
1005 template <
typename RESULT_TYPE>
1008 return Mean ().value_or (defaultValue);
1010 template <
typename T>
1011 template <
typename RESULT_TYPE>
1014 return Reduce<RESULT_TYPE> ([] (T lhs, T rhs) {
return lhs + rhs; });
1016 template <
typename T>
1017 template <
typename RESULT_TYPE>
1020 return Sum ().value_or (defaultValue);
1022 template <
typename T>
1023 template <constructible_from<T> RESULT_TYPE, Common::IPotentiallyComparer<RESULT_TYPE> INORDER_COMPARE_FUNCTION>
1024 inline optional<RESULT_TYPE>
Iterable<T>::Median (
const INORDER_COMPARE_FUNCTION& compare)
const
1027 if (i == end ()) [[unlikely]] {
1030 return Math::Median<RESULT_TYPE> (i, end (), compare);
1032 template <
typename T>
1033 template <constructible_from<T> RESULT_TYPE>
1036 return Median ().value_or (defaultValue);
1038 template <
typename T>
1048 vector<T> origList{begin (),
Iterator<T>{end ()}};
1049 size_t repeatCountIndex{1};
1050 size_t innerIndex{0};
1051 function<optional<T> ()> getNext = [origList, repeatCountIndex, innerIndex, count] ()
mutable -> optional<T> {
1053 if (innerIndex < origList.size ()) [[likely]] {
1054 return origList[innerIndex++];
1056 if (repeatCountIndex < count) [[likely]] {
1067 template <
typename T>
1070 return not empty ();
1072 template <
typename T>
1073 inline bool Iterable<T>::Any (
const function<
bool (ArgByValueType<T>)>& includeIfTrue)
const
1075 return static_cast<bool> (Find (includeIfTrue));
1077 template <
typename T>
1082 template <
typename T>
1083 inline size_t Iterable<T>::Count (
const function<
bool (ArgByValueType<T>)>& includeIfTrue)
const
1086 Apply ([&] (ArgByValueType<T> a) {
1087 if (includeIfTrue (a))
1090 Ensure (cnt == Where (includeIfTrue).size ());
1093 template <
typename T>
1098 template <
typename T>
1101 return MakeIterator ();
1103 template <
typename T>
1108 template <
typename T>
1113 accessor._ConstGetRep ().Apply (doToElement, seq);
1115 template <
typename T>
1116 template <predicate<T> THAT_FUNCTION>
1121 _SafeReadRepAccessor<> accessor{
this};
1122 return accessor._ConstGetRep ().Find (forward<THAT_FUNCTION> (that), seq);
1124 template <
typename T>
1125 template <Common::IPotentiallyComparer<T> EQUALS_COMPARER>
1130 _SafeReadRepAccessor<> accessor{
this};
1131 return accessor._ConstGetRep ().Find_equal_to (v, seq);
1137 template <
typename T>
1138 template <predicate<T> THAT_FUNCTION>
1141 for (Iterator<T> i = startAt; i != end (); ++i) {
1148 template <
typename T>
1149 template <Common::IPotentiallyComparer<T> EQUALS_COMPARER>
1153 for (Iterator<T> i = startAt; i != end (); ++i) {
1154 if (equalsComparer (v, *i)) {
1160 template <
typename T>
1161 template <IIterableOfFrom<T> CONTAINER_OF_T,
typename... CONTAINER_OF_T_CONSTRUCTOR_ARGS>
1162 inline CONTAINER_OF_T
Iterable<T>::As (CONTAINER_OF_T_CONSTRUCTOR_ARGS... args)
const
1166 if constexpr (derived_from<CONTAINER_OF_T, Iterable<T>>) {
1167 return CONTAINER_OF_T (forward<CONTAINER_OF_T_CONSTRUCTOR_ARGS> (args)..., begin (), end ());
1170 return CONTAINER_OF_T (forward<CONTAINER_OF_T_CONSTRUCTOR_ARGS> (args)..., begin (),
Iterator<T>{end ()});
1173 template <
typename T>
1176 Require (n <
static_cast<ptrdiff_t
> (size ()));
1177 Require (n > -
static_cast<ptrdiff_t
> (size ()));
1178 size_t useIndex = n >= 0 ?
static_cast<size_t> (n) :
static_cast<size_t> (n +
static_cast<ptrdiff_t
> (size ()));
1179 size_t idx = useIndex;
1180 for (
const T& i : *
this) {
1189 template <
typename T>
1192 size_t useIndex = n >= 0 ?
static_cast<size_t> (n) :
static_cast<size_t> (n +
static_cast<ptrdiff_t
> (size ()));
1193 size_t idx = useIndex;
1194 for (
const T& i : *
this) {
1200 return defaultValue;
1208 template <
typename T>
1209 template <qCompilerAndStdLib_Constra
intDiffersInTemplateRedeclaration_BWA (IEqualsComparer<T>) T_EQUALS_COMPARER>
1211 bool useIterableSize)
1212 : fElementComparer{elementEqualsComparer}
1213 , fUseIterableSize{useIterableSize}
1216 template <
typename T>
1217 template <qCompilerAndStdLib_Constra
intDiffersInTemplateRedeclaration_BWA (IEqualsComparer<T>) T_EQUALS_COMPARER>
1220 return SequentialEquals (lhs, rhs, fElementComparer, fUseIterableSize);
1228 template <
typename T>
1229 template <qCompilerAndStdLib_Constra
intDiffersInTemplateRedeclaration_BWA (IThreeWayComparer<T>) T_THREEWAY_COMPARER>
1231 : fElementComparer{elementComparer}
1234 DISABLE_COMPILER_MSC_WARNING_START (4701)
1235 template <typename T>
1236 template <qCompilerAndStdLib_ConstraintDiffersInTemplateRedeclaration_BWA (IThreeWayComparer<T>) T_THREEWAY_COMPARER>
1237 inline auto
Iterable<T>::SequentialThreeWayComparer<T_THREEWAY_COMPARER>::operator() (const
Iterable& lhs, const
Iterable& rhs)
const
1239 auto li = lhs.
begin ();
1240 auto le = lhs.end ();
1241 auto ri = rhs.begin ();
1242 auto re = rhs.end ();
1243 DISABLE_COMPILER_MSC_WARNING_START (6001)
1244 DISABLE_COMPILER_GCC_WARNING_START ("GCC diagnostic ignored \"-Wmaybe-uninitialized\"")
1247 optional<strong_ordering> c;
1248 while ((li != le) and (ri != re) and (c = fElementComparer (*li, *ri)) == strong_ordering::equal) {
1254 return strong_ordering::equal;
1257 return strong_ordering::less;
1260 else if (ri == re) {
1261 return strong_ordering::greater;
1264 Assert (li != le and ri != re);
1265 Assert (c == fElementComparer (*li, *ri));
1268 DISABLE_COMPILER_GCC_WARNING_END (
"GCC diagnostic ignored \"-Wmaybe-uninitialized\"")
1269 DISABLE_COMPILER_MSC_WARNING_END (6001)
1271 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)
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 ...
nonvirtual SharedByValue_State 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 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 void Apply(const function< void(ArgByValueType< T > item)> &doToElement, Execution::SequencePolicy seq=Execution::SequencePolicy::eDEFAULT) const
Run the argument function (or lambda) on each element of the container.
nonvirtual RESULT_TYPE MaxValue(ArgByValueType< RESULT_TYPE > defaultValue={}) const
nonvirtual Iterable< T > Slice(size_t from, size_t to) const
nonvirtual Iterator< T > Find(THAT_FUNCTION &&that, Execution::SequencePolicy seq=Execution::SequencePolicy::eDEFAULT) const
Run the argument bool-returning function (or lambda) on each element of the container,...
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 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 Iterable< T > Top() const
return the top/largest (possibly just top N) values from this Iterable<T>
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 Memory::SharedByValue_State _GetSharingState() const
nonvirtual optional< T > First() const
return first element in iterable, or if 'that' specified, first where 'that' is true,...
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 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 > OrderBy(INORDER_COMPARER_TYPE &&inorderComparer=INORDER_COMPARER_TYPE{}, Execution::SequencePolicy seq=Execution::SequencePolicy::ePar) 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.
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 bool empty() const
Returns true iff size() == 0.
nonvirtual T LastValue(ArgByValueType< T > defaultValue={}) const
static bool SequentialEquals(const LHS_CONTAINER_TYPE &lhs, const RHS_CONTAINER_TYPE &rhs, EQUALS_COMPARER &&equalsComparer=EQUALS_COMPARER{}, bool useIterableSize=false)
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 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 ()
conditional_t<(sizeof(CHECK_T)<=2 *sizeof(void *)) and is_trivially_copyable_v< CHECK_T >, CHECK_T, const CHECK_T & > ArgByValueType
This is an alias for 'T' - but how we want to pass it on stack as formal parameter.
SequencePolicy
equivalent which of 4 types being used std::execution::sequenced_policy, parallel_policy,...
@ eSeq
default case - not parallelized