7#include "Stroika/Foundation/Containers/Adapters/Adder.h"
14namespace Stroika::Foundation::Traversal {
16 constexpr bool kIterableUsesStroikaSharedPtr [[deprecated (
"Since Stroika v3.0d1 - not used")]] =
false;
18 struct [[deprecated (
"Since Stroika v3.0d1")]] IterableBase {
19 template <
typename SHARED_T>
20 using PtrImplementationTemplate [[deprecated (
"Since Stroika v3.0d1 - use shared_ptr directly")]] = shared_ptr<SHARED_T>;
21 template <
typename SHARED_T,
typename... ARGS_TYPE>
22 [[deprecated (
"Since Stroika v3.0d1 - use Memory::MakeSharedPtr directly")]]
static shared_ptr<SHARED_T> MakeSmartPtr (ARGS_TYPE&&... args)
24 return Memory::MakeSharedPtr<SHARED_T> (forward<ARGS_TYPE> (args)...);
26 template <
typename SHARED_T>
27 using enable_shared_from_this_PtrImplementationTemplate [[deprecated (
"Since Stroika v3.0d1")]] = std::enable_shared_from_this<SHARED_T>;
43 this->
Apply ([&sz] (
const T&) { ++sz; }, Execution::SequencePolicy::eDEFAULT);
92 return Find ([&v] (
const T& rhs) {
return equal_to<T>{}(v, rhs); }, seq);
96 if (equal_to<T>{}(v, *i)) {
114 template <
typename T>
115 template <
typename REP_SUB_TYPE>
117 : fConstRef_{Debug::UncheckedDynamicCast<const REP_SUB_TYPE*> (it->_fRep.cget ())}
118 , fIterableEnvelope_{it}
119#if qStroika_Foundation_Debug_AssertionsChecked
120 , fAssertReadLock_{it->_fThisAssertExternallySynchronized}
126 template <
typename T>
127 template <
typename REP_SUB_TYPE>
128 inline Iterable<T>::_SafeReadRepAccessor<REP_SUB_TYPE>::_SafeReadRepAccessor (_SafeReadRepAccessor&& src) noexcept
129 : fConstRef_{src.fConstRef_}
130 , fIterableEnvelope_{src.fIterableEnvelope_}
131#if qStroika_Foundation_Debug_AssertionsChecked
132 , fAssertReadLock_{move (src.fAssertReadLock_)}
137 src.fConstRef_ =
nullptr;
139 template <
typename T>
140 template <
typename REP_SUB_TYPE>
141 inline auto Iterable<T>::_SafeReadRepAccessor<REP_SUB_TYPE>::operator= (_SafeReadRepAccessor&& rhs)
noexcept -> _SafeReadRepAccessor&
143 fConstRef_ = rhs.fConstRef_;
144 this->fIterableEnvelope_ = rhs.fIterableEnvelope_;
145#if qStroika_Foundation_Debug_AssertionsChecked
146 this->fAssertReadLock_ = move (rhs.fAssertReadLock_);
150 template <
typename T>
151 template <
typename REP_SUB_TYPE>
152 inline const REP_SUB_TYPE& Iterable<T>::_SafeReadRepAccessor<REP_SUB_TYPE>::_ConstGetRep () const noexcept
157 template <
typename T>
158 template <
typename REP_SUB_TYPE>
159 inline auto Iterable<T>::_SafeReadRepAccessor<REP_SUB_TYPE>::_ConstGetRepSharedPtr () const noexcept -> shared_ptr<REP_SUB_TYPE>
161 return Debug::UncheckedDynamicPointerCast<REP_SUB_TYPE> (this->fIterableEnvelope_->_fRep.cget_ptr ());
169 template <
typename T>
170 template <
typename REP_SUB_TYPE>
171 inline Iterable<T>::_SafeReadWriteRepAccessor<REP_SUB_TYPE>::_SafeReadWriteRepAccessor (Iterable<T>* iterableEnvelope)
174 , fAssertWriteLock_{iterableEnvelope->_fThisAssertExternallySynchronized}
175 , fIterableEnvelope_{iterableEnvelope}
180 template <
typename T>
181 template <
typename REP_SUB_TYPE>
182 inline Iterable<T>::_SafeReadWriteRepAccessor<REP_SUB_TYPE>::_SafeReadWriteRepAccessor (_SafeReadWriteRepAccessor&& from)
183 : fRepReference_{from.fRepReference_}
185 , fAssertWriteLock_{move (from.fAssertWriteLock_)}
186 , fIterableEnvelope_{from.fIterableEnvelope_}
191#if qStroika_Foundation_Debug_AssertionsChecked
192 from.fIterableEnvelope_ =
nullptr;
194 from.fRepReference_ =
nullptr;
196 template <
typename T>
197 template <
typename REP_SUB_TYPE>
198 inline auto Iterable<T>::_SafeReadWriteRepAccessor<REP_SUB_TYPE>::operator= (_SafeReadWriteRepAccessor&& rhs)
noexcept -> _SafeReadWriteRepAccessor&
200 fRepReference_ = rhs.fRepReference_;
202#if qStroika_Foundation_Debug_AssertionsChecked
203 this->fAssertWriteLock_ = move (rhs.fAssertWriteLock_);
204 this->fIterableEnvelope_ = rhs.fIterableEnvelope_;
205 rhs.fIterableEnvelope_ =
nullptr;
209 template <
typename T>
210 template <
typename REP_SUB_TYPE>
211 inline const REP_SUB_TYPE& Iterable<T>::_SafeReadWriteRepAccessor<REP_SUB_TYPE>::_ConstGetRep ()
const
214 return *fRepReference_;
216 template <
typename T>
217 template <
typename REP_SUB_TYPE>
218 inline REP_SUB_TYPE& Iterable<T>::_SafeReadWriteRepAccessor<REP_SUB_TYPE>::_GetWriteableRep ()
221#if qStroika_Foundation_Debug_AssertionsChecked
224 Ensure (fIterableEnvelope_->_fRep.use_count () == 1);
226 return *fRepReference_;
234 template <
typename T>
240 template <
typename T>
245 Require (rep ==
nullptr);
247#if !qCompilerAndStdLib_RequiresNotMatchInlineOutOfLineForTemplateClassBeingDefined_Buggy
248 template <
typename T>
249 template <IIterableOfTo<T> CONTAINER_OF_T>
251 requires (not derived_from<remove_cvref_t<CONTAINER_OF_T>,
Iterable<T>> and
252 (copyable<remove_cvref_t<CONTAINER_OF_T>> or same_as<remove_cvref_t<CONTAINER_OF_T>, initializer_list<T>>))
253 :
_fRep{mk_ (forward<CONTAINER_OF_T> (from)).
_fRep}
257 template <
typename T>
262 template <
typename T>
267 template <
typename T>
272 template <
typename T>
273 template <
typename CONTAINER_OF_T>
274 Iterable<T> Iterable<T>::mk_ (CONTAINER_OF_T&& from)
275 requires (copyable<remove_cvref_t<CONTAINER_OF_T>> or same_as<remove_cvref_t<CONTAINER_OF_T>, initializer_list<T>>)
277 using DECAYED_CONTAINER = remove_cvref_t<CONTAINER_OF_T>;
279 using USE_CONTAINER_TYPE =
280 conditional_t<copy_constructible<DECAYED_CONTAINER> and not same_as<DECAYED_CONTAINER, initializer_list<T>>, DECAYED_CONTAINER, vector<T>>;
281 auto sharedCopyOfContainer = Memory::MakeSharedPtr<USE_CONTAINER_TYPE> (forward<CONTAINER_OF_T> (from));
283 function<optional<T> ()> getNext = [sharedCopyOfContainer, i = sharedCopyOfContainer->begin ()] ()
mutable -> optional<T> {
284 if (i != sharedCopyOfContainer->end ()) {
289 return CreateGenerator (getNext);
291 template <
typename T>
294 return _fRep.GetSharingState ();
296 template <
typename T>
300 return accessor._ConstGetRep ().MakeIterator ();
302 template <
typename T>
306 return accessor._ConstGetRep ().size ();
308 template <
typename T>
311 _SafeReadRepAccessor<> accessor{
this};
312 return accessor._ConstGetRep ().empty ();
314 template <
typename T>
315 template <Common::IPotentiallyComparer<T> EQUALS_COMPARER>
319 return static_cast<bool> (this->Find ([&element, &equalsComparer] (T i) ->
bool {
return equalsComparer (i, element); }));
321 template <
typename T>
322 template <ranges::range LHS_CONTAINER_TYPE, ranges::range RHS_CONTAINER_TYPE, Common::IEqualsComparer<T> EQUALS_COMPARER>
323 bool Iterable<T>::SetEquals (
const LHS_CONTAINER_TYPE& lhs,
const RHS_CONTAINER_TYPE& rhs, EQUALS_COMPARER&& equalsComparer)
330 for (
const auto& ti : lhs) {
331 bool contained =
false;
332 for (
const auto& ri : rhs) {
333 if (equalsComparer (ti, ri)) {
342 for (
const auto& ri : rhs) {
343 bool contained =
false;
344 for (
const auto& ti : lhs) {
345 if (equalsComparer (ti, ri)) {
356 template <
typename T>
357 template <ranges::range RHS_CONTAINER_TYPE, Common::IEqualsComparer<T> EQUALS_COMPARER>
358 inline bool Iterable<T>::SetEquals (
const RHS_CONTAINER_TYPE& rhs, EQUALS_COMPARER&& equalsComparer)
const
360 return SetEquals (*
this, rhs, forward<EQUALS_COMPARER> (equalsComparer));
362 template <
typename T>
363 template <ranges::range LHS_CONTAINER_TYPE, ranges::range RHS_CONTAINER_TYPE, Common::IEqualsComparer<T> EQUALS_COMPARER>
368 for (
const auto& ti : c) {
369 if (equalsComparer (ti, item)) {
379 for (
const auto& ti : lhs) {
380 if (tallyOf (lhs, ti) != tallyOf (rhs, ti)) {
384 for (
const auto& ti : rhs) {
385 if (tallyOf (lhs, ti) != tallyOf (rhs, ti)) {
391 template <
typename T>
392 template <ranges::range RHS_CONTAINER_TYPE, Common::IEqualsComparer<T> EQUALS_COMPARER>
395 return MultiSetEquals (*
this, rhs, equalsComparer);
397 template <
typename T>
398 template <ranges::range LHS_CONTAINER_TYPE, ranges::range RHS_CONTAINER_TYPE, Common::IEqualsComparer<T> EQUALS_COMPARER>
401 if (useIterableSize) {
402 if (lhs.size () != rhs.size ()) {
406 auto li{lhs.begin ()};
407 auto ri{rhs.begin ()};
409 if (useIterableSize) {
410#if qStroika_Foundation_Debug_AssertionsChecked
412 Assert ((li != le) == (ri != re));
415 if (not equalsComparer (*li, *ri)) {
420#if qStroika_Foundation_Debug_AssertionsChecked
421 Assert ((li != le) == (ri != re));
424#if qStroika_Foundation_Debug_AssertionsChecked
425 Assert (li == le and ri == re);
431 for (; li != le and ri != re; ++ri, ++li) {
432 if (not equalsComparer (*li, *ri)) {
437 Assert (li == le or ri == re);
439 return li == le and ri == re;
442 template <
typename T>
443 template <ranges::range RHS_CONTAINER_TYPE, Common::IEqualsComparer<T> EQUALS_COMPARER>
446 return SequentialEquals (*
this, rhs, forward<EQUALS_COMPARER> (equalsComparer), useIterableSize);
448 template <
typename T>
449#if qCompilerAndStdLib_RequiresNotMatchInlineOutOfLineForTemplateClassBeingDefined_Buggy
450 template <
typename RESULT_CONTAINER, predicate<T> INCLUDE_PREDICATE>
452 template <derived_from<Iterable<T>> RESULT_CONTAINER, predicate<T> INCLUDE_PREDICATE>
459 if constexpr (same_as<RESULT_CONTAINER, Iterable<T>>) {
461 auto sharedContext = Memory::MakeSharedPtr<Iterable<T>> (*this);
464 function<optional<T> ()> getNext = [sharedContext, i = sharedContext->MakeIterator (), includeIfTrue] ()
mutable -> optional<T> {
465 while (i and not includeIfTrue (*i)) {
478 return Where<RESULT_CONTAINER> (forward<INCLUDE_PREDICATE> (includeIfTrue), RESULT_CONTAINER{});
481 template <
typename T>
482#if qCompilerAndStdLib_RequiresNotMatchInlineOutOfLineForTemplateClassBeingDefined_Buggy
483 template <
typename RESULT_CONTAINER, predicate<T> INCLUDE_PREDICATE>
485 template <derived_from<Iterable<T>> RESULT_CONTAINER, predicate<T> INCLUDE_PREDICATE>
487 RESULT_CONTAINER
Iterable<T>::Where (INCLUDE_PREDICATE&& includeIfTrue, [[maybe_unused]] RESULT_CONTAINER&& emptyResult)
const
489 if constexpr (same_as<RESULT_CONTAINER, Iterable<T>>) {
491 return Where<RESULT_CONTAINER> (forward<INCLUDE_PREDICATE> (includeIfTrue));
494 Require (emptyResult.empty ());
495 RESULT_CONTAINER result = forward<RESULT_CONTAINER> (emptyResult);
496 this->Apply ([&result, &includeIfTrue] (Common::ArgByValueType<T> arg) {
497 if (includeIfTrue (arg)) {
498 Containers::Adapters::Adder<RESULT_CONTAINER>::Add (&result, arg);
504 template <
typename T>
505 template <Common::IPotentiallyComparer<T> EQUALS_COMPARER>
509 if constexpr (same_as<equal_to<T>, EQUALS_COMPARER> and is_invocable_v<less<T>>) {
510 set<T> t1{begin (), end ()};
511 tmp = vector<T>{t1.begin (), t1.end ()};
514 for (
const auto& i : *this) {
515 if (find_if (tmp.begin (), tmp.end (), [&] (ArgByValueType<T> n) { return equalsComparer (n, i); }) == tmp.end ()) {
520 function<optional<T> ()> getNext = [container = move (tmp), idx =
size_t{0}] ()
mutable -> optional<T> {
521 if (idx < container.size ()) {
522 return container[idx++];
530 template <
typename T>
531 template <
typename RESULT, Common::IPotentiallyComparer<T> EQUALS_COMPARER>
532 Iterable<RESULT>
Iterable<T>::Distinct (
const function<RESULT (ArgByValueType<T>)>& extractElt, EQUALS_COMPARER&& equalsComparer)
const
536 if constexpr (same_as<equal_to<T>, EQUALS_COMPARER> and is_invocable_v<less<T>>) {
538 for (
const T& i : *this) {
539 t1.add (extractElt (i));
541 tmp = vector<RESULT>{t1.begin (), t1.end ()};
544 for (
const T& i : *this) {
545 RESULT item2Test = extractElt (i);
546 if (find_if (tmp.begin (), tmp.end (), [&] (ArgByValueType<T> n) { return equalsComparer (n, item2Test); }) == tmp.end ()) {
547 tmp.push_back (item2Test);
551 function<optional<RESULT> ()> getNext = [container = move (tmp), idx =
size_t{0}] ()
mutable -> optional<RESULT> {
552 if (idx < container.size ()) {
553 return container[idx++];
559 return CreateGenerator (getNext);
561 template <
typename T>
562 template <ranges::range RESULT_CONTAINER, invocable<T> ELEMENT_MAPPER>
564 requires (convertible_to<invoke_result_t<ELEMENT_MAPPER, T>,
typename RESULT_CONTAINER::value_type> or
565 convertible_to<invoke_result_t<ELEMENT_MAPPER, T>, optional<typename RESULT_CONTAINER::value_type>>)
567 using RESULT_ELEMENT =
typename RESULT_CONTAINER::value_type;
568 constexpr bool kLazyEvaluateIteration_ = same_as<RESULT_CONTAINER, Iterable<RESULT_ELEMENT>>;
569 [[maybe_unused]]
constexpr bool kOptionalExtractor_ =
570 not convertible_to<invoke_result_t<ELEMENT_MAPPER, T>,
typename RESULT_CONTAINER::value_type> and
571 convertible_to<invoke_result_t<ELEMENT_MAPPER, T>, optional<typename RESULT_CONTAINER::value_type>>;
572 if constexpr (kLazyEvaluateIteration_) {
574 auto sharedContext = Memory::MakeSharedPtr<Iterable<T>> (*this);
576 function<optional<RESULT_ELEMENT> ()> getNext = [sharedContext, i = sharedContext->MakeIterator (),
577 elementMapper] ()
mutable -> optional<RESULT_ELEMENT> {
580 if constexpr (kOptionalExtractor_) {
582 optional<RESULT_ELEMENT> t = elementMapper (*i);
592 RESULT_ELEMENT result = elementMapper (*i);
594 return move (result);
603 return this->Map<RESULT_CONTAINER> (forward<ELEMENT_MAPPER> (elementMapper), RESULT_CONTAINER{});
606 template <
typename T>
607 template <ranges::range RESULT_CONTAINER, invocable<T> ELEMENT_MAPPER>
608 RESULT_CONTAINER
Iterable<T>::Map (ELEMENT_MAPPER&& elementMapper, RESULT_CONTAINER&& emptyResult)
const
609 requires (convertible_to<invoke_result_t<ELEMENT_MAPPER, T>,
typename RESULT_CONTAINER::value_type> or
610 convertible_to<invoke_result_t<ELEMENT_MAPPER, T>, optional<typename RESULT_CONTAINER::value_type>>)
612 using RESULT_ELEMENT =
typename RESULT_CONTAINER::value_type;
613 constexpr bool kLazyEvaluateIteration_ = same_as<RESULT_CONTAINER, Iterable<RESULT_ELEMENT>>;
614 constexpr bool kOptionalExtractor_ = not convertible_to<invoke_result_t<ELEMENT_MAPPER, T>,
typename RESULT_CONTAINER::value_type> and
615 convertible_to<invoke_result_t<ELEMENT_MAPPER, T>, optional<typename RESULT_CONTAINER::value_type>>;
616 if constexpr (kLazyEvaluateIteration_) {
617 return this->Map<RESULT_CONTAINER> (forward<ELEMENT_MAPPER> (elementMapper));
620 RESULT_CONTAINER c = forward<RESULT_CONTAINER> (emptyResult);
622 if constexpr (not kOptionalExtractor_ and
requires (RESULT_CONTAINER p) { p.reserve (3u); }) {
623 c.reserve (this->size ());
625 this->Apply ([&c, &elementMapper] (Common::ArgByValueType<T> arg) {
626 if constexpr (kOptionalExtractor_) {
627 if (
auto oarg = elementMapper (arg)) {
628 Containers::Adapters::Adder<RESULT_CONTAINER>::Add (&c, *oarg);
632 Containers::Adapters::Adder<RESULT_CONTAINER>::Add (&c, elementMapper (arg));
638 template <
typename T>
639 template <
typename RESULT_T, invocable<T> CONVERT_TO_RESULT, invocable<RESULT_T, RESULT_T,
bool> COMBINER>
640 RESULT_T
Iterable<T>::Join (
const CONVERT_TO_RESULT& convertToResult,
const COMBINER& combiner)
const
641 requires (convertible_to<invoke_result_t<CONVERT_TO_RESULT, T>, RESULT_T> and
642 convertible_to<invoke_result_t<COMBINER, RESULT_T, RESULT_T, bool>, RESULT_T>)
646 size_t cnt = this->size ();
647 for (
auto i : *this) {
649 result = convertToResult (i);
652 result = combiner (result, convertToResult (i), idx + 1 == cnt);
658 template <
typename T>
662 auto sharedContext = Memory::MakeSharedPtr<Iterable<T>> (*this);
666 function<optional<T> ()> getNext = [sharedContext, i = sharedContext->MakeIterator (),
667 perIteratorContextNItemsToSkip = nItems] ()
mutable -> optional<T> {
668 while (i and perIteratorContextNItemsToSkip > 0) {
669 --perIteratorContextNItemsToSkip;
675 return move (result);
681 template <
typename T>
685 auto sharedContext = Memory::MakeSharedPtr<Iterable<T>> (*this);
689 function<optional<T> ()> getNext = [sharedContext, i = sharedContext->MakeIterator (),
690 perIteratorContextNItemsToTake = nItems] ()
mutable -> optional<T> {
691 if (perIteratorContextNItemsToTake == 0) {
694 perIteratorContextNItemsToTake--;
698 return move (result);
704 template <
typename T>
708 auto sharedContext = Memory::MakeSharedPtr<Iterable<T>> (*this);
713 function<optional<T> ()> getNext = [sharedContext, i = sharedContext->MakeIterator (), perIteratorContextNItemsToSkip = from,
714 perIteratorContextNItemsToTake = to - from] ()
mutable -> optional<T> {
715 while (i and perIteratorContextNItemsToSkip > 0) {
716 --perIteratorContextNItemsToSkip;
719 if (perIteratorContextNItemsToTake == 0) {
722 perIteratorContextNItemsToTake--;
726 return move (result);
732 template <
typename T>
733 template <Common::IPotentiallyComparer<T> COMPARER>
737 vector<T> tmp{this->begin (),
Iterator<T>{this->end ()}};
738#if __cpp_lib_execution >= 201603L
739 sort (std::execution::par, tmp.begin (), tmp.end (), forward<COMPARER> (cmp));
741 sort (tmp.begin (), tmp.end (), forward<COMPARER> (cmp));
744 function<optional<T> ()> getNext = [tmp, idx] ()
mutable -> optional<T> {
745 if (idx < tmp.size ()) {
754 template <
typename T>
755 template <Common::IPotentiallyComparer<T> COMPARER>
759 return Top (forward<COMPARER> (cmp));
762 vector<T> tmp{this->begin (), Iterator<T>{this->end ()}};
763#if __cpp_lib_execution >= 201603L
764 partial_sort (std::execution::par, tmp.begin (), tmp.begin () + n, tmp.end (), forward<COMPARER> (cmp));
766 partial_sort (tmp.begin (), tmp.begin () + n, tmp.end (), forward<COMPARER> (cmp));
769 tmp.erase (tmp.begin () + n, tmp.end ());
770 function<optional<T> ()> getNext = [tmp, idx] ()
mutable -> optional<T> {
771 if (idx < tmp.size ()) {
780 template <
typename T>
783 return Top (std::greater<T>{});
785 template <
typename T>
788 return Top (n, std::greater<int>{});
790 template <
typename T>
791 template <Common::IPotentiallyComparer<T> INORDER_COMPARER_TYPE>
795 vector<T> tmp{begin (), Iterator<T>{end ()}};
797#if __cpp_lib_execution >= 201603L
799 stable_sort (tmp.begin (), tmp.end (), inorderComparer);
802 stable_sort (std::execution::par, tmp.begin (), tmp.end (), inorderComparer);
805 stable_sort (tmp.begin (), tmp.end (), inorderComparer);
807 function<optional<T> ()> getNext = [tmp, idx =
size_t{0}] ()
mutable -> optional<T> {
808 if (idx < tmp.size ()) {
817 template <
typename T>
818 template <Common::IPotentiallyComparer<T> INORDER_COMPARER_TYPE>
822 for (
const T& i : *this) {
823 if (last.has_value ()) [[likely]] {
825 if (inorderComparer (i, *last)) [[unlikely]] {
833 template <
typename T>
837 return i ? *i : optional<T>{};
839 template <
typename T>
840 template <invocable<T> F>
842 requires (convertible_to<invoke_result_t<F, T>,
bool>)
844 constexpr bool kUseIterableRepIteration_ =
true;
845 if (kUseIterableRepIteration_) {
847 return t ? optional<T>{*t} : optional<T>{};
850 for (
const auto& i : *this) {
858 template <
typename T>
859 template <
typename RESULT_T>
860 inline optional<RESULT_T>
Iterable<T>::First (
const function<optional<RESULT_T> (ArgByValueType<T>)>& that)
const
863 constexpr bool kUseIterableRepIteration_ =
true;
864 if (kUseIterableRepIteration_) {
865 optional<RESULT_T> result;
866 auto f = [&that, &result] (ArgByValueType<T> i) {
return (result = that (i)).has_value (); };
867 _SafeReadRepAccessor<_IRep> accessor{
this};
869 return t ? result : optional<RESULT_T>{};
872 for (
const auto& i : *this) {
873 if (
auto r = that (i)) {
880 template <
typename T>
883 return this->First ().value_or (defaultValue);
885 template <
typename T>
886 template <invocable<T> F>
888 requires (convertible_to<invoke_result_t<F, T>,
bool>)
890 return this->First (forward<F> (that)).value_or (defaultValue);
892 template <
typename T>
906 template <
typename T>
907 template <invocable<T> F>
909 requires (convertible_to<invoke_result_t<F, T>,
bool>)
912 for (
const auto& i : *this) {
919 template <
typename T>
920 template <
typename RESULT_T>
921 inline optional<RESULT_T>
Iterable<T>::Last (
const function<optional<RESULT_T> (ArgByValueType<T>)>& that)
const
925 for (
const auto& i : *this) {
926 if (
auto o = that (i)) {
932 template <
typename T>
935 return this->Last ().value_or (defaultValue);
937 template <
typename T>
938 template <invocable<T> F>
940 requires (convertible_to<invoke_result_t<F, T>,
bool>)
942 return this->Last (forward<F> (that)).value_or (defaultValue);
944 template <
typename T>
948 for (
const auto& i : *
this) {
949 if (not testEachElt (i)) {
955 template <
typename T>
956 template <
typename REDUCED_TYPE>
957 optional<REDUCED_TYPE>
Iterable<T>::Reduce (
const function<REDUCED_TYPE (ArgByValueType<T>, ArgByValueType<T>)>& op)
const
959 optional<REDUCED_TYPE> result;
960 for (
const auto& i : *this) {
962 result = op (i, *result);
970 template <
typename T>
971 template <
typename REDUCED_TYPE>
972 inline REDUCED_TYPE
Iterable<T>::ReduceValue (
const function<REDUCED_TYPE (ArgByValueType<T>, ArgByValueType<T>)>& op,
973 ArgByValueType<REDUCED_TYPE> defaultValue)
const
975 return Reduce<REDUCED_TYPE> (op).value_or (defaultValue);
977 template <
typename T>
980 return Reduce<T> ([] (T lhs, T rhs) -> T {
return min (lhs, rhs); });
982 template <
typename T>
983 template <
typename RESULT_TYPE>
986 return Min ().value_or (defaultValue);
988 template <
typename T>
991 return Reduce<T> ([] (T lhs, T rhs) -> T {
return max (lhs, rhs); });
993 template <
typename T>
994 template <
typename RESULT_TYPE>
997 return Max ().value_or (defaultValue);
999 template <
typename T>
1000 template <
typename RESULT_TYPE>
1003 Iterator<T> i = begin ();
1004 if (i == end ()) [[unlikely]] {
1007 return Math::Mean (i, end ());
1009 template <
typename T>
1010 template <
typename RESULT_TYPE>
1013 return Mean ().value_or (defaultValue);
1015 template <
typename T>
1016 template <
typename RESULT_TYPE>
1019 return Reduce<RESULT_TYPE> ([] (T lhs, T rhs) {
return lhs + rhs; });
1021 template <
typename T>
1022 template <
typename RESULT_TYPE>
1025 return Sum ().value_or (defaultValue);
1027 template <
typename T>
1028 template <constructible_from<T> RESULT_TYPE, Common::IPotentiallyComparer<RESULT_TYPE> INORDER_COMPARE_FUNCTION>
1029 inline optional<RESULT_TYPE>
Iterable<T>::Median (
const INORDER_COMPARE_FUNCTION& compare)
const
1032 if (i == end ()) [[unlikely]] {
1035 return Math::Median<RESULT_TYPE> (i, end (), compare);
1037 template <
typename T>
1038 template <constructible_from<T> RESULT_TYPE>
1041 return Median ().value_or (defaultValue);
1043 template <
typename T>
1053 vector<T> origList{begin (),
Iterator<T>{end ()}};
1054 size_t repeatCountIndex{1};
1055 size_t innerIndex{0};
1056 function<optional<T> ()> getNext = [origList, repeatCountIndex, innerIndex, count] ()
mutable -> optional<T> {
1058 if (innerIndex < origList.size ()) [[likely]] {
1059 return origList[innerIndex++];
1061 if (repeatCountIndex < count) [[likely]] {
1072 template <
typename T>
1075 return not empty ();
1077 template <
typename T>
1078 inline bool Iterable<T>::Any (
const function<
bool (ArgByValueType<T>)>& includeIfTrue)
const
1080 return static_cast<bool> (Find (includeIfTrue));
1082 template <
typename T>
1087 template <
typename T>
1088 inline size_t Iterable<T>::Count (
const function<
bool (ArgByValueType<T>)>& includeIfTrue)
const
1091 Apply ([&] (ArgByValueType<T> a) {
1092 if (includeIfTrue (a))
1095 Ensure (cnt == Where (includeIfTrue).size ());
1098 template <
typename T>
1103 template <
typename T>
1106 return MakeIterator ();
1108 template <
typename T>
1113 template <
typename T>
1118 accessor._ConstGetRep ().Apply (doToElement, seq);
1120 template <
typename T>
1121 template <predicate<T> THAT_FUNCTION>
1126 _SafeReadRepAccessor<> accessor{
this};
1127 return accessor._ConstGetRep ().Find (forward<THAT_FUNCTION> (that), seq);
1129 template <
typename T>
1130 template <Common::IPotentiallyComparer<T> EQUALS_COMPARER>
1135 _SafeReadRepAccessor<> accessor{
this};
1136 return accessor._ConstGetRep ().Find_equal_to (v, seq);
1142 template <
typename T>
1143 template <predicate<T> THAT_FUNCTION>
1147 if (forward<THAT_FUNCTION> (that) (*i)) [[unlikely]] {
1153 template <
typename T>
1154 template <Common::IPotentiallyComparer<T> EQUALS_COMPARER>
1158 for (Iterator<T> i = startAt; i != end (); ++i) {
1159 if (forward<EQUALS_COMPARER> (equalsComparer) (v, *i)) [[unlikely]] {
1165 template <
typename T>
1166 template <IIterableOfFrom<T> CONTAINER_OF_T,
typename... CONTAINER_OF_T_CONSTRUCTOR_ARGS>
1167 inline CONTAINER_OF_T
Iterable<T>::As (CONTAINER_OF_T_CONSTRUCTOR_ARGS... args)
const
1171 if constexpr (derived_from<CONTAINER_OF_T, Iterable<T>>) {
1172 return CONTAINER_OF_T (forward<CONTAINER_OF_T_CONSTRUCTOR_ARGS> (args)..., begin (), end ());
1175 return CONTAINER_OF_T (forward<CONTAINER_OF_T_CONSTRUCTOR_ARGS> (args)..., begin (),
Iterator<T>{end ()});
1178 template <
typename T>
1181 Require (n <
static_cast<ptrdiff_t
> (size ()));
1182 Require (n > -
static_cast<ptrdiff_t
> (size ()));
1183 size_t useIndex = n >= 0 ?
static_cast<size_t> (n) :
static_cast<size_t> (n +
static_cast<ptrdiff_t
> (size ()));
1184 size_t idx = useIndex;
1185 for (
const T& i : *
this) {
1194 template <
typename T>
1197 size_t useIndex = n >= 0 ?
static_cast<size_t> (n) :
static_cast<size_t> (n +
static_cast<ptrdiff_t
> (size ()));
1198 size_t idx = useIndex;
1199 for (
const T& i : *
this) {
1205 return defaultValue;
1213 template <
typename T>
1214 template <qCompilerAndStdLib_Constra
intDiffersInTemplateRedeclaration_BWA (IEqualsComparer<T>) T_EQUALS_COMPARER>
1216 bool useIterableSize)
1217 : fElementComparer{elementEqualsComparer}
1218 , fUseIterableSize{useIterableSize}
1221 template <
typename T>
1222 template <qCompilerAndStdLib_Constra
intDiffersInTemplateRedeclaration_BWA (IEqualsComparer<T>) T_EQUALS_COMPARER>
1225 return SequentialEquals (lhs, rhs, fElementComparer, fUseIterableSize);
1233 template <
typename T>
1234 template <qCompilerAndStdLib_Constra
intDiffersInTemplateRedeclaration_BWA (IThreeWayComparer<T>) T_THREEWAY_COMPARER>
1236 : fElementComparer{elementComparer}
1239 DISABLE_COMPILER_MSC_WARNING_START (4701)
1240 template <typename T>
1241 template <qCompilerAndStdLib_ConstraintDiffersInTemplateRedeclaration_BWA (IThreeWayComparer<T>) T_THREEWAY_COMPARER>
1242 inline auto
Iterable<T>::SequentialThreeWayComparer<T_THREEWAY_COMPARER>::operator() (const
Iterable& lhs, const
Iterable& rhs)
const
1244 auto li = lhs.
begin ();
1245 auto le = lhs.end ();
1246 auto ri = rhs.begin ();
1247 auto re = rhs.end ();
1248 DISABLE_COMPILER_MSC_WARNING_START (6001)
1249 DISABLE_COMPILER_GCC_WARNING_START ("GCC diagnostic ignored \"-Wmaybe-uninitialized\"")
1252 optional<strong_ordering> c;
1253 while ((li != le) and (ri != re) and (c = fElementComparer (*li, *ri)) == strong_ordering::equal) {
1259 return strong_ordering::equal;
1262 return strong_ordering::less;
1265 else if (ri == re) {
1266 return strong_ordering::greater;
1269 Assert (li != le and ri != re);
1270 Assert (c == fElementComparer (*li, *ri));
1273 DISABLE_COMPILER_GCC_WARNING_END (
"GCC diagnostic ignored \"-Wmaybe-uninitialized\"")
1274 DISABLE_COMPILER_MSC_WARNING_END (6001)
1276 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