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>> and
251 (copyable<remove_cvref_t<CONTAINER_OF_T>> or same_as<remove_cvref_t<CONTAINER_OF_T>, initializer_list<T>>))
252 :
_fRep{mk_ (forward<CONTAINER_OF_T> (from)).
_fRep}
256 template <
typename T>
261 template <
typename T>
266 template <
typename T>
271 template <
typename T>
272 template <
typename CONTAINER_OF_T>
273 Iterable<T> Iterable<T>::mk_ (CONTAINER_OF_T&& from)
274 requires (copyable<remove_cvref_t<CONTAINER_OF_T>> or same_as<remove_cvref_t<CONTAINER_OF_T>, initializer_list<T>>)
276 using DECAYED_CONTAINER = remove_cvref_t<CONTAINER_OF_T>;
278 using USE_CONTAINER_TYPE =
279 conditional_t<copy_constructible<DECAYED_CONTAINER> and not same_as<DECAYED_CONTAINER, initializer_list<T>>, DECAYED_CONTAINER, vector<T>>;
280 auto sharedCopyOfContainer = make_shared<USE_CONTAINER_TYPE> (forward<CONTAINER_OF_T> (from));
282 function<optional<T> ()> getNext = [sharedCopyOfContainer, i = sharedCopyOfContainer->begin ()] ()
mutable -> optional<T> {
283 if (i != sharedCopyOfContainer->end ()) {
288 return CreateGenerator (getNext);
290 template <
typename T>
293 return _fRep.GetSharingState ();
295 template <
typename T>
299 return accessor._ConstGetRep ().MakeIterator ();
301 template <
typename T>
305 return accessor._ConstGetRep ().size ();
307 template <
typename T>
310 _SafeReadRepAccessor<> accessor{
this};
311 return accessor._ConstGetRep ().empty ();
313 template <
typename T>
314 template <Common::IPotentiallyComparer<T> EQUALS_COMPARER>
318 return static_cast<bool> (this->Find ([&element, &equalsComparer] (T i) ->
bool {
return equalsComparer (i, element); }));
320 template <
typename T>
321 template <ranges::range LHS_CONTAINER_TYPE, ranges::range RHS_CONTAINER_TYPE, Common::IEqualsComparer<T> EQUALS_COMPARER>
322 bool Iterable<T>::SetEquals (
const LHS_CONTAINER_TYPE& lhs,
const RHS_CONTAINER_TYPE& rhs, EQUALS_COMPARER&& equalsComparer)
329 for (
const auto& ti : lhs) {
330 bool contained =
false;
331 for (
const auto& ri : rhs) {
332 if (equalsComparer (ti, ri)) {
341 for (
const auto& ri : rhs) {
342 bool contained =
false;
343 for (
const auto& ti : lhs) {
344 if (equalsComparer (ti, ri)) {
355 template <
typename T>
356 template <ranges::range RHS_CONTAINER_TYPE, Common::IEqualsComparer<T> EQUALS_COMPARER>
357 inline bool Iterable<T>::SetEquals (
const RHS_CONTAINER_TYPE& rhs, EQUALS_COMPARER&& equalsComparer)
const
359 return SetEquals (*
this, rhs, forward<EQUALS_COMPARER> (equalsComparer));
361 template <
typename T>
362 template <ranges::range LHS_CONTAINER_TYPE, ranges::range RHS_CONTAINER_TYPE, Common::IEqualsComparer<T> EQUALS_COMPARER>
367 for (
const auto& ti : c) {
368 if (equalsComparer (ti, item)) {
378 for (
const auto& ti : lhs) {
379 if (tallyOf (lhs, ti) != tallyOf (rhs, ti)) {
383 for (
const auto& ti : rhs) {
384 if (tallyOf (lhs, ti) != tallyOf (rhs, ti)) {
390 template <
typename T>
391 template <ranges::range RHS_CONTAINER_TYPE, Common::IEqualsComparer<T> EQUALS_COMPARER>
394 return MultiSetEquals (*
this, rhs, equalsComparer);
396 template <
typename T>
397 template <ranges::range LHS_CONTAINER_TYPE, ranges::range RHS_CONTAINER_TYPE, Common::IEqualsComparer<T> EQUALS_COMPARER>
400 if (useIterableSize) {
401 if (lhs.size () != rhs.size ()) {
405 auto li{lhs.begin ()};
406 auto ri{rhs.begin ()};
408 if (useIterableSize) {
409#if qStroika_Foundation_Debug_AssertionsChecked
411 Assert ((li != le) == (ri != re));
414 if (not equalsComparer (*li, *ri)) {
419#if qStroika_Foundation_Debug_AssertionsChecked
420 Assert ((li != le) == (ri != re));
423#if qStroika_Foundation_Debug_AssertionsChecked
424 Assert (li == le and ri == re);
430 for (; li != le and ri != re; ++ri, ++li) {
431 if (not equalsComparer (*li, *ri)) {
436 Assert (li == le or ri == re);
438 return li == le and ri == re;
441 template <
typename T>
442 template <ranges::range RHS_CONTAINER_TYPE, Common::IEqualsComparer<T> EQUALS_COMPARER>
445 return SequentialEquals (*
this, rhs, forward<EQUALS_COMPARER> (equalsComparer), useIterableSize);
447 template <
typename T>
448#if qCompilerAndStdLib_RequiresNotMatchInlineOutOfLineForTemplateClassBeingDefined_Buggy
449 template <
typename RESULT_CONTAINER, predicate<T> INCLUDE_PREDICATE>
451 template <derived_from<Iterable<T>> RESULT_CONTAINER, predicate<T> INCLUDE_PREDICATE>
458 if constexpr (same_as<RESULT_CONTAINER, Iterable<T>>) {
460 auto sharedContext = make_shared<Iterable<T>> (*this);
463 function<optional<T> ()> getNext = [sharedContext, i = sharedContext->MakeIterator (), includeIfTrue] ()
mutable -> optional<T> {
464 while (i and not includeIfTrue (*i)) {
477 return Where<RESULT_CONTAINER> (forward<INCLUDE_PREDICATE> (includeIfTrue), RESULT_CONTAINER{});
480 template <
typename T>
481#if qCompilerAndStdLib_RequiresNotMatchInlineOutOfLineForTemplateClassBeingDefined_Buggy
482 template <
typename RESULT_CONTAINER, predicate<T> INCLUDE_PREDICATE>
484 template <derived_from<Iterable<T>> RESULT_CONTAINER, predicate<T> INCLUDE_PREDICATE>
486 RESULT_CONTAINER
Iterable<T>::Where (INCLUDE_PREDICATE&& includeIfTrue, [[maybe_unused]] RESULT_CONTAINER&& emptyResult)
const
488 if constexpr (same_as<RESULT_CONTAINER, Iterable<T>>) {
490 return Where<RESULT_CONTAINER> (forward<INCLUDE_PREDICATE> (includeIfTrue));
493 Require (emptyResult.empty ());
494 RESULT_CONTAINER result = forward<RESULT_CONTAINER> (emptyResult);
495 this->Apply ([&result, &includeIfTrue] (Common::ArgByValueType<T> arg) {
496 if (includeIfTrue (arg)) {
497 Containers::Adapters::Adder<RESULT_CONTAINER>::Add (&result, arg);
503 template <
typename T>
504 template <Common::IPotentiallyComparer<T> EQUALS_COMPARER>
508 if constexpr (same_as<equal_to<T>, EQUALS_COMPARER> and is_invocable_v<less<T>>) {
509 set<T> t1{begin (), end ()};
510 tmp = vector<T>{t1.
begin (), t1.end ()};
513 for (
const auto& i : *
this) {
514 if (find_if (tmp.begin (), tmp.end (), [&] (ArgByValueType<T> n) { return equalsComparer (n, i); }) == tmp.end ()) {
519 function<optional<T> ()> getNext = [container = move (tmp), idx =
size_t{0}] ()
mutable -> optional<T> {
520 if (idx < container.size ()) {
521 return container[idx++];
529 template <
typename T>
530 template <
typename RESULT, Common::IPotentiallyComparer<T> EQUALS_COMPARER>
531 Iterable<RESULT>
Iterable<T>::Distinct (
const function<RESULT (ArgByValueType<T>)>& extractElt, EQUALS_COMPARER&& equalsComparer)
const
535 if constexpr (same_as<equal_to<T>, EQUALS_COMPARER> and is_invocable_v<less<T>>) {
537 for (
const T& i : *this) {
538 t1.add (extractElt (i));
540 tmp = vector<RESULT>{t1.begin (), t1.end ()};
543 for (
const T& i : *this) {
544 RESULT item2Test = extractElt (i);
545 if (find_if (tmp.begin (), tmp.end (), [&] (ArgByValueType<T> n) { return equalsComparer (n, item2Test); }) == tmp.end ()) {
546 tmp.push_back (item2Test);
550 function<optional<RESULT> ()> getNext = [container = move (tmp), idx =
size_t{0}] ()
mutable -> optional<RESULT> {
551 if (idx < container.size ()) {
552 return container[idx++];
558 return CreateGenerator (getNext);
560 template <
typename T>
561 template <ranges::range RESULT_CONTAINER, invocable<T> ELEMENT_MAPPER>
563 requires (convertible_to<invoke_result_t<ELEMENT_MAPPER, T>,
typename RESULT_CONTAINER::value_type> or
564 convertible_to<invoke_result_t<ELEMENT_MAPPER, T>, optional<typename RESULT_CONTAINER::value_type>>)
566 using RESULT_ELEMENT =
typename RESULT_CONTAINER::value_type;
567 constexpr bool kLazyEvaluateIteration_ = same_as<RESULT_CONTAINER, Iterable<RESULT_ELEMENT>>;
568 [[maybe_unused]]
constexpr bool kOptionalExtractor_ =
569 not convertible_to<invoke_result_t<ELEMENT_MAPPER, T>,
typename RESULT_CONTAINER::value_type> and
570 convertible_to<invoke_result_t<ELEMENT_MAPPER, T>, optional<typename RESULT_CONTAINER::value_type>>;
571 if constexpr (kLazyEvaluateIteration_) {
573 auto sharedContext = make_shared<Iterable<T>> (*this);
575 function<optional<RESULT_ELEMENT> ()> getNext = [sharedContext, i = sharedContext->MakeIterator (),
576 elementMapper] ()
mutable -> optional<RESULT_ELEMENT> {
579 if constexpr (kOptionalExtractor_) {
581 optional<RESULT_ELEMENT> t = elementMapper (*i);
591 RESULT_ELEMENT result = elementMapper (*i);
593 return move (result);
602 return this->Map<RESULT_CONTAINER> (forward<ELEMENT_MAPPER> (elementMapper), RESULT_CONTAINER{});
605 template <
typename T>
606 template <ranges::range RESULT_CONTAINER, invocable<T> ELEMENT_MAPPER>
607 RESULT_CONTAINER
Iterable<T>::Map (ELEMENT_MAPPER&& elementMapper, RESULT_CONTAINER&& emptyResult)
const
608 requires (convertible_to<invoke_result_t<ELEMENT_MAPPER, T>,
typename RESULT_CONTAINER::value_type> or
609 convertible_to<invoke_result_t<ELEMENT_MAPPER, T>, optional<typename RESULT_CONTAINER::value_type>>)
611 using RESULT_ELEMENT =
typename RESULT_CONTAINER::value_type;
612 constexpr bool kLazyEvaluateIteration_ = same_as<RESULT_CONTAINER, Iterable<RESULT_ELEMENT>>;
613 constexpr bool kOptionalExtractor_ = not convertible_to<invoke_result_t<ELEMENT_MAPPER, T>,
typename RESULT_CONTAINER::value_type> and
614 convertible_to<invoke_result_t<ELEMENT_MAPPER, T>, optional<typename RESULT_CONTAINER::value_type>>;
615 if constexpr (kLazyEvaluateIteration_) {
616 return this->Map<RESULT_CONTAINER> (forward<ELEMENT_MAPPER> (elementMapper));
619 RESULT_CONTAINER c = forward<RESULT_CONTAINER> (emptyResult);
621 if constexpr (not kOptionalExtractor_ and
requires (RESULT_CONTAINER p) { p.reserve (3u); }) {
622 c.reserve (this->size ());
624 this->Apply ([&c, &elementMapper] (Common::ArgByValueType<T> arg) {
625 if constexpr (kOptionalExtractor_) {
626 if (
auto oarg = elementMapper (arg)) {
627 Containers::Adapters::Adder<RESULT_CONTAINER>::Add (&c, *oarg);
631 Containers::Adapters::Adder<RESULT_CONTAINER>::Add (&c, elementMapper (arg));
637 template <
typename T>
638 template <
typename RESULT_T, invocable<T> CONVERT_TO_RESULT, invocable<RESULT_T, RESULT_T,
bool> COMBINER>
639 RESULT_T
Iterable<T>::Join (
const CONVERT_TO_RESULT& convertToResult,
const COMBINER& combiner)
const
640 requires (convertible_to<invoke_result_t<CONVERT_TO_RESULT, T>, RESULT_T> and
641 convertible_to<invoke_result_t<COMBINER, RESULT_T, RESULT_T, bool>, RESULT_T>)
645 size_t cnt = this->size ();
646 for (
auto i : *this) {
648 result = convertToResult (i);
651 result = combiner (result, convertToResult (i), idx + 1 == cnt);
657 template <
typename T>
661 auto sharedContext = make_shared<Iterable<T>> (*this);
665 function<optional<T> ()> getNext = [sharedContext, i = sharedContext->MakeIterator (),
666 perIteratorContextNItemsToSkip = nItems] ()
mutable -> optional<T> {
667 while (i and perIteratorContextNItemsToSkip > 0) {
668 --perIteratorContextNItemsToSkip;
674 return move (result);
678 return CreateGenerator (getNext);
680 template <
typename T>
684 auto sharedContext = make_shared<Iterable<T>> (*this);
688 function<optional<T> ()> getNext = [sharedContext, i = sharedContext->MakeIterator (),
689 perIteratorContextNItemsToTake = nItems] ()
mutable -> optional<T> {
690 if (perIteratorContextNItemsToTake == 0) {
693 perIteratorContextNItemsToTake--;
697 return move (result);
703 template <
typename T>
707 auto sharedContext = make_shared<Iterable<T>> (*this);
712 function<optional<T> ()> getNext = [sharedContext, i = sharedContext->MakeIterator (), perIteratorContextNItemsToSkip = from,
713 perIteratorContextNItemsToTake = to - from] ()
mutable -> optional<T> {
714 while (i and perIteratorContextNItemsToSkip > 0) {
715 --perIteratorContextNItemsToSkip;
718 if (perIteratorContextNItemsToTake == 0) {
721 perIteratorContextNItemsToTake--;
725 return move (result);
731 template <
typename T>
732 template <Common::IPotentiallyComparer<T> COMPARER>
736 vector<T> tmp{this->begin (),
Iterator<T>{this->end ()}};
737#if __cpp_lib_execution >= 201603L
738 sort (std::execution::par, tmp.begin (), tmp.end (), forward<COMPARER> (cmp));
740 sort (tmp.begin (), tmp.end (), forward<COMPARER> (cmp));
743 function<optional<T> ()> getNext = [tmp, idx] ()
mutable -> optional<T> {
744 if (idx < tmp.size ()) {
753 template <
typename T>
754 template <Common::IPotentiallyComparer<T> COMPARER>
758 return Top (forward<COMPARER> (cmp));
761 vector<T> tmp{this->begin (), Iterator<T>{this->end ()}};
762#if __cpp_lib_execution >= 201603L
763 partial_sort (std::execution::par, tmp.begin (), tmp.begin () + n, tmp.end (), forward<COMPARER> (cmp));
765 partial_sort (tmp.begin (), tmp.begin () + n, tmp.end (), forward<COMPARER> (cmp));
768 tmp.erase (tmp.begin () + n, tmp.end ());
769 function<optional<T> ()> getNext = [tmp, idx] ()
mutable -> optional<T> {
770 if (idx < tmp.size ()) {
779 template <
typename T>
782 return Top (std::greater<T>{});
784 template <
typename T>
787 return Top (n, std::greater<int>{});
789 template <
typename T>
790 template <Common::IPotentiallyComparer<T> INORDER_COMPARER_TYPE>
794 vector<T> tmp{begin (), Iterator<T>{end ()}};
796#if __cpp_lib_execution >= 201603L
798 stable_sort (tmp.begin (), tmp.end (), inorderComparer);
801 stable_sort (std::execution::par, tmp.begin (), tmp.end (), inorderComparer);
804 stable_sort (tmp.begin (), tmp.end (), inorderComparer);
806 function<optional<T> ()> getNext = [tmp, idx =
size_t{0}] ()
mutable -> optional<T> {
807 if (idx < tmp.size ()) {
816 template <
typename T>
817 template <Common::IPotentiallyComparer<T> INORDER_COMPARER_TYPE>
821 for (
const T& i : *this) {
822 if (last.has_value ()) [[likely]] {
824 if (inorderComparer (i, *last)) [[unlikely]] {
832 template <
typename T>
836 return i ? *i : optional<T>{};
838 template <
typename T>
839 template <invocable<T> F>
841 requires (convertible_to<invoke_result_t<F, T>,
bool>)
843 constexpr bool kUseIterableRepIteration_ =
true;
844 if (kUseIterableRepIteration_) {
846 return t ? optional<T>{*t} : optional<T>{};
849 for (
const auto& i : *this) {
857 template <
typename T>
858 template <
typename RESULT_T>
859 inline optional<RESULT_T>
Iterable<T>::First (
const function<optional<RESULT_T> (ArgByValueType<T>)>& that)
const
862 constexpr bool kUseIterableRepIteration_ =
true;
863 if (kUseIterableRepIteration_) {
864 optional<RESULT_T> result;
865 auto f = [&that, &result] (ArgByValueType<T> i) {
return (result = that (i)).has_value (); };
866 _SafeReadRepAccessor<_IRep> accessor{
this};
868 return t ? result : optional<RESULT_T>{};
871 for (
const auto& i : *this) {
872 if (
auto r = that (i)) {
879 template <
typename T>
882 return this->First ().value_or (defaultValue);
884 template <
typename T>
885 template <invocable<T> F>
887 requires (convertible_to<invoke_result_t<F, T>,
bool>)
889 return this->First (forward<F> (that)).value_or (defaultValue);
891 template <
typename T>
905 template <
typename T>
906 template <invocable<T> F>
908 requires (convertible_to<invoke_result_t<F, T>,
bool>)
911 for (
const auto& i : *this) {
918 template <
typename T>
919 template <
typename RESULT_T>
920 inline optional<RESULT_T>
Iterable<T>::Last (
const function<optional<RESULT_T> (ArgByValueType<T>)>& that)
const
924 for (
const auto& i : *this) {
925 if (
auto o = that (i)) {
931 template <
typename T>
934 return this->Last ().value_or (defaultValue);
936 template <
typename T>
937 template <invocable<T> F>
939 requires (convertible_to<invoke_result_t<F, T>,
bool>)
941 return this->Last (forward<F> (that)).value_or (defaultValue);
943 template <
typename T>
947 for (
const auto& i : *
this) {
948 if (not testEachElt (i)) {
954 template <
typename T>
955 template <
typename REDUCED_TYPE>
956 optional<REDUCED_TYPE>
Iterable<T>::Reduce (
const function<REDUCED_TYPE (ArgByValueType<T>, ArgByValueType<T>)>& op)
const
958 optional<REDUCED_TYPE> result;
959 for (
const auto& i : *this) {
961 result = op (i, *result);
969 template <
typename T>
970 template <
typename REDUCED_TYPE>
971 inline REDUCED_TYPE
Iterable<T>::ReduceValue (
const function<REDUCED_TYPE (ArgByValueType<T>, ArgByValueType<T>)>& op,
972 ArgByValueType<REDUCED_TYPE> defaultValue)
const
974 return Reduce<REDUCED_TYPE> (op).value_or (defaultValue);
976 template <
typename T>
979 return Reduce<T> ([] (T lhs, T rhs) -> T {
return min (lhs, rhs); });
981 template <
typename T>
982 template <
typename RESULT_TYPE>
985 return Min ().value_or (defaultValue);
987 template <
typename T>
990 return Reduce<T> ([] (T lhs, T rhs) -> T {
return max (lhs, rhs); });
992 template <
typename T>
993 template <
typename RESULT_TYPE>
996 return Max ().value_or (defaultValue);
998 template <
typename T>
999 template <
typename RESULT_TYPE>
1002 Iterator<T> i = begin ();
1003 if (i == end ()) [[unlikely]] {
1006 return Math::Mean (i, end ());
1008 template <
typename T>
1009 template <
typename RESULT_TYPE>
1012 return Mean ().value_or (defaultValue);
1014 template <
typename T>
1015 template <
typename RESULT_TYPE>
1018 return Reduce<RESULT_TYPE> ([] (T lhs, T rhs) {
return lhs + rhs; });
1020 template <
typename T>
1021 template <
typename RESULT_TYPE>
1024 return Sum ().value_or (defaultValue);
1026 template <
typename T>
1027 template <constructible_from<T> RESULT_TYPE, Common::IPotentiallyComparer<RESULT_TYPE> INORDER_COMPARE_FUNCTION>
1028 inline optional<RESULT_TYPE>
Iterable<T>::Median (
const INORDER_COMPARE_FUNCTION& compare)
const
1031 if (i == end ()) [[unlikely]] {
1034 return Math::Median<RESULT_TYPE> (i, end (), compare);
1036 template <
typename T>
1037 template <constructible_from<T> RESULT_TYPE>
1040 return Median ().value_or (defaultValue);
1042 template <
typename T>
1052 vector<T> origList{begin (),
Iterator<T>{end ()}};
1053 size_t repeatCountIndex{1};
1054 size_t innerIndex{0};
1055 function<optional<T> ()> getNext = [origList, repeatCountIndex, innerIndex, count] ()
mutable -> optional<T> {
1057 if (innerIndex < origList.size ()) [[likely]] {
1058 return origList[innerIndex++];
1060 if (repeatCountIndex < count) [[likely]] {
1071 template <
typename T>
1074 return not empty ();
1076 template <
typename T>
1077 inline bool Iterable<T>::Any (
const function<
bool (ArgByValueType<T>)>& includeIfTrue)
const
1079 return static_cast<bool> (Find (includeIfTrue));
1081 template <
typename T>
1086 template <
typename T>
1087 inline size_t Iterable<T>::Count (
const function<
bool (ArgByValueType<T>)>& includeIfTrue)
const
1090 Apply ([&] (ArgByValueType<T> a) {
1091 if (includeIfTrue (a))
1094 Ensure (cnt == Where (includeIfTrue).size ());
1097 template <
typename T>
1102 template <
typename T>
1105 return MakeIterator ();
1107 template <
typename T>
1112 template <
typename T>
1117 accessor._ConstGetRep ().Apply (doToElement, seq);
1119 template <
typename T>
1120 template <predicate<T> THAT_FUNCTION>
1125 _SafeReadRepAccessor<> accessor{
this};
1126 return accessor._ConstGetRep ().Find (forward<THAT_FUNCTION> (that), seq);
1128 template <
typename T>
1129 template <Common::IPotentiallyComparer<T> EQUALS_COMPARER>
1134 _SafeReadRepAccessor<> accessor{
this};
1135 return accessor._ConstGetRep ().Find_equal_to (v, seq);
1141 template <
typename T>
1142 template <predicate<T> THAT_FUNCTION>
1146 if (forward<THAT_FUNCTION> (that) (*i)) [[unlikely]] {
1152 template <
typename T>
1153 template <Common::IPotentiallyComparer<T> EQUALS_COMPARER>
1158 if (forward<EQUALS_COMPARER> (equalsComparer) (v, *i)) [[unlikely]] {
1164 template <
typename T>
1165 template <IIterableOfFrom<T> CONTAINER_OF_T,
typename... CONTAINER_OF_T_CONSTRUCTOR_ARGS>
1166 inline CONTAINER_OF_T
Iterable<T>::As (CONTAINER_OF_T_CONSTRUCTOR_ARGS... args)
const
1170 if constexpr (derived_from<CONTAINER_OF_T, Iterable<T>>) {
1171 return CONTAINER_OF_T (forward<CONTAINER_OF_T_CONSTRUCTOR_ARGS> (args)..., begin (), end ());
1174 return CONTAINER_OF_T (forward<CONTAINER_OF_T_CONSTRUCTOR_ARGS> (args)..., begin (),
Iterator<T>{end ()});
1177 template <
typename T>
1180 Require (n <
static_cast<ptrdiff_t
> (size ()));
1181 Require (n > -
static_cast<ptrdiff_t
> (size ()));
1182 size_t useIndex = n >= 0 ?
static_cast<size_t> (n) :
static_cast<size_t> (n +
static_cast<ptrdiff_t
> (size ()));
1183 size_t idx = useIndex;
1184 for (
const T& i : *
this) {
1193 template <
typename T>
1196 size_t useIndex = n >= 0 ?
static_cast<size_t> (n) :
static_cast<size_t> (n +
static_cast<ptrdiff_t
> (size ()));
1197 size_t idx = useIndex;
1198 for (
const T& i : *
this) {
1204 return defaultValue;
1212 template <
typename T>
1213 template <qCompilerAndStdLib_Constra
intDiffersInTemplateRedeclaration_BWA (IEqualsComparer<T>) T_EQUALS_COMPARER>
1215 bool useIterableSize)
1216 : fElementComparer{elementEqualsComparer}
1217 , fUseIterableSize{useIterableSize}
1220 template <
typename T>
1221 template <qCompilerAndStdLib_Constra
intDiffersInTemplateRedeclaration_BWA (IEqualsComparer<T>) T_EQUALS_COMPARER>
1224 return SequentialEquals (lhs, rhs, fElementComparer, fUseIterableSize);
1232 template <
typename T>
1233 template <qCompilerAndStdLib_Constra
intDiffersInTemplateRedeclaration_BWA (IThreeWayComparer<T>) T_THREEWAY_COMPARER>
1235 : fElementComparer{elementComparer}
1238 DISABLE_COMPILER_MSC_WARNING_START (4701)
1239 template <typename T>
1240 template <qCompilerAndStdLib_ConstraintDiffersInTemplateRedeclaration_BWA (IThreeWayComparer<T>) T_THREEWAY_COMPARER>
1241 inline auto
Iterable<T>::SequentialThreeWayComparer<T_THREEWAY_COMPARER>::operator() (const
Iterable& lhs, const
Iterable& rhs)
const
1243 auto li = lhs.
begin ();
1244 auto le = lhs.end ();
1245 auto ri = rhs.begin ();
1246 auto re = rhs.end ();
1247 DISABLE_COMPILER_MSC_WARNING_START (6001)
1248 DISABLE_COMPILER_GCC_WARNING_START ("GCC diagnostic ignored \"-Wmaybe-uninitialized\"")
1251 optional<strong_ordering> c;
1252 while ((li != le) and (ri != re) and (c = fElementComparer (*li, *ri)) == strong_ordering::equal) {
1258 return strong_ordering::equal;
1261 return strong_ordering::less;
1264 else if (ri == re) {
1265 return strong_ordering::greater;
1268 Assert (li != le and ri != re);
1269 Assert (c == fElementComparer (*li, *ri));
1272 DISABLE_COMPILER_GCC_WARNING_END (
"GCC diagnostic ignored \"-Wmaybe-uninitialized\"")
1273 DISABLE_COMPILER_MSC_WARNING_END (6001)
1275 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