GCC Code Coverage Report


Directory: ./
File: include/CXXIter/CXXIter.h
Date: 2023-01-04 16:32:12
Exec Total Coverage
Lines: 259 259 100.0%
Functions: 1336 1343 99.5%
Branches: 89 142 62.7%

Line Branch Exec Source
1 #pragma once
2
3 #include <utility>
4 #include <optional>
5 #include <concepts>
6 #include <functional>
7 #include <string>
8 #include <limits>
9
10 #include <unordered_map>
11 #include <vector>
12 #include <cmath>
13
14 #include "src/Common.h"
15 #include "src/Generator.h"
16 #include "src/sources/Concepts.h"
17 #include "src/sources/ContainerSources.h"
18 #include "src/sources/GeneratorSources.h"
19 #include "src/Collector.h"
20 #include "src/op/Alternater.h"
21 #include "src/op/Caster.h"
22 #include "src/op/Chainer.h"
23 #include "src/op/Chunked.h"
24 #include "src/op/ChunkedExact.h"
25 #include "src/op/Filter.h"
26 #include "src/op/FilterMap.h"
27 #include "src/op/FlagLast.h"
28 #include "src/op/FlatMap.h"
29 #include "src/op/GenerateFrom.h"
30 #include "src/op/GroupBy.h"
31 #include "src/op/InplaceModifier.h"
32 #include "src/op/Intersperser.h"
33 #include "src/op/Map.h"
34 #include "src/op/Reverse.h"
35 #include "src/op/SkipN.h"
36 #include "src/op/SkipWhile.h"
37 #include "src/op/Sorter.h"
38 #include "src/op/TakeN.h"
39 #include "src/op/TakeWhile.h"
40 #include "src/op/Unique.h"
41 #include "src/op/Zipper.h"
42 #include "src/Helpers.h"
43
44
45 /**
46 * @brief CXXIter
47 */
48 namespace CXXIter {
49
50 // ################################################################################################
51 // SURFACE-API
52 // ################################################################################################
53
54 /**
55 * @brief Public Iterator API surface.
56 */
57 template<CXXIterIterator TSelf>
58 class IterApi {
59 public: // Associated types
60 /**
61 * @brief Type of the trait::Iterator implemenation for this.
62 */
63 using Iterator = trait::Iterator<TSelf>;
64 /**
65 * @brief Type of the elements of this iterator. (Can be references)
66 */
67 using Item = typename Iterator::Item;
68 /**
69 * @brief Owned Type of the elements of this iterator. (References removed).
70 */
71 using ItemOwned = std::remove_cvref_t<Item>;
72
73 private:
74 6219 constexpr TSelf* self() { return static_cast<TSelf*>(this); }
75 532 constexpr const TSelf* self() const { return static_cast<const TSelf*>(this); }
76 static constexpr bool IS_REFERENCE = std::is_lvalue_reference_v<Item>;
77
78 public: // C++ Iterator API-Surface
79
80 /**
81 * @brief C++ iterator implementation for a CXXIter chain.
82 */
83 class iterator {
84 friend class IterApi;
85 TSelf& self;
86 IterValue<Item> element;
87
88 /** end ctor */
89 1 iterator(TSelf& self) : self(self) {}
90 /** element ctor */
91 1 iterator(TSelf& self, IterValue<Item>&& element) : self(self), element(std::move(element)) {}
92
93
94 public:
95 2 iterator& operator++() {
96
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
2 if(element.has_value()) {
97 2 element = self.next();
98 }
99 2 return *this;
100 }
101
102 2 Item& operator*() { return element.value(); }
103
104 3 bool operator!=(const iterator& o) {
105 3 return (element.has_value() != o.element.has_value());
106 }
107 };
108
109 /**
110 * @brief begin() method, part of C++'s iterator interface
111 * @return C++ interface on top of this iterator pipeline.
112 */
113 1 iterator begin() { return {*self(), next()}; }
114
115 /**
116 * @brief end() method, part of C++'s iterator interface
117 * @return C++ interface on top of this iterator pipeline.
118 */
119 1 iterator end() { return {*self()}; }
120
121 public: // CXXIter API-Surface
122
123 /**
124 * @brief Get the bounds on the remaining length of this iterator, estimated from the source
125 * and all of the chained iterations on it.
126 * @return The estimated bounds on the remaining length of this iterator.
127 */
128 462 constexpr SizeHint sizeHint() const {
129 462 return Iterator::sizeHint(*self());
130 }
131
132 /**
133 * @brief Get this iterator's exact size.
134 * @note This method only exists if the iterator's exact size is known. Operations like @c IterApi::filter
135 * cause the remaining iterator to have an unknown exact size.
136 * @return This iterator's exact number of elements.
137 *
138 * Usage Example:
139 * - Valid (Exact number of elements is known):
140 * @code
141 * size_t size = CXXIter::range<float>(0.0f, 2.0f, 0.25f)
142 * .map([](float blub) { return std::to_string(blub); })
143 * .sort()
144 * .intersperse(CXXIter::empty<std::string>())
145 * .size();
146 * // size == 8
147 * @endcode
148 * - Invalid, does not compile (Exact number of elements is unknown):
149 * @code
150 * size_t size = CXXIter::range<float>(0.0f, 2.0f, 0.25f)
151 * .map([](float blub) { return std::to_string(blub); })
152 * .sort()
153 * .intersperse(CXXIter::empty<std::string>())
154 * .flatMap()
155 * .size();
156 * @endcode
157 */
158 70 constexpr size_t size() const requires CXXIterExactSizeIterator<TSelf> {
159 70 return trait::ExactSizeIterator<TSelf>::size(*self());
160 }
161
162 /**
163 * @brief Get the next element from this iterator (if any), wrapped in a CXXIter::IterValue<>.
164 * @note If the returned CXXIter::IterValue is empty, there are no elements left in this iterator.
165 * Calling @c next() again after that is undefined behavior.
166 * @return The next element from this iterator (if any), wrapped in a CXXIter::IterValue<>
167 *
168 * Usage Example:
169 * @code
170 * std::optional<float> output = CXXIter::range<float>(1.337f, 2.0f, 0.25f)
171 * .next().toStdOptional();
172 * // output == Some(1.337f);
173 * @endcode
174 */
175 227 constexpr IterValue<Item> next() {
176 227 return Iterator::next(*self());
177 }
178
179 /**
180 * @brief Advance the iterator by n elements.
181 * @details If possible, this is a O(1) operation. Some iterator pipeline elements make that impossible
182 * though. In these cases, the implementation falls back to pulling n elements and dropping them.
183 * @param n The amount of elements to advance the iterator by.
184 *
185 * Usage Example:
186 * @code
187 * auto src = CXXIter::range<float>(1.337f, 2.0f, 0.25f, 5.0f, 42.0f);
188 * std::optional<float> output = src.next().toStdOptional();
189 * // output == Some(1.337f);
190 * src.advanceBy(2);
191 * output = src.next().toStdOptional();
192 * // output == Some(5.0f);
193 * @endcode
194 */
195 18 constexpr void advanceBy(size_t n) {
196 18 Iterator::advanceBy(*self(), n);
197 18 }
198
199 /**
200 * @brief Get the next element from the back of this iterator (if any), wrapped in a CXXIter::IterValue<>.
201 * @note If the returned CXXIter::IterValue is empty, there are no elements left in this iterator.
202 * Calling @c nextBack() again after that is undefined behavior.
203 * @note This method only exists if the iterator implements the DoubleEndedIterator trait.
204 * @return The next element from the back of this iterator (if any), wrapped in a CXXIter::IterValue<>
205 *
206 * Usage Example:
207 * @code
208 * std::optional<float> output = CXXIter::range<float>(1.337f, 2.0f, 0.25f)
209 * .nextBack().toStdOptional();
210 * // output == Some(0.25f);
211 * @endcode
212 */
213 176 constexpr IterValue<Item> nextBack() requires CXXIterDoubleEndedIterator<TSelf> {
214 176 return trait::DoubleEndedIterator<TSelf>::nextBack(*self());
215 }
216
217 // ###################
218 // CONSUMERS
219 // ###################
220 /**
221 * @name Consumers
222 */
223 //@{
224
225 /**
226 * @brief Consumer that calls the given function @p useFn for each of the elements in this iterator.
227 * @note This consumes the iterator.
228 * @param useFn Function called for each of the elements in this iterator.
229 *
230 * Usage Example:
231 * @code
232 * std::vector<std::string> input = {"1337", "42", "64"};
233 * std::vector<std::string> output;
234 * CXXIter::from(input)
235 * .forEach([&output](std::string& item) {
236 * output.push_back(std::forward<std::string>(item));
237 * });
238 * @endcode
239 */
240 template<typename TUseFn>
241 4402 constexpr void forEach(TUseFn useFn) {
242
2/2
✓ Branch 1 taken 1119 times.
✓ Branch 2 taken 46 times.
6230 while(true) {
243
2/2
✓ Branch 2 taken 2184 times.
✓ Branch 3 taken 1 times.
4402 auto item = Iterator::next(*self());
244
2/2
✓ Branch 1 taken 250 times.
✓ Branch 2 taken 1950 times.
4492 if(!item.has_value()) [[unlikely]] { return; }
245
2/4
✓ Branch 1 taken 1950 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 1785 times.
✗ Branch 6 not taken.
3900 useFn(std::forward<Item>( item.value() ));
246 }
247 }
248
249 /**
250 * @brief Consumer that collects all elements from this iterator in a new container of type @p TTargetContainer
251 * @note This consumes the iterator.
252 * @tparam TTargetContainer Type-Template for the target container that the elements from this iterator should
253 * be collected into. The first template parameter of this Type-Template has to take the type of the elements.
254 * @tparam TTargetContainerArgs... Optional additional type attributes to pass on to the target container. These
255 * are appended to the item value type, which is automatically supplied.
256 * @return An instance of @p TTargetContainer with all the elements of this iterator collected into.
257 *
258 * Usage Example:
259 * @code
260 * std::vector<std::string> input = {"1337", "42", "64"};
261 * std::vector<std::string> output = CXXIter::from(input)
262 * .collect<std::vector>();
263 * @endcode
264 *
265 * With Additional container type parameters:
266 * @code
267 * std::vector<std::string> input = {"1337", "42", "64"};
268 * std::vector<std::string, std::allocator<std::string>> output = CXXIter::from(input)
269 * .collect<std::vector, std::allocator<std::string>>();
270 * @endcode
271 */
272 template<template <typename...> typename TTargetContainer, typename... TTargetContainerArgs>
273 286 constexpr auto collect() {
274 286 return Collector<TSelf, TTargetContainer, TTargetContainerArgs...>::template collect<Item, ItemOwned>(*self());
275 }
276
277 /**
278 * @brief Consumer that collects all elements from this iterator in a new container of type @p TTargetContainer
279 * @note This consumes the iterator.
280 * @tparam TTargetContainer Fully qualified type of the target container to collect the items of this iterator into.
281 * @return An instance of @p TTargetContainer with all the elements of this iterator collected into.
282 *
283 * Usage Example:
284 * - std::vector<std::string>
285 * @code
286 * std::vector<std::string> input = {"1337", "42", "64"};
287 * std::vector<std::string> output = CXXIter::from(input)
288 * .collect<std::vector<std::string>>();
289 * @endcode
290 *
291 * - std::vector<std::string> with explicitly defined allocator
292 * @code
293 * std::vector<std::string> input = {"1337", "42", "64"};
294 * std::vector<std::string, std::allocator<std::string>> output = CXXIter::from(input)
295 * .collect<std::vector<std::string, std::allocator<std::string>>>();
296 * @endcode
297 *
298 * - std::array<std::string, 3>
299 * @code
300 * std::vector<std::string> input = {"1337", "42", "64"};
301 * std::array<std::string, 3> output = CXXIter::from(input)
302 * .collect<std::array<std::string, 3>>();
303 * @endcode
304 */
305 template<typename TTargetContainer>
306 46 constexpr TTargetContainer collect() {
307 46 TTargetContainer container;
308
1/2
✓ Branch 1 taken 23 times.
✗ Branch 2 not taken.
46 collectInto(container);
309 46 return container;
310 }
311
312 /**
313 * @brief Consumer that collects all elements from this iterator into the given @p container.
314 * @note This consumes the iterator.
315 * @param container to collect this iterator's elements into.
316 * @details Before appending this iterator's elements to the elements already present in the
317 * given @p container, the collector tries to resize the @p container to its current size + this
318 * iterator's expected amount of items.
319 *
320 * Usage Example:
321 * @code
322 * std::vector<std::string> input = {"1337", "42", "64"};
323 * std::vector<std::string> output = {"prevElement"};
324 * CXXIter::from(input).collectInto(output);
325 * // output == {"prevElement", "1337", "42", "64"}
326 * @endcode
327 */
328 template<typename TTargetContainer>
329 96 constexpr void collectInto(TTargetContainer& container) {
330 96 IntoCollector<TSelf, TTargetContainer>::collectInto(*self(), container);
331 96 }
332
333 /**
334 * @brief Consumer that executes the given @p foldFn for each item in this iterator, to apply
335 * to a working value, which is passed on and passed as second argument to the next call to @p foldFn.
336 * @note This consumes the iterator.
337 * @param startValue The initial value of the working value passed to @p foldFn.
338 * @param foldFn Function called for each element in this iterator, passed the current workingValue and
339 * an element from this iterator.
340 * @return The workingValue from the last call to @p foldFn for the last element from this iterator.
341 *
342 * Usage Example:
343 * @code
344 * std::vector<double> input = {1.331335363800390, 1.331335363800390, 1.331335363800390, 1.331335363800390};
345 * double output = CXXIter::from(input)
346 * .fold(1.0, [](double& workingValue, double item) {
347 * workingValue *= item;
348 * });
349 * // output ~ 3.141592653589793
350 * @endcode
351 */
352 template<typename TResult, std::invocable<TResult&, Item&&> FoldFn>
353 48 constexpr TResult fold(TResult startValue, FoldFn foldFn) {
354 48 TResult result = startValue;
355
1/2
✓ Branch 1 taken 24 times.
✗ Branch 2 not taken.
133 forEach([&result, &foldFn](Item&& item) { foldFn(result, std::forward<Item>(item)); });
356 48 return result;
357 }
358
359 /**
360 * @brief Tests if all elements of this iterator match the given @p predicateFn.
361 * @note This consumes the iterator.
362 * @param predicateFn Predicate to test all items of this iterator against.
363 * @return @c true when the given @p predicateFn returned @c true for all elements of this
364 * iterator, @c false otherwise.
365 *
366 * Usage Example:
367 * (Using the following predicate)
368 * @code
369 * auto intAsBoolFn = [](uint32_t item) -> bool { return (item != 0); };
370 * @endcode
371 *
372 * - For cases where the predicate does not return @c true for all elements:
373 * @code
374 * std::vector<uint32_t> input = { 1, 1, 1, 0 };
375 * bool output = CXXIter::from(input).copied().all(intAsBoolFn);
376 * // output == false
377 *
378 * std::vector<uint32_t> input = { 0, 1, 1, 1 };
379 * bool output = CXXIter::from(input).copied().all(intAsBoolFn);
380 * // output == false
381 *
382 * std::vector<uint32_t> input = { 0, 0, 1, 1 };
383 * bool output = CXXIter::from(input).copied().all(intAsBoolFn);
384 * // output == false
385 * @endcode
386 *
387 * - For cases where the predicate does return @c true for all elements:
388 * @code
389 * std::vector<uint32_t> input = { 1, 1, 1, 1 };
390 * bool output = CXXIter::from(input).copied().all(intAsBoolFn);
391 * // output == true
392 * @endcode
393 */
394 template<std::invocable<const ItemOwned&> TPredicateFn>
395 requires std::same_as<std::invoke_result_t<TPredicateFn, const ItemOwned&>, bool>
396 24 constexpr bool all(TPredicateFn predicateFn) {
397
1/2
✓ Branch 2 taken 12 times.
✗ Branch 3 not taken.
24 return !skipWhile(predicateFn).next().has_value();
398 }
399
400 /**
401 * @brief Tests if all elements of this iterator yield the value @c true when casted to @c bool.
402 * @note This consumes the iterator.
403 * @details This is an overload of all(TPredicateFn) for item types that support
404 * being casted to @c bool.
405 * @return @c true when all elements of this iterator yielded the value @c true when casted to
406 * a @c bool, @c false otherwise.
407 *
408 * Usage Example:
409 * - For cases where not all elements of this iterator evaluate to @c true when casted to @c bool.
410 * @code
411 * std::vector<bool> input = { true, true, true, false };
412 * bool output = CXXIter::from(input).copied().all();
413 * // output == false
414 *
415 * std::vector<bool> input = { false, true, true, true };
416 * bool output = CXXIter::from(input).copied().all();
417 * // output == false
418 *
419 * std::vector<bool> input = { true, true, false, true };
420 * bool output = CXXIter::from(input).copied().all();
421 * // output == false
422 * @endcode
423 *
424 * - For cases where all elements of this iterator evaluate to @c true when casted to @c bool.
425 * @code
426 * std::vector<bool> input = { true, true, true, true };
427 * bool output = CXXIter::from(input).copied().all();
428 * // output == true
429 * @endcode
430 */
431 7 constexpr bool all() requires requires(const ItemOwned& item) {
432 {static_cast<bool>(item)};
433 } {
434 25 return all([](const auto& item) -> bool { return item; });
435 }
436
437 /**
438 * @brief Tests if any of the elements of this iterator match the given @p predicateFn.
439 * @note This consumes the iterator.
440 * @param predicateFn Predicate to test all items of this iterator against.
441 * @return @c true when the given @p predicateFn returned @c true for any of the elements
442 * of this iterator, @c false otherwise.
443 *
444 * Usage Example:
445 * (Using the following predicate)
446 * @code
447 * auto intAsBoolFn = [](uint32_t item) -> bool { return (item != 0); };
448 * @endcode
449 *
450 * - For the case where the @p predicateFn returns @c false for all elements:
451 * @code
452 * std::vector<uint32_t> input = { 0, 0, 0, 0 };
453 * bool output = CXXIter::from(input).copied().any(intAsBoolFn);
454 * // output == false
455 * @endcode
456 * - For the case where the @p predicateFn returns @c true for any of the elements:
457 * @code
458 * std::vector<uint32_t> input = { 0, 1, 1, 1 };
459 * bool output = CXXIter::from(input).copied().any(intAsBoolFn);
460 * // output == true
461 *
462 * std::vector<uint32_t> input = { 0, 0, 0, 1 };
463 * bool output = CXXIter::from(input).copied().any(intAsBoolFn);
464 * // output == true
465 *
466 * std::vector<uint32_t> input = { 1, 1, 1, 1 };
467 * bool output = CXXIter::from(input).copied().any(intAsBoolFn);
468 * // output == true
469 * @endcode
470 */
471 template<std::invocable<const ItemOwned&> TPredicateFn>
472 24 constexpr bool any(TPredicateFn predicateFn) {
473
1/2
✓ Branch 2 taken 12 times.
✗ Branch 3 not taken.
24 return filter(predicateFn).next().has_value();
474 }
475
476 /**
477 * @brief Tests if any of the elements of this iterator yield the value @c true when casted to @c bool.
478 * @note This consumes the iterator.
479 * @details This is an overload of any(TPredicateFn) for item types that support
480 * being casted to @c bool.
481 * @return @c true when any of the elements of this iterator yielded the value @c true when casted to
482 * a @c bool, @c false otherwise.
483 *
484 * Usage Example:
485 * - For cases where none of the elements yields the value @c true when casted to @c bool.
486 * @code
487 * std::vector<bool> input = { false, false, false, false };
488 * bool output = CXXIter::from(input).copied().any();
489 * // output == false
490 * @endcode
491 *
492 * - For cases where any of the elements yields the value @c true when casted to @c bool.
493 * @code
494 * std::vector<bool> input = { false, true, true, true };
495 * bool output = CXXIter::from(input).copied().any();
496 * // output == true
497 *
498 * std::vector<bool> input = { true, false, false, false };
499 * bool output = CXXIter::from(input).copied().any();
500 * // output == true
501 *
502 * std::vector<bool> input = { true, true, true, true };
503 * bool output = CXXIter::from(input).copied().any();
504 * // output == true
505 * @endcode
506 */
507 7 constexpr bool any() requires requires(const ItemOwned& item) {
508 {static_cast<bool>(item)};
509 } {
510 20 return any([](const auto& item) -> bool { return item; });
511 }
512
513 /**
514 * @brief Search for the given @p searchItem within the items of this iterator, and return the index of the first item
515 * from the iterator that is equal to the given @p searchItem.
516 * @param searchItem Item to search for in the iterator.
517 * @return Index of the given @p searchItem in the iterator, if found.
518 *
519 * Usage Example:
520 * - When item is found in the iterator:
521 * @code
522 * std::vector<int> input = {42, 1337, 52};
523 * std::optional<size_t> output = CXXIter::from(input).findIdx(1337);
524 * // output == Some(1)
525 * @endcode
526 * - When item is not found in the iterator:
527 * @code
528 * std::vector<int> input = {"42", "1337", "52"};
529 * std::optional<size_t> output = CXXIter::from(input).findIdx("not found");
530 * // output == None
531 * @endcode
532 */
533 6 constexpr std::optional<size_t> findIdx(const ItemOwned& searchItem) requires requires(const ItemOwned& searchItem, const Item& item) {
534 {searchItem == item} -> std::same_as<bool>;
535 } {
536 12 return findIdx([&searchItem](const ItemOwned& item) {
537 6 return (searchItem == item);
538 6 });
539 }
540
541
542 /**
543 * @brief Search for the iterator with the given @p findFn, and return the index of the element from this iterator,
544 * for which the @p findFn returned @c true the first time.
545 * @param findFn Lambda invoked for each element of this stream, to determined whether it is the item that is searched for.
546 * @return Index of the first element from this stream, for which the invocation to the given @p findFn returned @c true.
547 *
548 * Usage Example:
549 * - When item is found in the iterator:
550 * @code
551 * std::vector<int> input = {1337, 31337, 41, 43, 42, 64};
552 * std::optional<size_t> output = CXXIter::from(input)
553 * .findIdx([](int item) { return (item % 2 == 0); });
554 * // output == Some(4)
555 * @endcode
556 * - When item is not found in the iterator:
557 * @code
558 * std::vector<int> input = {1337, 31337, 41, 43};
559 * std::optional<size_t> output = CXXIter::from(input)
560 * .findIdx([](int item) { return (item % 2 == 0); });
561 * // output == None
562 * @endcode
563 */
564 template<std::invocable<const ItemOwned&> TFindFn>
565 10 constexpr std::optional<size_t> findIdx(TFindFn findFn) {
566 10 size_t idx = 0;
567 24 while(true) {
568
1/2
✓ Branch 2 taken 17 times.
✗ Branch 3 not taken.
34 auto item = Iterator::next(*self());
569
2/2
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 15 times.
34 if(!item.has_value()) [[unlikely]] { return {}; }
570
3/4
✓ Branch 1 taken 15 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 3 times.
✓ Branch 5 taken 12 times.
30 if(findFn(item.value())) [[unlikely]] { return idx; }
571 24 idx += 1;
572 }
573 }
574
575 /**
576 * @brief Searches for an element of this iterator, that satisfies the given @p findFn predicate.
577 * @param findFn Predicate used to search for an element in this iterator.
578 * @return An CXXIter::IterValue containing the first element, for which the @p findFn predicate
579 * returned @c true (if any), otherwise empty.
580 *
581 * Usage Example:
582 * - When item is found in the iterator:
583 * @code
584 * std::vector<std::string> input = {"42", "1337", "52"};
585 * CXXIter::IterValue<std::string&> output = CXXIter::from(input)
586 * .find([](const std::string& item) {
587 * return item.size() == 4;
588 * });
589 * // output == Some("1337"&)
590 * @endcode
591 * - When item is not found in the iterator:
592 * @code
593 * std::vector<std::string> input = {"42", "1337", "52"};
594 * CXXIter::IterValue<std::string&> output = CXXIter::from(input)
595 * .find([](const std::string& item) {
596 * return item.size() == 3;
597 * });
598 * // output == None
599 * @endcode
600 */
601 template<std::invocable<const ItemOwned&> TFindFn>
602 4 constexpr IterValue<Item> find(TFindFn findFn) {
603
1/2
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
8 return filter(findFn).next();
604 }
605
606 /**
607 * @brief Consumer that counts the elements in this iterator.
608 * @note This consumes the iterator.
609 * @return The amount of elements in this iterator
610 *
611 * Usage Example:
612 * @code
613 * std::vector<int> input = {42, 1337, 52};
614 * size_t output = CXXIter::from(input).count();
615 * // output == 3
616 * std::vector<int> input2 = {};
617 * size_t output2 = CXXIter::from(input2).count();
618 * // output == 0
619 * @endcode
620 */
621 2 constexpr size_t count() {
622 2 return fold((size_t)0, [](size_t& cnt, auto&&) { cnt += 1; });
623 }
624
625 /**
626 * @brief Consumer that counts the elements in this iterator, for which the given @p predicateFn
627 * returns @c true.
628 * @note This consumes the iterator.
629 * @param predicateFn Predicate that is run for each element of this iterator, to determine whether it
630 * should contribute to the resulting count.
631 * @return The amount of elements in this iterator for which the given @p predicateFn returned @c true.
632 *
633 * Usage Example:
634 * @code
635 * std::vector<int> input = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11};
636 * size_t output = CXXIter::from(input)
637 * .count([](int item){ return (item % 2 == 0); });
638 * // output == 5
639 * @endcode
640 */
641 template<std::invocable<const ItemOwned&> TPredicateFn>
642 4 constexpr size_t count(TPredicateFn predicateFn) {
643 38 return fold((size_t)0, [&predicateFn](size_t& cnt, auto&& item) {
644
3/4
✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
✓ Branch 4 taken 5 times.
✓ Branch 5 taken 6 times.
17 if(predicateFn(item)) { cnt += 1; }
645 4 });
646 }
647
648 /**
649 * @brief Consumer that counts the occurences of @p countItem within this iterator.
650 * @note This consumes the iterator.
651 * @param countItem Item for which to count the amount of occurences within this iterator.
652 * @return The number of occurences of @p countItem within this iterator.
653 *
654 * Usage Example:
655 * @code
656 * std::vector<int> input = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11};
657 * size_t output = CXXIter::from(input)
658 * .map([](int item) { return (item % 2 == 0); })
659 * .count(true);
660 * // output == 5
661 * @endcode
662 */
663 4 constexpr size_t count(const ItemOwned& countItem)
664 requires requires(const ItemOwned& countItem, Item&& item) {
665 {countItem == item};
666 } {
667 38 return fold((size_t)0, [&countItem](size_t& cnt, auto&& item) {
668
3/4
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
✓ Branch 2 taken 5 times.
✓ Branch 3 taken 6 times.
17 if(item == countItem) { cnt += 1; }
669 4 });
670 }
671
672
673 /**
674 * @brief Consumer that calculates the sum of all elements from this iterator.
675 * @note This consumes the iterator.
676 * @param startValue Starting value from which to start the sum.
677 * @return The sum of all elements from this iterator, or @p startValue if this
678 * iterator had no elements.
679 *
680 * Usage Example:
681 * - Non-empty iterator with default startValue
682 * @code
683 * std::vector<int> input = {42, 1337, 52};
684 * int output = CXXIter::from(input).sum();
685 * // output == 1431
686 * @endcode
687 * - Non-Empty iterator with custom startValue of 29906
688 * @code
689 * std::vector<int> input = {42, 1337, 52};
690 * int output = CXXIter::from(input).sum(29906);
691 * // output == 31337
692 * @endcode
693 * - Empty iterator with default startValue
694 * @code
695 * std::vector<int> input = {};
696 * int output = CXXIter::from(input).sum();
697 * // output == 0
698 * @endcode
699 * - Empty iterator with custom startValue
700 * @code
701 * std::vector<int> input = {};
702 * int output = CXXIter::from(input).sum(31337);
703 * // output == 31337
704 * @endcode
705 */
706 template<typename TResult = ItemOwned>
707 requires requires(TResult res, Item item) { { res += item }; }
708 8 constexpr TResult sum(TResult startValue = TResult()) {
709 16 return fold(startValue, [](TResult& res, Item&& item) { res += item; });
710 }
711
712 /**
713 * @brief Consumer that concatenates the elements of this iterator to a large @c std::string , where
714 * each element is separated by the specified @p separator.
715 * @note This consumes the iterator.
716 * @note This method is only available for iterators whose elements are @c std::string . If that is not
717 * the case, convert your items to @c std::string s first, using a method like @c map().
718 * @return The resulting string concatenation of all items of this iterator.
719 *
720 * Usage Example:
721 * - Non-empty iterator with default startValue
722 * @code
723 * std::vector<int> input = {42, 1337, 52};
724 * int output = CXXIter::from(input).sum();
725 * // output == 1431
726 * @endcode
727 * - Non-Empty iterator with custom startValue of 29906
728 * @code
729 * std::vector<int> input = {42, 1337, 52};
730 * int output = CXXIter::from(input).sum(29906);
731 * // output == 31337
732 * @endcode
733 * - Empty iterator with default startValue
734 * @code
735 * std::vector<int> input = {};
736 * int output = CXXIter::from(input).sum();
737 * // output == 0
738 * @endcode
739 * - Empty iterator with custom startValue
740 * @code
741 * std::vector<int> input = {};
742 * int output = CXXIter::from(input).sum(31337);
743 * // output == 31337
744 * @endcode
745 */
746 4 std::string stringJoin(const std::string& separator) requires std::is_same_v<ItemOwned, std::string> {
747 4 std::string result;
748
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
7 forEach([&result, &separator](const std::string& item) {
749
3/8
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 10 taken 2 times.
✓ Branch 11 taken 1 times.
✓ Branch 14 taken 2 times.
✗ Branch 15 not taken.
3 if(result.size() > 0) [[likely]] { result += separator + item; }
750 1 else [[unlikely]] { result = item; }
751 });
752 4 return result;
753 }
754
755 /**
756 * @brief Consumer that calculates the mean of all elements of this iterator.
757 * @details The mean is calculated by first summing up all elements, and then
758 * dividing through the number of elements counted while summing.
759 * @note This consumes the iterator.
760 * @param sumStart Optional starting point for the sum of all items. Normally uses default ctor of @p TResult.
761 * @return The mean of all elements of this iterator.
762 * @tparam NORM Type of the statistical normalization variant to use for the
763 * calculation. @see StatisticNormalization
764 * @tparam TResult Type of the mean-calculation's result. This is also the type used
765 * for the sum of all elements.
766 * @tparam TCount Type the element counter is converted into, before dividing the sum
767 * by. This can be necessary, if TResult is a complex object that only supports the
768 * division operator for e.g. double.
769 *
770 * Usage Example:
771 * - For a non-empty iterator
772 * @code
773 * std::vector<float> input = {1.0f, 2.0f, 3.0f};
774 * std::optional<float> output = CXXIter::from(input).mean();
775 * // output == Some(2.0f)
776 * @endcode
777 * - For an empty iterator:
778 * @code
779 * std::vector<float> input = {};
780 * std::optional<float> output = CXXIter::from(input).mean();
781 * // output == None
782 * @endcode
783 */
784 template<StatisticNormalization NORM = StatisticNormalization::N, typename TResult = ItemOwned, typename TCount = ItemOwned>
785 22 constexpr std::optional<TResult> mean(TResult sumStart = TResult()) {
786 22 size_t cnt = 0;
787
1/2
✓ Branch 1 taken 11 times.
✗ Branch 2 not taken.
58 TResult result = fold(sumStart, [&cnt](TResult& res, Item&& item) {
788 30 cnt += 1;
789 24 res += item;
790 });
791
2/2
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 1 times.
22 if(cnt > 0) {
792 if constexpr(NORM == StatisticNormalization::N) {
793 14 return result / static_cast<TCount>(cnt);
794 } else {
795 6 return result / static_cast<TCount>(cnt - 1);
796 }
797 }
798 2 return {};
799 }
800
801 /**
802 * @brief Consumer that calculates the variance of all elements of this iterator.
803 * @details The variance is calculated by incrementally calculating a sum and
804 * a squared sum of all elements. Then from there, the mean and then the variance
805 * are calculated.
806 * @note This consumes the iterator.
807 * @return The variance of all elements of this iterator.
808 * @tparam NORM Type of the statistical normalization variant to use for the
809 * calculation. @see StatisticNormalization
810 * @tparam TResult Type of the variance-calculation's result. This is also the type used
811 * for the sum of all elements.
812 * @tparam TCount Type the element counter is converted into, before dividing the sum and
813 * the squared sum by. This can be necessary, if TResult is a complex object that only supports
814 * the division operator for e.g. double.
815 * @see https://en.wikipedia.org/wiki/Algorithms_for_calculating_variance
816 *
817 * Usage Example:
818 * - For iterators with at least 2 values:
819 * @code
820 * std::vector<float> input = {2.0f, 4.0f, 4.0f, 4.0f, 5.0f, 5.0f, 7.0f, 9.0f};
821 * std::optional<float> output = CXXIter::from(input).variance();
822 * // output == Some(4.0f)
823 * @endcode
824 * - For iterators with at least 2 values with (N-1) norm:
825 * @code
826 * std::vector<float> input = {1.0f, 2.0f, 3.0f};
827 * std::optional<float> output = CXXIter::from(input)
828 * .variance<CXXIter::StatisticNormalization::N_MINUS_ONE>();
829 * // output == Some(1.0f)
830 * @endcode
831 * - For iterators with less than 2 values (not defined):
832 * @code
833 * std::vector<float> input = {42.0f};
834 * std::optional<float> output = CXXIter::from(input).variance();
835 * // output == None
836 * @endcode
837 */
838 template<StatisticNormalization NORM = StatisticNormalization::N, typename TResult = ItemOwned, typename TCount = ItemOwned>
839 22 constexpr std::optional<TResult> variance() {
840 22 TResult sumSquare = TResult();
841 22 TResult sum = TResult();
842 22 size_t cnt = 0;
843
1/2
✓ Branch 1 taken 11 times.
✗ Branch 2 not taken.
60 forEach([&sumSquare, &sum, &cnt](Item&& item) {
844 38 sum += item;
845 38 sumSquare += (item * item);
846 38 cnt += 1;
847 });
848
2/2
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 4 times.
22 if(cnt >= 2) {
849 if constexpr(NORM == StatisticNormalization::N) {
850 8 TResult E1 = (sumSquare / static_cast<TCount>(cnt));
851 8 TResult E2 = (sum / static_cast<TCount>(cnt));
852 8 return E1 - (E2 * E2);
853 } else {
854 6 TResult E1 = (sum * sum / static_cast<TCount>(cnt));
855 6 return (sumSquare - E1) / static_cast<TCount>(cnt - 1);
856 }
857 }
858 8 return {};
859 }
860
861 /**
862 * @brief Consumer that calculates the standard deviation of all elements of this iterator.
863 * @details The standard deviation is calculated using @see variance().
864 * @note This consumes the iterator.
865 * @return The standard deviation of all elements of this iterator.
866 * @tparam NORM Type of the statistical normalization variant to use for the
867 * calculation. @see StatisticNormalization
868 * @tparam TResult Type of the stddev-calculation's result. This is also the type used
869 * for the sum of all elements.
870 * @tparam TCount Type the element counter is converted into, before dividing the sum and
871 * the squared sum by. This can be necessary, if TResult is a complex object that only supports
872 * the division operator for e.g. double.
873 *
874 * Usage Example:
875 * - For iterators with at least 2 values:
876 * @code
877 * std::vector<float> input = {2.0f, 4.0f, 4.0f, 4.0f, 5.0f, 5.0f, 7.0f, 9.0f};
878 * std::optional<float> output = CXXIter::from(input).stddev();
879 * // output == Some(2.0f)
880 * @endcode
881 * - For iterators with at least 2 values with (N-1) norm:
882 * @code
883 * std::vector<float> input = {1.0f, 2.0f, 3.0f};
884 * std::optional<float> output = CXXIter::from(input)
885 * .stddev<CXXIter::StatisticNormalization::N_MINUS_ONE>();
886 * // output == Some(1.0f)
887 * @endcode
888 * - For iterators with less than 2 values (not defined):
889 * @code
890 * std::vector<float> input = {42.0f};
891 * std::optional<float> output = CXXIter::from(input).stddev();
892 * // output == None
893 * @endcode
894 */
895 template<StatisticNormalization NORM = StatisticNormalization::N, typename TResult = ItemOwned, typename TCount = ItemOwned>
896 10 constexpr std::optional<TResult> stddev() {
897
1/2
✓ Branch 1 taken 5 times.
✗ Branch 2 not taken.
10 std::optional<TResult> result = variance<NORM, TResult, TCount>();
898
3/4
✓ Branch 1 taken 3 times.
✓ Branch 2 taken 2 times.
✓ Branch 4 taken 3 times.
✗ Branch 5 not taken.
10 if(result.has_value()) { return std::sqrt(result.value()); }
899 4 return {};
900 }
901
902 /**
903 * @brief Consumer that yields the smallest element from this iterator.
904 * @note This consumes the iterator.
905 * @return A CXXIter::IterValue optional either containing the smallest element of this iterator (if any),
906 * or empty otherwise.
907 *
908 * Usage Example:
909 * - For a non-empty iterator
910 * @code
911 * std::vector<int> input = {42, 1337, 52};
912 * std::optional<int> output = CXXIter::from(input)
913 * .min().toStdOptional();
914 * // output == Some(42)
915 * @endcode
916 * - For an empty iterator:
917 * @code
918 * std::vector<int> input = {};
919 * std::optional<int> output = CXXIter::from(input)
920 * .min().toStdOptional();
921 * // output == None
922 * @endcode
923 */
924 2 constexpr IterValue<Item> min() {
925 5 return minBy([](auto&& item) { return item; });
926 }
927
928 /**
929 * @brief Consumer that yields the index of the smallest element within this iterator.
930 * @note This consumes the iterator.
931 * @return Index of the smallest element within the input iterator (if any).
932 *
933 * Usage Example:
934 * - For a non-empty iterator
935 * @code
936 * std::vector<int> input = {1337, 42, 52};
937 * std::optional<size_t> output = CXXIter::from(input).minIdx();
938 * // output == Some(1)
939 * @endcode
940 * - For an empty iterator:
941 * @code
942 * std::vector<int> input = {};
943 * std::optional<size_t> output = CXXIter::from(input).minIdx();
944 * // output == None
945 * @endcode
946 */
947 2 constexpr std::optional<size_t> minIdx() {
948 5 return minIdxBy([](auto&& item) { return item; });
949 }
950
951 /**
952 * @brief Consumer that yields the largest element from this iterator.
953 * @note This consumes the iterator.
954 * @return A CXXIter::IterValue optional either containing the largest element of this iterator (if any),
955 * or empty otherwise.
956 *
957 * Usage Example:
958 * - For a non-empty iterator
959 * @code
960 * std::vector<int> input = {42, 1337, 52};
961 * std::optional<int> output = CXXIter::from(input)
962 * .max().toStdOptional();
963 * // output == Some(1337)
964 * @endcode
965 * - For an empty iterator:
966 * @code
967 * std::vector<int> input = {};
968 * std::optional<int> output = CXXIter::from(input)
969 * .max().toStdOptional();
970 * // output == None
971 * @endcode
972 */
973 2 constexpr IterValue<Item> max() {
974 5 return maxBy([](auto&& item) { return item; });
975 }
976
977 /**
978 * @brief Consumer that yields the index of the largest element within this iterator.
979 * @note This consumes the iterator.
980 * @return Index of the largest element within the input iterator (if any).
981 *
982 * Usage Example:
983 * - For a non-empty iterator
984 * @code
985 * std::vector<int> input = {42, 1337, 52};
986 * std::optional<size_t> output = CXXIter::from(input).maxIdx();
987 * // output == Some(1)
988 * @endcode
989 * - For an empty iterator:
990 * @code
991 * std::vector<int> input = {};
992 * std::optional<size_t> output = CXXIter::from(input).maxIdx();
993 * // output == None
994 * @endcode
995 */
996 2 constexpr std::optional<size_t> maxIdx() {
997 5 return maxIdxBy([](auto&& item) { return item; });
998 }
999
1000 /**
1001 * @brief Consumer that yields the smallest element from this iterator. Comparison of items is done
1002 * using the comparison values returned by invoking the given @p compValueExtractFn on each element.
1003 * @note This consumes the iterator.
1004 * @param compValueExtractFn Function that, given an element from the input iterator as parameter returns
1005 * the value by which the item should be compared to others.
1006 * @return A CXXIter::IterValue optional either containing the smallest element of this iterator (if any),
1007 * or empty otherwise.
1008 *
1009 * Usage Example:
1010 * - For a non-empty iterator
1011 * @code
1012 * std::vector<std::string> input = {"smol", "middle", "largeString"};
1013 * std::optional<std::string> output = CXXIter::from(input)
1014 * .minBy([](const std::string& str) { return str.size(); })
1015 * .toStdOptional();
1016 * // output == Some("smol")
1017 * @endcode
1018 * - For an empty iterator:
1019 * @code
1020 * std::vector<std::string> input = {};
1021 * std::optional<std::string> output = CXXIter::from(input)
1022 * .minBy([](const std::string& str) { return str.size(); })
1023 * .toStdOptional();
1024 * // output == None
1025 * @endcode
1026 */
1027 template<typename TCompValueExtractFn>
1028 requires requires(const std::invoke_result_t<TCompValueExtractFn, Item&&>& a, std::remove_cvref_t<decltype(a)> ownedA) {
1029 { a < a };
1030 { ownedA = ownedA };
1031 }
1032 12 constexpr IterValue<Item> minBy(TCompValueExtractFn compValueExtractFn) {
1033
1/2
✓ Branch 2 taken 6 times.
✗ Branch 3 not taken.
12 IterValue<Item> result = Iterator::next(*self());
1034
2/2
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 4 times.
12 if(!result.has_value()) { return {}; }
1035
1/2
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
8 auto resultValue = compValueExtractFn(std::forward<Item>(result.value()));
1036
1/2
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
36 forEach([&result, &resultValue, &compValueExtractFn](Item&& item) {
1037 8 auto itemValue = compValueExtractFn(std::forward<Item>(item));
1038
7/10
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 times.
✓ Branch 5 taken 1 times.
✓ Branch 6 taken 1 times.
✓ Branch 7 taken 1 times.
✓ Branch 8 taken 1 times.
✓ Branch 9 taken 1 times.
8 if(itemValue < resultValue) {
1039 3 result = item;
1040 3 resultValue = itemValue;
1041 }
1042 });
1043 8 return result;
1044 }
1045
1046 /**
1047 * @brief Consumer that yields the index of the smallest element from this iterator. Comparison of items is done
1048 * using the comparison values returned by invoking the given @p compValueExtractFn on each element.
1049 * @note This consumes the iterator.
1050 * @param compValueExtractFn Function that, given an element from the input iterator as parameter, returns
1051 * the value by which the item should be compared to others.
1052 * @return Index of the smallest element within the input iterator (if any).
1053 *
1054 * Usage Example:
1055 * - For a non-empty iterator
1056 * @code
1057 * const std::vector<std::string> input = {"middle", "smol", "largeString"};
1058 * std::optional<size_t> output = CXXIter::SrcCRef(input)
1059 * .minIdxBy([](const std::string& str) { return str.size(); });
1060 * // output = Some(1)
1061 * @endcode
1062 * - For an empty iterator:
1063 * @code
1064 * const std::vector<std::string> input = {};
1065 * std::optional<size_t> output = CXXIter::SrcCRef(input)
1066 * .minIdxBy([](const std::string& str) { return str.size(); });
1067 * // output = None
1068 * @endcode
1069 */
1070 template<typename TCompValueExtractFn>
1071 requires requires(const std::invoke_result_t<TCompValueExtractFn, Item&&>& a) {
1072 { a < a };
1073 }
1074 12 constexpr std::optional<size_t> minIdxBy(TCompValueExtractFn compValueExtractFn) {
1075
1/2
✓ Branch 2 taken 6 times.
✗ Branch 3 not taken.
12 IterValue<Item> tmp = Iterator::next(*self());
1076
2/2
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 4 times.
12 if(!tmp.has_value()) { return {}; }
1077 8 size_t iterationIdx = 1, minIdx = 0;
1078
1/2
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
8 auto minValue = compValueExtractFn(std::forward<Item>(tmp.value()));
1079
1/2
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
36 forEach([iterationIdx, &minIdx, &minValue, &compValueExtractFn](Item&& item) mutable {
1080 8 auto itemValue = compValueExtractFn(std::forward<Item>(item));
1081
8/10
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 times.
✓ Branch 5 taken 1 times.
✓ Branch 6 taken 1 times.
✓ Branch 7 taken 1 times.
✓ Branch 8 taken 1 times.
✓ Branch 9 taken 1 times.
8 if(itemValue < minValue) {
1082 4 minValue = itemValue;
1083 4 minIdx = iterationIdx;
1084 }
1085 8 iterationIdx += 1;
1086 });
1087 8 return minIdx;
1088 }
1089
1090 /**
1091 * @brief Consumer that yields the largest element from this iterator. Comparison of items is done
1092 * using the comparison values returned by invoking the given @p compValueExtractFn on each element.
1093 * @note This consumes the iterator.
1094 * @param compValueExtractFn Function that, given an element from the input iterator as parameter returns
1095 * the value by which the item should be compared to others.
1096 * @return A CXXIter::IterValue optional either containing the largest element of this iterator (if any),
1097 * or empty otherwise.
1098 *
1099 * Usage Example:
1100 * - For a non-empty iterator
1101 * @code
1102 * std::vector<std::string> input = {"smol", "middle", "largeString"};
1103 * std::optional<std::string> output = CXXIter::from(input)
1104 * .maxBy([](const std::string& str) { return str.size(); })
1105 * .toStdOptional();
1106 * // output == Some("largeString")
1107 * @endcode
1108 * - For an empty iterator:
1109 * @code
1110 * std::vector<std::string> input = {};
1111 * std::optional<std::string> output = CXXIter::from(input)
1112 * .maxBy([](const std::string& str) { return str.size(); })
1113 * .toStdOptional();
1114 * // output == None
1115 * @endcode
1116 */
1117 template<typename TMaxValueExtractFn>
1118 requires requires(const std::invoke_result_t<TMaxValueExtractFn, Item&&>& a, std::remove_cvref_t<decltype(a)> ownedA) {
1119 { a > a };
1120 { ownedA = ownedA };
1121 }
1122 12 constexpr IterValue<Item> maxBy(TMaxValueExtractFn compValueExtractFn) {
1123
1/2
✓ Branch 2 taken 6 times.
✗ Branch 3 not taken.
12 IterValue<Item> result = Iterator::next(*self());
1124
2/2
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 4 times.
12 if(!result.has_value()) { return {}; }
1125
1/2
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
8 auto resultValue = compValueExtractFn(std::forward<Item>(result.value()));
1126
1/2
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
41 forEach([&result, &resultValue, &compValueExtractFn](Item&& item) {
1127 8 auto itemValue = compValueExtractFn(std::forward<Item>(item));
1128
5/10
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 2 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 2 times.
✗ Branch 9 not taken.
8 if(itemValue > resultValue) {
1129 7 result = item;
1130 7 resultValue = itemValue;
1131 }
1132 });
1133 8 return result;
1134 }
1135
1136 /**
1137 * @brief Consumer that yields the index of the largest element from this iterator. Comparison of items is done
1138 * using the comparison values returned by invoking the given @p TCompValueExtractFn on each element.
1139 * @note This consumes the iterator.
1140 * @param compValueExtractFn Function that, given an element from the input iterator as parameter, returns
1141 * the value by which the item should be compared to others.
1142 * @return Index of the largest element within the input iterator (if any).
1143 *
1144 * Usage Example:
1145 * - For a non-empty iterator
1146 * @code
1147 * const std::vector<std::string> input = {"middle", "largeString", "smol"};
1148 * std::optional<size_t> output = CXXIter::SrcCRef(input)
1149 * .maxIdxBy([](const std::string& str) { return str.size(); });
1150 * // output = Some(1)
1151 * @endcode
1152 * - For an empty iterator:
1153 * @code
1154 * const std::vector<std::string> input = {};
1155 * std::optional<size_t> output = CXXIter::SrcCRef(input)
1156 * .maxIdxBy([](const std::string& str) { return str.size(); });
1157 * // output = None
1158 * @endcode
1159 */
1160 template<typename TMaxValueExtractFn>
1161 requires requires(const std::invoke_result_t<TMaxValueExtractFn, Item&&>& a, std::remove_cvref_t<decltype(a)> ownedA) {
1162 { a > a };
1163 { ownedA = ownedA };
1164 }
1165 12 constexpr std::optional<size_t> maxIdxBy(TMaxValueExtractFn compValueExtractFn) {
1166
1/2
✓ Branch 2 taken 6 times.
✗ Branch 3 not taken.
12 IterValue<Item> tmp = Iterator::next(*self());
1167
2/2
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 4 times.
12 if(!tmp.has_value()) { return {}; }
1168 8 size_t iterationIdx = 1, maxIdx = 0;
1169
1/2
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
8 auto maxValue = compValueExtractFn(std::forward<Item>(tmp.value()));
1170
1/2
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
39 forEach([iterationIdx, &maxIdx, &maxValue, &compValueExtractFn](Item&& item) mutable {
1171 8 auto itemValue = compValueExtractFn(std::forward<Item>(item));
1172
5/10
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 2 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 2 times.
✗ Branch 9 not taken.
8 if(itemValue > maxValue) {
1173 7 maxValue = itemValue;
1174 7 maxIdx = iterationIdx;
1175 }
1176 8 iterationIdx += 1;
1177 });
1178 8 return maxIdx;
1179 }
1180
1181 /**
1182 * @brief Consumer that yields the last element of this iterator.
1183 * @note This consumes the iterator.
1184 * @return The last element of this iterator (if any).
1185 *
1186 * Usage Example:
1187 * - For a non-empty iterator
1188 * @code
1189 * std::vector<int> input = {42, 1337, 52};
1190 * std::optional<int> output = CXXIter::from(input)
1191 * .last()
1192 * .toStdOptional();
1193 * // output == Some(52)
1194 * @endcode
1195 * - For an empty iterator:
1196 * @code
1197 * std::vector<int> input = {};
1198 * std::optional<int> output = CXXIter::from(input)
1199 * .last()
1200 * .toStdOptional();
1201 * // output == None
1202 * @endcode
1203 */
1204 2 constexpr IterValue<Item> last() {
1205 2 IterValue<Item> tmp;
1206 5 forEach([&tmp](Item&& item) { tmp = item; });
1207 2 return tmp;
1208 }
1209
1210 /**
1211 * @brief Return the @p{n}-th element from this iterator (if available).
1212 * @param n Index of the element to return from this iterator.
1213 * @return The @p{n}-th element from this iterator.
1214 *
1215 * Usage Example:
1216 * - When the n-th element exists:
1217 * @code
1218 * std::vector<int> input = {42, 1337, 52};
1219 * std::optional<int> output = CXXIter::from(input).nth(1).toStdOptional();
1220 * // output == Some(1337)
1221 * @endcode
1222 * - When the n-th element does not exist:
1223 * @code
1224 * std::vector<int> input = {42, 1337, 52};
1225 * std::optional<int> output = CXXIter::from(input).nth(10).toStdOptional();
1226 * // output == None
1227 * @endcode
1228 */
1229 3 constexpr IterValue<Item> nth(size_t n) {
1230
1/2
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
6 return skip(n).next();
1231 }
1232 //@}
1233
1234
1235 // ###################
1236 // CHAINERS
1237 // ###################
1238 /**
1239 * @name Chainers
1240 */
1241 //@{
1242
1243 /**
1244 * @brief Constructs a new iterator that casts the elements of this iterator to the type requested by @p TItemOutput.
1245 * @details This iterator applies the requested type cast to @p TItemOutput using @c static_cast<>.
1246 * @tparam TItemOutput Type to cast the elements of this iterator to.
1247 * @return A new iterator that casts all elements from this iterator to the requested type @p TItemOutput.
1248 *
1249 * Usage Example:
1250 * @code
1251 * std::vector<float> input = {1.35, 56.123};
1252 * std::vector<double> output = CXXIter::from(input)
1253 * .cast<double>()
1254 * .collect<std::vector>();
1255 * @endcode
1256 */
1257 template<typename TItemOutput>
1258 5 constexpr op::Caster<TSelf, TItemOutput> cast() {
1259 5 return op::Caster<TSelf, TItemOutput>(std::move(*self()));
1260 }
1261
1262 /**
1263 * @brief Constructs a new iterator that copies the elements of this iterator.
1264 * @details This function essentially converts an iterator that is passing elements by
1265 * reference, to an iterator that is passing elements by value midway.
1266 * @return A new iterator that is passing copies of the original input elements by value.
1267 *
1268 * Usage Example:
1269 * @code
1270 * std::vector<std::string> input = {"inputString1", "inputString2"};
1271 * std::vector<std::string> output = CXXIter::from(input)
1272 * .copied() // clone values, now working with owned copies instead of references to input
1273 * .modify([](std::string& item) { item[item.size() - 1] += 1; }) // modify copies, input untouched
1274 * .collect<std::vector>();
1275 * @endcode
1276 */
1277 258 constexpr auto copied() {
1278 545 return map([](const ItemOwned& item) -> ItemOwned {
1279 91 ItemOwned copy = item;
1280 299 return copy;
1281 258 });
1282
1283 }
1284
1285 /**
1286 * @brief Constructs a new iterator that tags each element of this iterator with the corresponding index,
1287 * stored in a @c std::pair.
1288 * @return A new iterator whose elements are @c std::pair with an element index in the first, and the
1289 * original iterator's corresponding element in the second slot.
1290 *
1291 * Usage Example:
1292 * @code
1293 * std::vector<std::string> input = {"1337", "42", "64"};
1294 * std::vector<std::pair<size_t, std::string&>> output = CXXIter::from(input)
1295 * .indexed()
1296 * .collect<std::vector>();
1297 * // output == {{0, "1337"}, {1, "42"}, {2, "64"}}
1298 * @endcode
1299 */
1300 5 constexpr auto indexed() {
1301 5 size_t idx = 0;
1302 15 return map([idx](Item&& item) mutable -> std::pair<size_t, Item> {
1303 11 return std::pair<size_t, Item>(idx++, std::forward<Item>(item));
1304 5 });
1305 }
1306
1307 /**
1308 * @brief Constructs a new iterator that tags each element with a boolean value specifying whether the
1309 * element is the last one in the iterator. Boolean and actual iterator element are stored in a @c std::pair.
1310 * @return A new iterator whose elements are @c std::pair with the iterator element in the first, and a boolean
1311 * flag specifying whether the element will be the last one in the second slot.
1312 *
1313 * Usage Example:
1314 * - Flag last element in filtered iterator
1315 * @code
1316 * std::vector<std::string> input = {"1337", "42", "420", "64"};
1317 * std::vector<std::pair<std::string&, bool>> output = CXXIter::from(input)
1318 * .filter([](const std::string& el) { return el.size() >= 3; })
1319 * .flagLast()
1320 * .collect<std::vector>();
1321 * // output == {{"1337", false}, {"420", true}}
1322 * @endcode
1323 * - Use last flag to filter (remove last element from iterator)
1324 * @code
1325 * std::vector<std::string> input = {"1337", "42", "64"};
1326 * std::vector<std::pair<std::string&, bool>> output = CXXIter::from(input)
1327 * .flagLast()
1328 * .filter([](const std::pair<std::string&, bool>& el) { return !el.second; })
1329 * .collect<std::vector>();
1330 * // output == {{"1337", false}, {"42", false}}
1331 * @endcode
1332 */
1333 10 constexpr op::FlagLast<TSelf> flagLast() {
1334 10 return op::FlagLast<TSelf>(std::move(*self()));
1335 }
1336
1337 /**
1338 * @brief Constructs a new iterator that only contains the elements from this iterator, for
1339 * which the given @p filterFn returned @c true.
1340 * @param filterFn Function that decides which element of this iterator to yield in the
1341 * newly created iterator.
1342 * @return Iterator that only returns the elements for which the @p filterFn returns @c true.
1343 *
1344 * Usage Example:
1345 * @code
1346 * std::vector<int> input = {1, 2, 3, 4, 5, 6, 7, 8};
1347 * std::vector<int> output = CXXIter::from(input)
1348 * .filter([](int item) { return (item % 2) == 0; })
1349 * .collect<std::vector>();
1350 * @endcode
1351 */
1352 template<std::invocable<const ItemOwned&> TFilterFn>
1353 104 constexpr op::Filter<TSelf, TFilterFn> filter(TFilterFn filterFn) {
1354
1/2
✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
104 return op::Filter<TSelf, TFilterFn>(std::move(*self()), filterFn);
1355 }
1356
1357 /**
1358 * @brief Constructs a new iterator that only contains every element of the input iterator only once.
1359 * @details This variant checks whether the data returned by the given @p mapFn when invoked with the input's
1360 * item is unique. This requires the data returned by @p mapFn to be hashable using @c std::hash.
1361 * @param mapFn Function that maps the input's element to data that should be used in the uniqueness-check.
1362 * @return Iterator that does not contain duplicate elements from the input iterator's elements.
1363 * @attention Unique requires extra data storage to remember what items it has already seen. This
1364 * leads to additional memory usage.
1365 *
1366 * Usage Example:
1367 * @code
1368 * std::vector<double> input = {1.0, 1.0, 1.5, 1.4, 2.0, 2.1, 2.99, 3.25, 4.5};
1369 * std::vector<double> output = CXXIter::from(input)
1370 * .unique([](double item) { return std::floor(item); })
1371 * .copied()
1372 * .collect<std::vector>();
1373 * // output == { 1.0, 2.0, 3.25, 4.5 }
1374 * @endcode
1375 */
1376 template<std::invocable<const ItemOwned&> TMapFn>
1377 requires util::is_hashable<std::invoke_result_t<TMapFn, const ItemOwned&>>
1378 8 constexpr op::Unique<TSelf, TMapFn> unique(TMapFn mapFn) {
1379 8 return op::Unique<TSelf, TMapFn>(std::move(*self()), mapFn);
1380 }
1381
1382 /**
1383 * @brief Constructs a new iterator that only contains every element of the input iterator only once.
1384 * @details This variant uses the input elements directly for the uniqueness-comparison.
1385 * This requires the input elements to be hashable using @c std::hash.
1386 * @return Iterator that does not contain duplicate elements from the input iterator's elements.
1387 * @attention Unique requires extra data storage to remember what items it has already seen. This
1388 * leads to additional memory usage.
1389 *
1390 * Usage Example:
1391 * @code
1392 * std::vector<double> input = {1.0, 1.0, 1.5, 1.4, 2.0, 2.1, 2.99, 3.25, 4.5};
1393 * std::vector<double> output = CXXIter::from(input)
1394 * .unique()
1395 * .copied()
1396 * .collect<std::vector>();
1397 * // output == { 1.0, 1.5, 1.4, 2.0, 2.1, 2.99, 3.25, 4.5 }
1398 * @endcode
1399 */
1400 6 constexpr auto unique() {
1401 24 return unique([](const auto& item) { return item; });
1402 }
1403
1404 /**
1405 * @brief Constructs a new iterator that provides the elements of this iterator in reverse order.
1406 * @attention If the underlying iterator implements DoubleEndedIterator it is going to be used and this operation
1407 * will not have an additional cost. If the underlying iterator does not implement DoubleEndedIterator, it will
1408 * be emulated by first draining the iterator into a container and then providing those elements in reverse.
1409 * This leads to additional memory usage.
1410 * @return Iterator that provides the elements of this iterator in reverse order.
1411 *
1412 * Usage Example:
1413 * @code
1414 * std::vector<size_t> input = {1, 42, 2, 1337, 3, 4, 69, 5, 6, 5};
1415 * std::vector<size_t> output = CXXIter::from(input).copied()
1416 * .reverse()
1417 * .collect<std::vector>();
1418 * // output == { 5, 6, 5, 69, 4, 3, 1337, 2, 42, 1 }
1419 * @endcode
1420 */
1421 14 constexpr op::Reverse<TSelf> reverse() {
1422 14 return op::Reverse<TSelf>(std::move(*self()));
1423 }
1424
1425 /**
1426 * @brief Create new iterator that collects elements from this iterator in chunks of size up to @p CHUNK_SIZE, which then
1427 * constitue the elements of the new iterator.
1428 * @details Chunks are of up to @p CHUNK_SIZE elements in size. If the amount of items in the iterator are not dividable
1429 * by the requested @p CHUNK_SIZE the last chunk will be smaller.
1430 * @tparam CHUNK_SIZE Amount of elements from this iterator, that get collected to one chunk.
1431 * @return New iterator that contains chunks of up to the requested size, containing elements from this iterator as elements.
1432 *
1433 * Usage Example:
1434 * - If the amount of elements of the input can be evenly divided up into the requested @p CHUNK_SIZE :
1435 * @code
1436 * std::vector<size_t> input = {1337, 42, 512, 31337, 69, 5, 1, 2, 3};
1437 * auto output = CXXIter::from(input)
1438 * .copied()
1439 * .chunked<3>()
1440 * .collect<std::vector>();
1441 * // output == { {1337, 42, 512}, {31337, 69, 5}, {1, 2, 3} }
1442 * @endcode
1443 * - If the amount of elements of the input can **not** be evenly divided up into the requested @p CHUNK_SIZE :
1444 * @code
1445 * std::vector<size_t> input = {1337, 42, 512, 31337, 69, 5, 1, 2};
1446 * auto output = CXXIter::from(input)
1447 * .copied()
1448 * .chunked<3>()
1449 * .collect<std::vector>();
1450 * // output == { {1337, 42, 512}, {31337, 69, 5}, {1, 2} }
1451 * @endcode
1452 */
1453 template<const size_t CHUNK_SIZE>
1454 14 constexpr op::Chunked<TSelf, CHUNK_SIZE> chunked() {
1455 14 return op::Chunked<TSelf, CHUNK_SIZE>(std::move(*self()));
1456 }
1457
1458 /**
1459 * @brief Create new iterator that collects elements from this iterator in exact-sized chunks of @p CHUNK_SIZE, which then
1460 * constitue the elements of the new iterator.
1461 * @details A chunk is only committed in the new iterator, after it was filled completely. That means, that if the amount
1462 * of elements in this iterator do not evenly divide up to @p CHUNK_SIZE sized chunks, the last couple of elements that
1463 * fail to fill a complete chunk will be dropped.
1464 *
1465 * Where possible (for contiguous memory sources, such as @c std::vector<> or @c std::array<>), this method avoids creating
1466 * copies of the elements, and instead forwards an @c std::array<>& pointing at the memory position of the current chunk's
1467 * start. This essentially allows working directly on the source's memory region.
1468 * If this isn't possible because the source or any previous chainer method calls make direct source memory inaccessible,
1469 * this will fallback to using a temporary buffer, able to hold an entire chunk, that is filled by pulling elements from
1470 * this iterator into the buffer, before a const reference to the buffer is passed onwards.
1471 *
1472 * @tparam CHUNK_SIZE Amount of elements from this iterator, that get collected to one chunk.
1473 * @tparam STEP_SIZE Controls the step-size between chunks. Per default, this is set to the same as @p CHUNK_SIZE, so the produced
1474 * chunks are directly adjacent. If this is set to a value smaler than @p CHUNK_SIZE, the generated chunks will overlap. If
1475 * this is set to a value higher than @p CHUNK_SIZE, the generated chunks will have gaps in between (those items are dropped).
1476 * @return New iterator that contains exact-sized (@p CHUNK_SIZE) chunks of elements from this iterator as elements.
1477 * - If this iterator supports contiguous memory access:
1478 * - the resulting iterator's elements will be of type @c std::array<...>& where the reference points directly to the contiguous memory
1479 * source's memory region - irrespecting of whether this iterator's elements are referenced or owned/copied. Changing the
1480 * elements in these chunk references will thus directly change the elements in the source.
1481 * - If this iterator doesn't support contiguous memory access (e.g. because of another chainer method between source and @c chunkedExact())
1482 * - ... and this iterator's elements are references, the resulting iterator's elements will be
1483 * of type @c std::array<std::reference_wrapper<...>>& , in order to preserve the ability to modify the elements in-place.
1484 * In case this is unwanted, prepend the call to @c chunkedExact() with a call to the @c copied() chainer method.
1485 * - ... and this iterator's elements are not references, the resulting iterator's elements will be of type @c const std::array<...>&
1486 *
1487 * @attention ChunkedExact tries to avoid making unnecessary copies, but that only works if this iterator is sourced
1488 * by a contiguous source of memory, without any obstructing chainer methods before the call to chunkedExact().
1489 * If this isn't possible, the internal chunk buffer and the copies from this iterator into the buffer, can cause
1490 * an additional strain on memory.
1491 *
1492 * <h3>Usage Examples:</h3>
1493 * <b>Contiguous Memory</b>
1494 * <hr/>
1495 * - If the amount of elements of the input can be evenly divided up into the requested @p CHUNK_SIZE :
1496 * @code
1497 * std::vector<size_t> input = {1337, 42, 512, 31337, 69, 5, 1, 2, 3};
1498 * std::vector<CXXIter::ExactChunk<size_t, 3>> output = CXXIter::from(input)
1499 * .chunkedExact<3>()
1500 * .collect<std::vector>();
1501 * // output == { {1337, 42, 512}, {31337, 69, 5}, {1, 2, 3} }
1502 * @endcode
1503 * - If the amount of elements of the input can **not** be evenly divided up into the requested @p CHUNK_SIZE :
1504 * @code
1505 * std::vector<size_t> input = {1337, 42, 512, 31337, 69, 5, 1, 2};
1506 * std::vector<CXXIter::ExactChunk<size_t, 3>> output = CXXIter::from(input)
1507 * .chunkedExact<3>()
1508 * .collect<std::vector>();
1509 * // output == { {1337, 42, 512}, {31337, 69, 5} }
1510 * @endcode
1511 * - Overlapping chunks (STEP_SIZE < CHUNK_SIZE):
1512 * @code
1513 * std::vector<size_t> input = {1337, 42, 512, 31337, 69, 5};
1514 * std::vector<CXXIter::ExactChunk<size_t, 3>> output = CXXIter::from(input)
1515 * .chunkedExact<3, 1>()
1516 * .collect<std::vector>();
1517 * // output == { {1337, 42, 512}, {42, 512, 31337}, {512, 31337, 69}, {31337, 69, 5} }
1518 * @endcode
1519 * - Gapped Chunks (STEP_SIZE > CHUNK_SIZE):
1520 * @code
1521 * std::vector<size_t> input = {1337, 42, 512, 31337, 69, 5, 1};
1522 * std::vector<CXXIter::ExactChunk<size_t, 3>> output = CXXIter::from(input)
1523 * .chunkedExact<3, 4>()
1524 * .collect<std::vector>();
1525 * // output == { {1337, 42, 512}, {69, 5, 1} }
1526 * @endcode
1527 * - In-Place source editing
1528 * @code
1529 * std::vector<size_t> input = {1337, 42, 512, 31337, 69, 5, 1};
1530 * CXXIter::from(input)
1531 * .chunkedExact<3, 4>()
1532 * .forEach([](std::array<size_t, 3>& chunkRef) {
1533 * chunkRef[0] += 1; chunkRef[1] += 2; chunkRef[2] += 3;
1534 * });
1535 * // input == { 1337+1, 42+2, 512+3, 31337, 69+1, 5+2, 1+3 }
1536 * @endcode
1537 *
1538 * <b>Non-Contiguous Memory</b>
1539 * <hr/>
1540 * - Container that doesn't store its elements in a contiguous region in memory:
1541 * @code
1542 * std::deque<size_t> input = {1337, 42, 512, 31337, 69, 5, 1};
1543 * std::vector<CXXIter::ExactChunk<size_t, 3>> output = CXXIter::from(input)
1544 * .copied() // required to avoid std::reference_wrapper<...> in elements produced by chunkedExact()
1545 * .chunkedExact<3, 4>()
1546 * .collect<std::vector>();
1547 * // output == { {1337, 42, 512}, {69, 5, 1} }
1548 * @endcode
1549 * - Using chunkedExact() with preceding chainers that prevent contiguous memory access:
1550 * @code
1551 * // container would normally support contiguous memory access
1552 * std::vector<size_t> input = {1337, 42, 512, 31337, 69, 5, 1};
1553 * // CXXIter::ExactChunk<size_t&, 3> resolves to std::array<std::reference_wrapper<size_t>, 3>
1554 * std::vector<CXXIter::ExactChunk<size_t&, 3>> output = CXXIter::from(input)
1555 * .filter([](const auto&) { return true; })
1556 * .chunkedExact<3, 4>()
1557 * .collect<std::vector>();
1558 * // output == { {1337, 42, 512}, {69, 5, 1} }
1559 * @endcode
1560 */
1561 template<const size_t CHUNK_SIZE, const size_t STEP_SIZE = CHUNK_SIZE>
1562 110 constexpr op::ChunkedExact<TSelf, CHUNK_SIZE, STEP_SIZE> chunkedExact() {
1563 110 return op::ChunkedExact<TSelf, CHUNK_SIZE, STEP_SIZE>(std::move(*self()));
1564 }
1565
1566 /**
1567 * @brief Creates an iterator that uses the given @p mapFn to map each element from this
1568 * iterator to elements of the new iterator.
1569 * @details This pulls a new value from this iterator, maps it to a new value (can have
1570 * a completely new type) using the given @p mapFn and then yields that as new item for
1571 * thew newly created iterator.
1572 * @param mapFn Function that maps items from this iterator to a new value.
1573 * @return New iterator that maps the values from this iterator to new values, using the
1574 * given @p mapFn.
1575 *
1576 * Usage Example:
1577 * @code
1578 * std::vector<int> input = {1337, 42};
1579 * std::unordered_map<int, std::string> output = CXXIter::from(input)
1580 * .map([](int i) { return std::make_pair(i, std::to_string(i)); }) // construct pair
1581 * .collect<std::unordered_map>(); // collect into map
1582 * @endcode
1583 */
1584 template<std::invocable<Item&&> TMapFn>
1585 335 constexpr auto map(TMapFn mapFn) {
1586 using TMapFnResult = std::invoke_result_t<TMapFn, Item&&>;
1587 335 return op::Map<TSelf, TMapFn, TMapFnResult>(std::move(*self()), mapFn);
1588 }
1589
1590 /**
1591 * @brief Creates an iterator that works like map(), but flattens nested containers.
1592 * @details This works by pulling elements from this iterator, passing them to the given
1593 * @p mapFn, and then taking the returned values to turn them into iterators themselves,
1594 * to merge them into the stream of the resulting iterator.
1595 * This only resolves one layer of nesting, and values returned by @p mapFn have to
1596 * be supported by CXXIter (by a fitting @c SourceTrait implementation).
1597 * @param mapFn Function that returns a nesting container, that should be merged into the returned
1598 * iterator's stream.
1599 * @return New iterator that pulls values from this iterator, maps them to a nested container, which
1600 * is then flattened into the new iterator's stream of elements.
1601 *
1602 * Usage Example:
1603 * @code
1604 * std::vector<std::pair<std::string, std::vector<int>>> input = {{"first pair", {1337, 42}}, {"second pair", {6, 123, 7888}}};
1605 * std::vector<int> output = CXXIter::from(std::move(input))
1606 * .flatMap([](auto&& item) { return std::get<1>(item); }) // flatten the std::vector<int> from the pair
1607 * .collect<std::vector>(); // collect into vector containing {1337, 42, 6, 123, 7888}
1608 * @endcode
1609 */
1610 template<std::invocable<Item&&> TFlatMapFn>
1611 8 constexpr auto flatMap(TFlatMapFn mapFn) {
1612 using TFlatMapFnResult = std::invoke_result_t<TFlatMapFn, Item&&>;
1613 8 return op::FlatMap<TSelf, TFlatMapFn, TFlatMapFnResult>(std::move(*self()), mapFn);
1614 }
1615
1616 #ifdef CXXITER_HAS_COROUTINE
1617 /**
1618 * @brief Creates a new iterator containing the items that the given generator produces for each element
1619 * in this iterator.
1620 * @details Conceptually, this method is very similar to flatMap() since it allows to take one element
1621 * from this iterator, and returning an arbitrary amount of new elements into the resulting iterator.
1622 * A big difference is, that with generateFrom(), elements can be produced on the fly using c++20
1623 * coroutines, while with flatMap() they need to be present in a supported container at once - taking up memory.
1624 * The given @p generatorFn is run for each element in this iterator, producing a generator.
1625 * This generator is then driven to completion, piping every element it produced into the resulting iterator.
1626 * @param generatorFn Generator function that is executed for each element of this iterator. This function
1627 * can use co_yield to produce as many elements as it wants. Its return value has to be explicitly specified
1628 * as CXXIter::Generator with the generated type as template parameter.
1629 * @note Returning references from the generator is supported. Make sure your references stay valid until
1630 * they are read, though.
1631 * @attention Special care has to be taken with respect to the argument types of the given @p generatorFn.
1632 * The generator must take the elements of the stream by-value (copied). If the elements in the stream are
1633 * moved through the stream, the @p generatorFn must take them as their owned type. If the elements are
1634 * passed as references through the stream, the @p generatorFn can take them as references.
1635 * If you are getting spurious SEGFAULTs - check your parameter types!
1636 *
1637 * Usage Example:
1638 *
1639 * The example shows a generator that repeats the strings from the source, depending on the string's
1640 * lengths. Special attention in these examples should be mainly on the parameter types, as well as the
1641 * explicitly specified return values of the given generator functions.
1642 *
1643 * - Using generateFrom() with a move source, that passes elements by move
1644 * (generator clones elements and passes them on as owned clones)\n
1645 * Here, the type of the elements passed through the iterator are owned @c std::string by move.
1646 * So the type the generator has to take as parameter is an owned @p std::string.
1647 * @code
1648 * std::vector<std::string> input = {"1337", "42"};
1649 * std::vector<std::string> output = CXXIter::from(std::move(input))
1650 * .generateFrom([](std::string item) -> CXXIter::Generator<std::string> {
1651 * for(size_t i = 0; i < item.size(); ++i) {
1652 * co_yield item;
1653 * }
1654 * })
1655 * .collect<std::vector>();
1656 * // output == { "1337", "1337", "1337", "1337", "42", "42" }
1657 * @endcode
1658 * - Using generateFrom() with a reference source, that passes elements as references
1659 * (generator clones elements and passes them on as owned clones)\n
1660 * Here, the type of the elements passed through the iterator are const @c std::string references.
1661 * So the type the generator takes can either be a const @c std::string reference (because they don't
1662 * reference something temporary, but are references from the permanent source) - or as an owned @p std::string.
1663 * @code
1664 * std::vector<std::string> input = {"1337", "42"};
1665 * std::vector<std::string> output = CXXIter::from(input)
1666 * .generateFrom([](const std::string& item) -> CXXIter::Generator<std::string> {
1667 * for(size_t i = 0; i < item.size(); ++i) {
1668 * co_yield item;
1669 * }
1670 * })
1671 * .collect<std::vector>();
1672 * // output == { "1337", "1337", "1337", "1337", "42", "42" }
1673 * @endcode
1674 * - Using generateFrom() with a reference source, that passes elements as references
1675 * (generator clones references to elements - and passes on the copied references)\n
1676 * @code
1677 * std::vector<std::string> input = {"1337", "42"};
1678 * std::vector<std::string> output = CXXIter::from(input)
1679 * .generateFrom([](const std::string& item) -> CXXIter::Generator<const std::string&> {
1680 * for(size_t i = 0; i < item.size(); ++i) {
1681 * co_yield item;
1682 * }
1683 * })
1684 * .collect<std::vector>();
1685 * // output == { "1337", "1337", "1337", "1337", "42", "42" }
1686 * @endcode
1687 */
1688 template<GeneratorFromFunction<Item> TGeneratorFn>
1689 14 constexpr auto generateFrom(TGeneratorFn generatorFn) {
1690 using TGeneratorFnResult = std::invoke_result_t<TGeneratorFn, Item>;
1691 14 return op::GenerateFrom<TSelf, TGeneratorFn, TGeneratorFnResult>(std::move(*self()), generatorFn);
1692 }
1693 #endif
1694
1695 /**
1696 * @brief Creates an iterator that flattens the iterable elements of this iterator.
1697 * @details This works by pulling elements from this iterator, turning them into iterators
1698 * themselves, and merging them into the stream of the resulting iterator.
1699 * This only resolves one layer of nesting, and the elements of this iterator have to
1700 * be supported by CXXIter (by a fitting @c SourceTrait implementation).
1701 * @return New iterator that pulls values from this iterator, and flattens the contained
1702 * iterable into the new iterator's stream.
1703 *
1704 * Usage Example:
1705 * @code
1706 * std::vector<std::vector<int>> input = {{1337, 42}, {6, 123, 7888}};
1707 * std::vector<int> output = CXXIter::from(std::move(input))
1708 * .flatMap()
1709 * .collect<std::vector>(); // collect into vector containing {1337, 42, 6, 123, 7888}
1710 * @endcode
1711 */
1712 3 constexpr auto flatMap() {
1713 8 return flatMap([](Item&& item) { return item; });
1714 }
1715
1716 /**
1717 * @brief Allows to inspect and modify each item in-place, that passes through this iterator.
1718 * @details This can be used instead of a map() with the same type as input and output.
1719 * @param modifierFn Function that is called for each item that passes through this iterator.
1720 * @return Iterator that forwards the items of this iterator, after they have been inspected
1721 * and potentially modified by the @p modifierFn.
1722 *
1723 * Usage Example:
1724 * @code
1725 * std::unordered_map<int, std::string> input = { {1337, "1337"}, {42, "42"} };
1726 * std::unordered_map<int, std::string> output = CXXIter::from(input)
1727 * .modify([](auto& keyValue) { keyValue.second = "-" + keyValue.second; }) // modify input
1728 * .collect<std::unordered_map>(); // copy to output
1729 * @endcode
1730 */
1731 template<std::invocable<Item&> TModifierFn>
1732 12 constexpr op::InplaceModifier<TSelf, TModifierFn> modify(TModifierFn modifierFn) {
1733 12 return op::InplaceModifier<TSelf, TModifierFn>(std::move(*self()), modifierFn);
1734 }
1735
1736 /**
1737 * @brief Creates a new iterator that filters and maps items from this iterator.
1738 * @param filterMapFn Function that maps the incomming items to an optional mapped value.
1739 * If it returns an empty @c std::optional<> the element is filtered. If it returns an
1740 * @c std::optional<> with a value, that item is yielded from the resulting iterator.
1741 * @return Iterator that yields only the items for which the given @c filterMapFn returned a
1742 * mapped value.
1743 *
1744 * Usage Example:
1745 * @code
1746 * std::vector<int> input = {1, 2, 3, 4, 5, 6, 7, 8};
1747 * std::vector<int> output = CXXIter::from(input)
1748 * .filterMap([](int item) -> std::optional<int> {
1749 * if(item % 2 == 0) { return (item + 3); }
1750 * return {};
1751 * })
1752 * .collect<std::vector>();
1753 * @endcode
1754 */
1755 template<std::invocable<ItemOwned&&> TFilterMapFn>
1756 requires util::is_optional<std::invoke_result_t<TFilterMapFn, ItemOwned&&>>
1757 22 constexpr auto filterMap(TFilterMapFn filterMapFn) {
1758 using TFilterMapFnResult = typename std::invoke_result_t<TFilterMapFn, ItemOwned&&>::value_type;
1759 22 return op::FilterMap<TSelf, TFilterMapFn, TFilterMapFnResult>(std::move(*self()), filterMapFn);
1760 }
1761
1762 /**
1763 * @brief Creates an iterator that skips the first @p cnt elements from this iterator, before it
1764 * yields the remaining items.
1765 * @param cnt Amount of elements to skip from this iterator.
1766 * @return A new iterator that skips @p cnt elements from this iterator, before yielding the remaining items.
1767 *
1768 * Usage Example:
1769 * @code
1770 * std::vector<int> input = {42, 42, 42, 42, 1337};
1771 * std::vector<int> output = CXXIter::from(input)
1772 * .skip(3) // skip first 3 values
1773 * .collect<std::vector>();
1774 * @endcode
1775 */
1776 38 constexpr op::SkipN<TSelf> skip(size_t cnt) {
1777 38 return op::SkipN<TSelf>(std::move(*self()), cnt);
1778 }
1779
1780 /**
1781 * @brief Creates an iterator that skips the first elements of this iterator, for which the
1782 * given @p skipPredicate returns @c true.
1783 * @details The @p skipPredicate is only called until it returned @c false for the first time,
1784 * after that its job is done.
1785 * @param skipPredicate Predicate that determines the items whether an item at the beginning
1786 * of this iterator should be skipped (@c true). Should return @c false for the first item
1787 * yielded from the resulted iterator.
1788 * @return A new iterator that skips the frist elements from this iterator, until the given
1789 * @p skipPredicate returns @c false for the first time. It then yields all remaining items of this
1790 * iterator.
1791 *
1792 * Usage Example:
1793 * @code
1794 * std::vector<int> input = {42, 42, 42, 42, 1337, 42};
1795 * std::vector<int> output = CXXIter::from(input)
1796 * .skipWhile([](const int value) { return (value == 42); }) // skip leading 42s
1797 * .collect<std::vector>();
1798 * @endcode
1799 */
1800 template<std::invocable<const Item&> TSkipPredicate>
1801 28 constexpr op::SkipWhile<TSelf, TSkipPredicate> skipWhile(TSkipPredicate skipPredicate) {
1802 28 return op::SkipWhile<TSelf, TSkipPredicate>(std::move(*self()), skipPredicate);
1803 }
1804
1805 /**
1806 * @brief Creates an iterator that yields at most the first @p cnt elements from this iterator.
1807 * @param cnt Amount of elements to yield from this iterator.
1808 * @return A new iterator that yields only at most the first @p cnt elements from this iterator.
1809 *
1810 * Usage Example:
1811 * @code
1812 * std::vector<int> input = {42, 57, 64, 128, 1337, 10};
1813 * std::vector<int> output = CXXIter::from(input)
1814 * .take(3) // take first 3 values
1815 * .collect<std::vector>();
1816 * @endcode
1817 */
1818 27 constexpr op::TakeN<TSelf> take(size_t cnt) {
1819 27 return op::TakeN<TSelf>(std::move(*self()), cnt);
1820 }
1821
1822 /**
1823 * @brief Creates an iterator that yields the first elements of this iterator, for which the
1824 * given @p takePredicate returns @c true.
1825 * @details The @p takePredicate is only called until it returned @c false for the first time,
1826 * after that its job is done.
1827 * @param takePredicate Predicate that determines the items returned by the newly constructed
1828 * iterator. After this predicate yielded @c false for the first time, the new iterator ends.
1829 * @return A new iterator that yields the first couple elements from this iterator, until
1830 * the given predicate returns @c false for the first time.
1831 *
1832 * Usage Example:
1833 * @code
1834 * std::vector<int> input = {42, 57, 64, 128, 1337, 10};
1835 * std::vector<int> output = CXXIter::from(input)
1836 * .takeWhile([](const int value) { return (value < 1000); }) // take until first item > 1000
1837 * .collect<std::vector>();
1838 * @endcode
1839 */
1840 template<std::invocable<const Item&> TTakePredicate>
1841 requires std::is_same_v<std::invoke_result_t<TTakePredicate, const Item&>, bool>
1842 4 constexpr auto takeWhile(TTakePredicate takePredicate) {
1843 4 return op::TakeWhile<TSelf, TTakePredicate>(std::move(*self()), takePredicate);
1844 }
1845
1846 /**
1847 * @brief Creates an iterator with the requested @p stepWidth from this iterator.
1848 * @details A step width of @c 1 is a NO-OP, a step width of @c 2 means that every second
1849 * element is skipped. The first element is always returned, irrespecting of the requested @p stepWidth.
1850 * @param step Step width with which elements from this iterator are yielded.
1851 * @return New iterator with the requested @p stepWidth
1852 *
1853 * Usage Example:
1854 * - Step width of 1 (No-Op):
1855 * @code
1856 * std::vector<int> input = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
1857 * std::vector<int> output = CXXIter::from(input)
1858 * .stepBy(1)
1859 * .collect<std::vector>();
1860 * // output == {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
1861 * @endcode
1862 * - Step width of 2:
1863 * @code
1864 * std::vector<int> input = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
1865 * std::vector<int> output = CXXIter::from(input)
1866 * .stepBy(2)
1867 * .collect<std::vector>();
1868 * // output == {0, 2, 4, 6, 8, 10}
1869 * @endcode
1870 */
1871 3 constexpr auto stepBy(size_t stepWidth) {
1872 //TODO: better SizeHints?
1873 3 size_t idx = 0;
1874 3 return filter([idx, stepWidth](const ItemOwned&) mutable {
1875 33 return (idx++ % stepWidth) == 0;
1876 3 });
1877 }
1878
1879 /**
1880 * @brief "Zips up" two CXXIter iterators into a single iterator over pairs from both iterators.
1881 * @details Constructs new iterator that iterates over @c std::pair<> instances where values from this
1882 * iterator are put in the first value, and values from the given @p otherIterator become the second values.
1883 * The resulting iterator is only as long as the shorter of both zipped iterators.
1884 * @param otherIterator Second iterator zipped against this iterator.
1885 * @return New iterator that zips together this iteratore and the given @p otherIterator into a new iterator
1886 * over @c std::pair<> for both zipped iterator's values.
1887 *
1888 * Usage Example:
1889 * @code
1890 * std::vector<std::string> input1 = {"1337", "42"};
1891 * std::vector<int> input2 = {1337, 42};
1892 * std::vector<std::pair<std::string, int>> output = CXXIter::from(input1).copied()
1893 * .zip(CXXIter::from(input2).copied())
1894 * .collect<std::vector>();
1895 * @endcode
1896 */
1897 template<typename TOtherIterator>
1898 18 constexpr op::Zipper<TSelf, std::pair, TOtherIterator> zip(TOtherIterator&& otherIterator) {
1899 18 return op::Zipper<TSelf, std::pair, TOtherIterator>(std::move(*self()), std::forward<TOtherIterator>(otherIterator));
1900 }
1901
1902 /**
1903 * @brief "Zips up" an arbitrary amount of CXXIter iterators into a single iterator over @c std::tuple<> from both iterators.
1904 * @details Constructs new iterator that iterates over @c std::tuple<> instances where values from this
1905 * iterator are put in the first value, and values from the given @p otherIterators are stored after that in order.
1906 * The resulting iterator is only as long as the shortest of all iterators part of the zip.
1907 * @param otherIterators Other iterators zipped against this iterator.
1908 * @return New iterator that zips together this iteratore and the given @p otherIterators into a new iterator
1909 * over @c std::tuple<> for all of the zipped iterator's values.
1910 *
1911 * Usage Example:
1912 * @code
1913 * std::vector<std::string> input1 = {"1337", "42"};
1914 * std::vector<int> input2 = {1337, 42, 80};
1915 * std::vector<float> input3 = {1337.0f, 42.0f, 64.0f};
1916 * std::vector<std::tuple<std::string, int, float>> output = CXXIter::from(input1).copied()
1917 * .zipTuple(CXXIter::from(input2).copied(), CXXIter::from(input3).copied())
1918 * .collect<std::vector>();
1919 * // output == { {"1337", 1337, 1337.0f}, {"42", 42, 42.0f} }
1920 * @endcode
1921 */
1922 template<typename... TOtherIterators>
1923 requires (CXXIterIterator<TOtherIterators> && ...)
1924 && (!std::disjunction_v< std::is_reference<typename trait::Iterator<TOtherIterators>::Item>... > && !IS_REFERENCE)
1925 14 constexpr op::Zipper<TSelf, std::tuple, TOtherIterators...> zipTuple(TOtherIterators&&... otherIterators) {
1926 14 return op::Zipper<TSelf, std::tuple, TOtherIterators...>(std::move(*self()), std::forward<TOtherIterators>(otherIterators)...);
1927 }
1928
1929 /**
1930 * @brief Chains this iterator with the given @p otherIterator, resulting in a new iterator that first yields
1931 * the elements of this iterator, and then the ones from the @p otherIterator.
1932 * @param otherIterator Other iterator whose elements should be "appended" to the elements of this iterator.
1933 * @return New iterator that consists of a chain of this iterator with the given @p otherIterator.
1934 * @note For this to work, the elements' types of this iterator and the given @p otherIterator have to be identical.
1935 *
1936 * Usage Example:
1937 * @code
1938 * std::vector<std::string> input1 = {"1337", "42"};
1939 * std::vector<std::string> input2 = {"31337", "64"};
1940 * std::vector<std::string> output = CXXIter::from(input1).copied()
1941 * .chain(CXXIter::from(input2).copied())
1942 * .collect<std::vector>();
1943 * // output == {"1337", "42", "31337", "64"}
1944 * @endcode
1945 */
1946 template<typename TOtherIterator>
1947 requires std::is_same_v<Item, typename TOtherIterator::Item>
1948 19 constexpr op::Chainer<TSelf, TOtherIterator> chain(TOtherIterator&& otherIterator) {
1949 19 return op::Chainer<TSelf, TOtherIterator>(std::move(*self()), std::forward<TOtherIterator>(otherIterator));
1950 }
1951
1952 /**
1953 * @brief Alternating the elements of this iterator with the ones from the other given iterator(s).
1954 * @details Everytime an element is polled from the iterator resulting from this call, an element from the
1955 * current input iterator is forwarded. Then, the current input iterator is switched to the next input.
1956 * The resulting iterator ends, when the currently active input has no more elements.
1957 * @param otherIterators An arbitrary amount of iterators to alternate the elements of this iterator with.
1958 * @return A new iterator that interweaves the elements from this iterator and all the given iterators in order.
1959 *
1960 * Usage Example:
1961 * @code
1962 * std::vector<int> input1 = {1, 4, 7};
1963 * std::vector<int> input2 = {2, 5};
1964 * std::vector<int> input3 = {3, 6, 9};
1965 * std::vector<int> output = CXXIter::from(input1)
1966 * .alternate(CXXIter::from(input2), CXXIter::from(input3))
1967 * .collect<std::vector>();
1968 * // output == {1, 2, 3, 4, 5, 6, 7}
1969 * @endcode
1970 */
1971 template<typename... TOtherIterators>
1972 requires (CXXIterIterator<TOtherIterators> && ...)
1973 && (util::are_same_v<Item, typename TOtherIterators::Item...>)
1974 8 constexpr op::Alternater<TSelf, TOtherIterators...> alternate(TOtherIterators&&... otherIterators) {
1975 8 return op::Alternater<TSelf, TOtherIterators...>(std::move(*self()), std::forward<TOtherIterators>(otherIterators)...);
1976 }
1977
1978 /**
1979 * @brief Draw elements from the given @p otherIterator and use the returned elements as separators between
1980 * the elements of this iterator.
1981 * @details This draws one element "into the future" of this iterator, in order to determine if another
1982 * separator element from the given @p otherIterator is required.
1983 * The resulting iterator ends if either this iterator or the @p otherIterator has no more elements to pull.
1984 * The resulting iterator will always start and end on an element from this iterator.
1985 * @param otherIterator Iterator whose elements will be inserted as separator elements between the elements
1986 * of this iterator.
1987 * @return New iterator that uses the given @p otherIterator's elements as separators between this iterator's
1988 * elements.
1989 *
1990 * Usage Example:
1991 * - Using infinite separator iterator (int)
1992 * @code
1993 * std::vector<int> input = { 1, 2, 3, 4, 5, 6 };
1994 * std::vector<int> output = CXXIter::from(input).copied()
1995 * .intersperse(CXXIter::repeat(0))
1996 * .collect<std::vector>();
1997 * // output == {1, 0, 2, 0, 3, 0, 4, 0, 5, 0, 6}
1998 * @endcode
1999 * - Using infinite separator iterator (string)
2000 * @code
2001 * std::vector<std::string> input = { "Apple", "Orange", "Cake" };
2002 * std::vector<std::string> output = CXXIter::from(input).copied()
2003 * .intersperse(CXXIter::repeat<std::string>(", "))
2004 * .collect<std::vector>();
2005 * // output == {"Apple", ", ", "Orange", ", ", "Cake"}
2006 * @endcode
2007 * - Using finite separator iterator that ends earlier than source iterator
2008 * @code
2009 * std::vector<int> input = { 1, 2, 3, 4, 5, 6 };
2010 * std::vector<int> output = CXXIter::from(input).copied()
2011 * .intersperse(CXXIter::range(100, 102, 1))
2012 * .collect<std::vector>();
2013 * // output == {1, 100, 2, 101, 3, 102, 4}
2014 * @endcode
2015 */
2016 template<typename TOtherIterator>
2017 requires (std::is_same_v<Item, typename TOtherIterator::Item>)
2018 34 constexpr op::Intersperser<TSelf, TOtherIterator> intersperse(TOtherIterator&& otherIterator) {
2019 34 return op::Intersperser<TSelf, TOtherIterator>(std::move(*self()), std::forward<TOtherIterator>(otherIterator));
2020 }
2021
2022 /**
2023 * @brief Groups the elements of this iterator according to the values returned by the given @p groupidentFn.
2024 * @param groupIdentFn Function called for each element from this iterator, to determine the grouping value,
2025 * that is then used to identify the group an item belongs to. The type returned by this function has to
2026 * implement @c std::hash<>.
2027 * @return New iterator whose elements are the calculated groups from the values of this iterator, in the form
2028 * of a @c std::pair<> with the group identifier as first value, and a @c std::vector of all values in the group
2029 * as second value.
2030 * @attention GroupBy requires to first drain the input iterator, before being able to supply a single element.
2031 * This leads to additional memory usage.
2032 *
2033 * Usage Example:
2034 * @code
2035 * struct CakeMeasurement {
2036 * std::string cakeType;
2037 * float cakeWeight;
2038 * bool operator==(const CakeMeasurement& o) const {
2039 * return cakeType == o.cakeType && cakeWeight == o.cakeWeight;
2040 * }
2041 * };
2042 * std::vector<CakeMeasurement> input = { {"ApplePie", 1.3f}, {"Sacher", 0.5f}, {"ApplePie", 1.8f} };
2043 * std::unordered_map<std::string, std::vector<CakeMeasurement>> output = CXXIter::from(input)
2044 * .groupBy([](const CakeMeasurement& item) { return item.cakeType; })
2045 * .collect<std::unordered_map>();
2046 * @endcode
2047 */
2048 template<std::invocable<const Item&> TGroupIdentifierFn>
2049 requires util::is_hashable<std::invoke_result_t<TGroupIdentifierFn, const Item&>>
2050 10 constexpr auto groupBy(TGroupIdentifierFn groupIdentFn) {
2051 using TGroupIdent = std::remove_cvref_t<std::invoke_result_t<TGroupIdentifierFn, const ItemOwned&>>;
2052 10 return op::GroupBy<TSelf, TGroupIdentifierFn, TGroupIdent>(std::move(*self()), groupIdentFn);
2053 }
2054
2055 /**
2056 * @brief Creates a new iterator that takes the items from this iterator, and passes them on sorted, using
2057 * the supplied @p compareFn.
2058 * @param compareFn Compare function used for the sorting of items.
2059 * @return New iterator that returns the items of this iterator sorted using the given @p compareFn.
2060 * @attention Sorter requires to first drain the input iterator, before being able to supply a single element.
2061 * This leads to additional memory usage.
2062 * @tparam STABLE If @c true, uses @c std::stable_sort internally, if @c false uses @c std::sort
2063 *
2064 * Usage Example:
2065 * - Sorting in ascending order using a custom comparer:
2066 * @code
2067 * std::vector<float> input = {1.0f, 2.0f, 0.5f, 3.0f, -42.0f};
2068 * std::vector<float> output = CXXIter::from(input)
2069 * .sort<false>([](const float& a, const float& b) {
2070 * return (a < b);
2071 * })
2072 * .collect<std::vector>();
2073 * @endcode
2074 * - Sorting in descending order using a custom comparer:
2075 * @code
2076 * std::vector<float> input = {1.0f, 2.0f, 0.5f, 3.0f, -42.0f};
2077 * std::vector<float> output = CXXIter::from(input)
2078 * .sort<false>([](const float& a, const float& b) {
2079 * return (a > b);
2080 * })
2081 * .collect<std::vector>();
2082 * @endcode
2083 */
2084 template<bool STABLE, std::invocable<const ItemOwned&, const ItemOwned&> TCompareFn>
2085 43 constexpr auto sort(TCompareFn compareFn) {
2086 43 return op::Sorter<TSelf, TCompareFn, STABLE>(std::move(*self()), compareFn);
2087 }
2088
2089 /**
2090 * @brief Creates a new iterator that takes the items from this iterator, and passes them on sorted.
2091 * @note This variant of sort() requires the items to support comparison operators.
2092 * @return New iterator that returns the items of this iterator sorted.
2093 * @attention Sorter requires to first drain the input iterator, before being able to supply a single element.
2094 * This leads to additional memory usage.
2095 * @tparam ORDER Decides the sort order of the resulting iterator.
2096 * @tparam STABLE If @c true, uses @c std::stable_sort internally, if @c false uses @c std::sort
2097 *
2098 * Usage Example:
2099 * - Sorting in ascending order using a custom comparer:
2100 * @code
2101 * std::vector<float> input = {1.0f, 2.0f, 0.5f, 3.0f, -42.0f};
2102 * std::vector<float> output = CXXIter::from(input)
2103 * .sort<CXXIter::ASCENDING, false>()
2104 * .collect<std::vector>();
2105 * @endcode
2106 * - Sorting in descending order using a custom comparer:
2107 * @code
2108 * std::vector<float> input = {1.0f, 2.0f, 0.5f, 3.0f, -42.0f};
2109 * std::vector<float> output = CXXIter::from(input)
2110 * .sort<CXXIter::DESCENDING, false>()
2111 * .collect<std::vector>();
2112 * @endcode
2113 */
2114 template<SortOrder ORDER = SortOrder::ASCENDING, bool STABLE = false>
2115 requires requires(const ItemOwned& a) { { a < a }; { a > a }; }
2116 24 constexpr auto sort() {
2117 24 return sort<STABLE>([](const ItemOwned& a, const ItemOwned& b) {
2118 if constexpr(ORDER == SortOrder::ASCENDING) {
2119 6 return (a < b);
2120 } else {
2121 18 return (a > b);
2122 }
2123 24 });
2124 }
2125
2126 /**
2127 * @brief Creates a new iterator that takes the items from this iterator, and passes them on sorted.
2128 * @details In comparison to sort(), which either uses a custom comparator or the items themselves
2129 * for the sort operation, this variant takes a @p sortValueExtractFn, which extracts a value for
2130 * each item in this iterator, that should be used for sorting comparisons.
2131 * @return New iterator that returns the items of this iterator sorted.
2132 * @attention Sorter requires to first drain the input iterator, before being able to supply a single element.
2133 * This leads to additional memory usage.
2134 * @tparam ORDER Decides the sort order of the resulting iterator.
2135 * @tparam STABLE If @c true, uses @c std::stable_sort internally, if @c false uses @c std::sort
2136 *
2137 * Usage Example:
2138 * - Sorting the items(strings) in ascending order of their length:
2139 * @code
2140 * std::vector<std::string> input = {"test1", "test2", "test23", "test", "tes"};
2141 * std::vector<std::string> output = CXXIter::from(input)
2142 * .sortBy<CXXIter::ASCENDING, true>([](const std::string& item) { return item.size(); })
2143 * .collect<std::vector>();
2144 * @endcode
2145 * - Sorting the items(strings) in descending order of their length:
2146 * @code
2147 * std::vector<std::string> input = {"test1", "test2", "test23", "test", "tes"};
2148 * std::vector<std::string> output = CXXIter::from(input)
2149 * .sortBy<CXXIter::DESCENDING, true>([](const std::string& item) { return item.size(); })
2150 * .collect<std::vector>();
2151 * @endcode
2152 */
2153 template<SortOrder ORDER = SortOrder::ASCENDING, bool STABLE = false, std::invocable<const ItemOwned&> TSortValueExtractFn>
2154 requires requires(const std::invoke_result_t<TSortValueExtractFn, const ItemOwned&>& a) {
2155 { a < a }; { a > a };
2156 }
2157 9 constexpr auto sortBy(TSortValueExtractFn sortValueExtractFn) {
2158 25 return sort<STABLE>([sortValueExtractFn](const ItemOwned& a, const ItemOwned& b) {
2159 if constexpr(ORDER == SortOrder::ASCENDING) {
2160 12 return (sortValueExtractFn(a) < sortValueExtractFn(b));
2161 } else {
2162 13 return (sortValueExtractFn(a) > sortValueExtractFn(b));
2163 }
2164 9 });
2165 }
2166 //@}
2167 };
2168
2169
2170
2171 // ################################################################################################
2172 // ENTRY POINTS
2173 // ################################################################################################
2174
2175 /**
2176 * @name Source Entry Points
2177 */
2178 //@{
2179 /**
2180 * @brief Construct a CXXIter move source from the given container.
2181 * @details This constructs a move source, which will move the items from the
2182 * given @p container into the iterator.
2183 * @param container Container to construct a CXXIter source from.
2184 * @return CXXIter move source from the given container.
2185 */
2186 template<typename TContainer>
2187 requires (!std::is_reference_v<TContainer> && !util::is_const_reference_v<TContainer> && concepts::SourceContainer<TContainer>)
2188 59 constexpr SrcMov<std::remove_cvref_t<TContainer>> from(TContainer&& container) {
2189 59 return SrcMov<std::remove_cvref_t<TContainer>>(std::forward<TContainer>(container));
2190 }
2191
2192 /**
2193 * @brief Construct a CXXIter mutable-reference source from the given container.
2194 * @details This constructs a mutable-reference source. This allows the iterator
2195 * to modify the elements in the given @p container.
2196 * @param container Container to construct a CXXIter source from.
2197 * @return CXXIter mutable-reference source from the given container.
2198 */
2199 template<typename TContainer>
2200 requires (!std::is_reference_v<TContainer> && !util::is_const_reference_v<TContainer> && concepts::SourceContainer<TContainer>)
2201 713 constexpr SrcRef<std::remove_cvref_t<TContainer>> from(TContainer& container) {
2202 713 return SrcRef<std::remove_cvref_t<TContainer>>(container);
2203 }
2204
2205 /**
2206 * @brief Construct a CXXIter const-reference source from the given container.
2207 * @details This constructs a const-reference source. This guarantees the
2208 * given @p container to stay untouched.
2209 * @param container Container to construct a CXXIter source from.
2210 * @return CXXIter const-reference source from the given container.
2211 */
2212 template<typename TContainer>
2213 requires (!std::is_reference_v<TContainer> && !util::is_const_reference_v<TContainer> && concepts::SourceContainer<TContainer>)
2214 37 constexpr SrcCRef<std::remove_cvref_t<TContainer>> from(const TContainer& container) {
2215 37 return SrcCRef<std::remove_cvref_t<TContainer>>(container);
2216 }
2217 //@}
2218
2219
2220 /**
2221 * @name Generator Entry Points
2222 */
2223 //@{
2224 /**
2225 * @brief Constructs an empty iterator yielding no items.
2226 * @return An empty iterator that yields no items.
2227 *
2228 * Usage Example:
2229 * @code
2230 * CXXIter::IterValue<std::string> output = CXXIter::empty<std::string>()
2231 * .next();
2232 * // output == None
2233 * @endcode
2234 */
2235 template<typename TItem>
2236 7 constexpr Empty<TItem> empty() { return Empty<TItem>(); }
2237
2238 /**
2239 * @brief Generator source that takes a @p generatorFn, each invocation of which produces one
2240 * element for the resulting iterator.
2241 * @param generatorFn Generator that returns an optional value. If the optional is None, the resulting
2242 * iterator ends.
2243 * @return CXXIter iterator whose elements are produced by the calls to the given @p generatorFn.
2244 * @details You could for example also use this to pull messages from a socket.
2245 *
2246 * Usage Example:
2247 * - Simple endless generator producing monotonically increasing numbers
2248 * @code
2249 * size_t generatorState = 0;
2250 * std::function<std::optional<size_t>()> generatorFn = [generatorState]() mutable {
2251 * return (generatorState++);
2252 * };
2253 * std::vector<size_t> output = CXXIter::fromFn(generatorFn)
2254 * .take(100)
2255 * .collect<std::vector>();
2256 * // output == {0, 1, 2, 3, ..., 99}
2257 * @endcode
2258 */
2259 template<std::invocable<> TGeneratorFn>
2260 requires util::is_optional<std::invoke_result_t<TGeneratorFn>>
2261 1 constexpr auto fromFn(TGeneratorFn generatorFn) {
2262 using TGeneratorFnResult = typename std::invoke_result_t<TGeneratorFn>::value_type;
2263
1/2
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
1 return FunctionGenerator<TGeneratorFnResult, TGeneratorFn>(generatorFn);
2264 }
2265
2266 #ifdef CXXITER_HAS_COROUTINE
2267 /**
2268 * @brief Generator source that produces a new iterator over the elements produced by the
2269 * given @p generatorFn - which is a c++20 coroutine yielding elements using @c co_yield.
2270 * @param generatorFn C++20 generator coroutine function yielding elements using @c co_yield.
2271 * The function must produces a generator of type CXXIter::Generator whose template parameter
2272 * is set to the produced element type.
2273 * @return CXXIter iterator over the elements produced by the c++20 coroutine given in @p generatorFn.
2274 *
2275 * Usage Example:
2276 * - Simple generator example producing all integer numbers from 0 to 1000 as @p std::string
2277 * @code
2278 * std::vector<std::string> output = CXXIter::generate(
2279 * []() -> CXXIter::Generator<std::string> {
2280 * for(size_t i = 0; i < 1000; ++i) {
2281 * co_yield std::to_string(i);
2282 * }
2283 * }
2284 * ).collect<std::vector>();
2285 * // output == {0, 1, 2, ..., 1000}
2286 * @endcode
2287 */
2288 template<GeneratorFunction TGeneratorFn>
2289 4 auto generate(TGeneratorFn generatorFn) {
2290 using TGenerator = typename std::invoke_result_t<TGeneratorFn>;
2291
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
4 TGenerator generator = generatorFn();
2292 8 return CoroutineGenerator<TGenerator>(std::forward<TGenerator>(generator));
2293 4 }
2294 #endif
2295
2296 /**
2297 * @brief Construct a CXXIter iterator, by repeating the given @p item @p cnt times.
2298 * @param item Item to use as repeated element of the generated element.
2299 * @param cnt Optional amount of repetitions of @p item the generated iterator should consist of.
2300 * If none, the iterator will repeat the item forever.
2301 * @return CXXIter iterator that returns the given @p item @p cnt times.
2302 *
2303 * Usage Example:
2304 * @code
2305 * std::vector<int> item = {1, 3, 3, 7};
2306 * std::vector<int> output = CXXIter::repeat(item, 3)
2307 * .flatMap()
2308 * .collect<std::vector>();
2309 * // output == {1, 3, 3, 7, 1, 3, 3, 7, 1, 3, 3, 7}
2310 * @endcode
2311 */
2312 template<typename TItem>
2313 37 constexpr Repeater<TItem> repeat(const TItem& item, std::optional<size_t> cnt = {}) {
2314 37 return Repeater<TItem>(item, cnt);
2315 }
2316
2317 /**
2318 * @brief Construct a CXXIter iterator that yields all elements in the range between
2319 * [@p from, @p to] (inclusive both edges), using the given @p step between elements.
2320 * @param from Start of the range of elements to generate.
2321 * @param to End of the range of elements to generate.
2322 * @param step Stepwidth to use between the generated elements.
2323 * @return CXXIter iterator returning elements from the requested range [@p from, @p to]
2324 * using the given @p step width.
2325 *
2326 * Usage Example:
2327 * - For an integer type:
2328 * @code
2329 * std::vector<int> output = CXXIter::range(1, 7, 2)
2330 * .collect<std::vector>();
2331 * // output == {1, 3, 5, 7}
2332 * @endcode
2333 * - For a float type
2334 * @code
2335 * std::vector<float> output = CXXIter::range(0.0f, 1.1f, 0.25f)
2336 * .collect<std::vector>();
2337 * // output == {0.0f, 0.25f, 0.5f, 0.75f, 1.0f}
2338 * @endcode
2339 */
2340 template<typename TValue>
2341 5 constexpr Range<TValue> range(TValue from, TValue to, TValue step = 1) {
2342 5 return Range<TValue>(from, to, step);
2343 }
2344 //@}
2345 }
2346