Embedded Template Library 1.0
Loading...
Searching...
No Matches
algorithm.h
Go to the documentation of this file.
1
2
3/******************************************************************************
4The MIT License(MIT)
5
6Embedded Template Library.
7https://github.com/ETLCPP/etl
8https://www.etlcpp.com
9
10Documentation: https://www.etlcpp.com/algorithm.html
11
12Copyright(c) 2014 John Wellbelove
13
14Permission is hereby granted, free of charge, to any person obtaining a copy
15of this software and associated documentation files(the "Software"), to deal
16in the Software without restriction, including without limitation the rights
17to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
18copies of the Software, and to permit persons to whom the Software is
19furnished to do so, subject to the following conditions :
20
21The above copyright notice and this permission notice shall be included in all
22copies or substantial portions of the Software.
23
24THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
25IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
26FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
27AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
28LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
29OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
30SOFTWARE.
31******************************************************************************/
32
33#ifndef ETL_ALGORITHM_INCLUDED
34#define ETL_ALGORITHM_INCLUDED
35
40
41#include "platform.h"
42#include "error_handler.h"
43#include "exception.h"
44#include "functional.h"
45#include "gcd.h"
46#include "initializer_list.h"
47#include "invoke.h"
48#include "iterator.h"
49#include "largest.h"
50#include "ranges.h"
51#include "type_traits.h"
52#include "utility.h"
53
54#include <stddef.h>
55#include <string.h>
56
57#include "private/minmax_push.h"
58
59#if ETL_USING_STL
60 #include <algorithm>
61 #include <functional>
62 #include <iterator>
63 #include <numeric>
64 #include <utility>
65#endif
66
67namespace etl
68{
69 // Declare prototypes of the ETL's sort functions
70 template <typename TIterator>
71#if ETL_USING_STD_NAMESPACE
72 ETL_CONSTEXPR20
73#else
74 ETL_CONSTEXPR14
75#endif
76 void
77 shell_sort(TIterator first, TIterator last);
78
79 template <typename TIterator, typename TCompare>
80#if ETL_USING_STD_NAMESPACE
81 ETL_CONSTEXPR20
82#else
83 ETL_CONSTEXPR14
84#endif
85 void
86 shell_sort(TIterator first, TIterator last, TCompare compare);
87
88 template <typename TIterator>
89 ETL_CONSTEXPR14 void insertion_sort(TIterator first, TIterator last);
90
91 template <typename TIterator, typename TCompare>
92 ETL_CONSTEXPR14 void insertion_sort(TIterator first, TIterator last, TCompare compare);
93
94} // namespace etl
95
96//*****************************************************************************
97// Algorithms defined by the ETL
98//*****************************************************************************
99namespace etl
100{
101 struct stable_partition_exception : etl::exception
102 {
103 stable_partition_exception(string_type reason_, string_type file_, numeric_type line_)
104 : etl::exception(reason_, file_, line_)
105 {
106 }
107 };
108
109 struct stable_partition_buffer_too_small : stable_partition_exception
110 {
111 stable_partition_buffer_too_small(string_type file_, numeric_type line_)
112 : stable_partition_exception(ETL_ERROR_TEXT("stable_partition:buffer too small", ETL_ALGORITHM_FILE_ID"A"), file_, line_)
113 {
114 }
115 };
116
117 namespace private_algorithm
118 {
119 template <bool use_swap>
120 struct swap_impl;
121
122 // Generic swap
123 template <>
124 struct swap_impl<false>
125 {
126 template <typename TIterator1, typename TIterator2>
127 static void do_swap(TIterator1 a, TIterator2 b)
128 {
129 typename etl::iterator_traits<TIterator1>::value_type tmp = *a;
130 *a = *b;
131 *b = tmp;
132 }
133 };
134
135 // Specialised swap
136 template <>
137 struct swap_impl<true>
138 {
139 template <typename TIterator1, typename TIterator2>
140 static void do_swap(TIterator1 a, TIterator2 b)
141 {
142 using ETL_OR_STD::swap; // Allow ADL
143 swap(*a, *b);
144 }
145 };
146 } // namespace private_algorithm
147
148 //***************************************************************************
149 // iter_swap
150 //***************************************************************************
151 template <typename TIterator1, typename TIterator2>
152#if ETL_USING_STD_NAMESPACE
153 ETL_CONSTEXPR20
154#else
155 ETL_CONSTEXPR14
156#endif
157 void
158 iter_swap(TIterator1 a, TIterator2 b)
159 {
160 typedef etl::iterator_traits<TIterator1> traits1;
161 typedef etl::iterator_traits<TIterator2> traits2;
162
163 typedef typename traits1::value_type v1;
164 typedef typename traits2::value_type v2;
165
166 typedef typename traits1::reference r1;
167 typedef typename traits2::reference r2;
168
169 const bool use_swap = etl::is_same<v1, v2>::value && etl::is_reference<r1>::value && etl::is_reference<r2>::value;
170
172 }
173
174 //***************************************************************************
175 // swap_ranges
176 //***************************************************************************
177 template <typename TIterator1, typename TIterator2>
178#if ETL_USING_STD_NAMESPACE
179 ETL_CONSTEXPR20
180#else
181 ETL_CONSTEXPR14
182#endif
183 TIterator2
184 swap_ranges(TIterator1 first1, TIterator1 last1, TIterator2 first2)
185 {
186 while (first1 != last1)
187 {
188 etl::iter_swap(first1, first2);
189 ++first1;
190 ++first2;
191 }
192
193 return first2;
194 }
195
196 //***************************************************************************
197 // generate
198 template <typename TIterator, typename TFunction>
199 ETL_CONSTEXPR14 void generate(TIterator db, TIterator de, TFunction funct)
200 {
201 while (db != de)
202 {
203 *db++ = funct();
204 }
205 }
206
207 //***************************************************************************
208 // copy
209#if ETL_USING_STL && ETL_USING_CPP20
210 // Use the STL constexpr implementation.
211 template <typename TIterator1, typename TIterator2>
212 constexpr TIterator2 copy(TIterator1 sb, TIterator1 se, TIterator2 db)
213 {
214 return std::copy(sb, se, db);
215 }
216#else
217 // Non-pointer or not trivially copyable or not using builtin memcpy.
218 template <typename TIterator1, typename TIterator2>
219 ETL_CONSTEXPR14 TIterator2 copy(TIterator1 sb, TIterator1 se, TIterator2 db)
220 {
221 while (sb != se)
222 {
223 *db = *sb;
224 ++db;
225 ++sb;
226 }
227
228 return db;
229 }
230#endif
231
232 //***************************************************************************
233 // reverse_copy
234#if ETL_USING_STL && ETL_USING_CPP20
235 template <typename TIterator1, typename TIterator2>
236 constexpr TIterator2 reverse_copy(TIterator1 sb, TIterator1 se, TIterator2 db)
237 {
238 return std::reverse_copy(sb, se, db);
239 }
240#else
241 template <typename TIterator1, typename TIterator2>
242 ETL_CONSTEXPR14 TIterator2 reverse_copy(TIterator1 sb, TIterator1 se, TIterator2 db)
243 {
244 while (sb != se)
245 {
246 *db = *--se;
247 ++db;
248 }
249
250 return db;
251 }
252#endif
253
254 //***************************************************************************
255 // copy_n
256#if ETL_USING_STL && ETL_USING_CPP20
257 // Use the STL implementation
258 template <typename TIterator1, typename TSize, typename TIterator2>
259 constexpr TIterator2 copy_n(TIterator1 sb, TSize count, TIterator2 db)
260 {
261 return std::copy_n(sb, count, db);
262 }
263#else
264 // Non-pointer or not trivially copyable or not using builtin memcpy.
265 template <typename TIterator1, typename TSize, typename TIterator2>
266 ETL_CONSTEXPR14 TIterator2 copy_n(TIterator1 sb, TSize count, TIterator2 db)
267 {
268 while (count != 0)
269 {
270 *db = *sb;
271 ++db;
272 ++sb;
273 --count;
274 }
275
276 return db;
277 }
278#endif
279
280 //***************************************************************************
281 // copy_backward
282#if ETL_USING_STL && ETL_USING_CPP20
283 template <typename TIterator1, typename TIterator2>
284 constexpr TIterator2 copy_backward(TIterator1 sb, TIterator1 se, TIterator2 de)
285 {
286 return std::copy_backward(sb, se, de);
287 }
288#else
289 template <typename TIterator1, typename TIterator2>
290 ETL_CONSTEXPR14 TIterator2 copy_backward(TIterator1 sb, TIterator1 se, TIterator2 de)
291 {
292 while (se != sb)
293 {
294 *(--de) = *(--se);
295 }
296
297 return de;
298 }
299#endif
300
301 //***************************************************************************
302 // move
303#if ETL_USING_STL && ETL_USING_CPP20
304 template <typename TIterator1, typename TIterator2>
305 constexpr TIterator2 move(TIterator1 sb, TIterator1 se, TIterator2 db)
306 {
307 return std::move(sb, se, db);
308 }
309#elif ETL_USING_CPP11
310 // For C++11
311 template <typename TIterator1, typename TIterator2>
312 ETL_CONSTEXPR14 TIterator2 move(TIterator1 sb, TIterator1 se, TIterator2 db)
313 {
314 while (sb != se)
315 {
316 *db = etl::move(*sb);
317 ++db;
318 ++sb;
319 }
320
321 return db;
322 }
323#else
324 // For C++03
325 template <typename TIterator1, typename TIterator2>
326 ETL_CONSTEXPR14 TIterator2 move(TIterator1 sb, TIterator1 se, TIterator2 db)
327 {
328 return copy(sb, se, db);
329 }
330#endif
331
332 //***************************************************************************
333 // move_backward
334#if ETL_USING_STL && ETL_USING_CPP20
335 template <typename TIterator1, typename TIterator2>
336 ETL_CONSTEXPR20 TIterator2 move_backward(TIterator1 sb, TIterator1 se, TIterator2 de)
337 {
339 return std::move_backward(sb, se, de);
341 }
342#elif ETL_USING_CPP11
343 // For C++11
344 template <typename TIterator1, typename TIterator2>
345 ETL_CONSTEXPR14 TIterator2 move_backward(TIterator1 sb, TIterator1 se, TIterator2 de)
346 {
347 while (sb != se)
348 {
349 *(--de) = etl::move(*(--se));
350 }
351
352 return de;
353 }
354#else
355 // For C++03
356 template <typename TIterator1, typename TIterator2>
357 ETL_CONSTEXPR14 TIterator2 move_backward(TIterator1 sb, TIterator1 se, TIterator2 de)
358 {
359 return etl::copy_backward(sb, se, de);
360 }
361#endif
362
363 //***************************************************************************
364 // reverse
365 //***************************************************************************
366 // Pointers
367 template <typename TIterator>
368 ETL_CONSTEXPR14 typename etl::enable_if<etl::is_pointer<TIterator>::value, void>::type reverse(TIterator b, TIterator e)
369 {
370 if (b != e)
371 {
372 while (b < --e)
373 {
374 etl::iter_swap(b, e);
375 ++b;
376 }
377 }
378 }
379
380 // Non-pointers
381 template <typename TIterator>
382 ETL_CONSTEXPR14 typename etl::enable_if<!etl::is_pointer<TIterator>::value, void>::type reverse(TIterator b, TIterator e)
383 {
384 while ((b != e) && (b != --e))
385 {
386 etl::iter_swap(b++, e);
387 }
388 }
389
390 //***************************************************************************
391 // lower_bound
392 //***************************************************************************
393 template <typename TIterator, typename TValue, typename TCompare>
394 ETL_NODISCARD ETL_CONSTEXPR14 TIterator lower_bound(TIterator first, TIterator last, const TValue& value, TCompare compare)
395 {
396 typedef typename etl::iterator_traits<TIterator>::difference_type difference_t;
397
398 difference_t count = etl::distance(first, last);
399
400 while (count > 0)
401 {
402 TIterator itr = first;
403 difference_t step = count / 2;
404
405 etl::advance(itr, step);
406
407 if (compare(*itr, value))
408 {
409 first = ++itr;
410 count -= step + 1;
411 }
412 else
413 {
414 count = step;
415 }
416 }
417
418 return first;
419 }
420
421 template <typename TIterator, typename TValue>
422 ETL_NODISCARD ETL_CONSTEXPR14 TIterator lower_bound(TIterator first, TIterator last, const TValue& value)
423 {
424 typedef etl::less<typename etl::iterator_traits<TIterator>::value_type> compare;
425
426 return etl::lower_bound(first, last, value, compare());
427 }
428
429 //***************************************************************************
430 // upper_bound
431 //***************************************************************************
432 template <typename TIterator, typename TValue, typename TCompare>
433 ETL_NODISCARD ETL_CONSTEXPR14 TIterator upper_bound(TIterator first, TIterator last, const TValue& value, TCompare compare)
434 {
435 typedef typename etl::iterator_traits<TIterator>::difference_type difference_t;
436
437 difference_t count = etl::distance(first, last);
438
439 while (count > 0)
440 {
441 TIterator itr = first;
442 difference_t step = count / 2;
443
444 etl::advance(itr, step);
445
446 if (!compare(value, *itr))
447 {
448 first = ++itr;
449 count -= step + 1;
450 }
451 else
452 {
453 count = step;
454 }
455 }
456
457 return first;
458 }
459
460 template <typename TIterator, typename TValue>
461 ETL_NODISCARD ETL_CONSTEXPR14 TIterator upper_bound(TIterator first, TIterator last, const TValue& value)
462 {
463 typedef etl::less<typename etl::iterator_traits<TIterator>::value_type> compare;
464
465 return etl::upper_bound(first, last, value, compare());
466 }
467
468 //***************************************************************************
469 // equal_range
470 //***************************************************************************
471 template <typename TIterator, typename TValue, typename TCompare>
472 ETL_NODISCARD ETL_CONSTEXPR14 ETL_OR_STD::pair<TIterator, TIterator> equal_range(TIterator first, TIterator last, const TValue& value, TCompare compare)
473 {
474 return ETL_OR_STD::make_pair(etl::lower_bound(first, last, value, compare), etl::upper_bound(first, last, value, compare));
475 }
476
477 template <typename TIterator, typename TValue>
478 ETL_NODISCARD
479 ETL_OR_STD::pair<TIterator, TIterator> equal_range(TIterator first, TIterator last, const TValue& value)
480 {
481 typedef etl::less<typename etl::iterator_traits<TIterator>::value_type> compare;
482
483 return ETL_OR_STD::make_pair(etl::lower_bound(first, last, value, compare()), etl::upper_bound(first, last, value, compare()));
484 }
485
486 //***************************************************************************
487 // binary_search
488 //***************************************************************************
489 template <typename TIterator, typename T, typename Compare>
490 ETL_NODISCARD ETL_CONSTEXPR14 bool binary_search(TIterator first, TIterator last, const T& value, Compare compare)
491 {
492 first = etl::lower_bound(first, last, value, compare);
493
494 return (!(first == last) && !(compare(value, *first)));
495 }
496
497 template <typename TIterator, typename T>
498 ETL_NODISCARD ETL_CONSTEXPR14 bool binary_search(TIterator first, TIterator last, const T& value)
499 {
500 typedef etl::less<typename etl::iterator_traits<TIterator>::value_type> compare;
501
502 return binary_search(first, last, value, compare());
503 }
504
505 //***************************************************************************
506 // find_if
507 //***************************************************************************
508 template <typename TIterator, typename TUnaryPredicate>
509 ETL_NODISCARD ETL_CONSTEXPR14 TIterator find_if(TIterator first, TIterator last, TUnaryPredicate predicate)
510 {
511 while (first != last)
512 {
513 if (predicate(*first))
514 {
515 return first;
516 }
517
518 ++first;
519 }
520
521 return last;
522 }
523
524 //***************************************************************************
525 // find
526 //***************************************************************************
527 template <typename TIterator, typename T>
528 ETL_NODISCARD ETL_CONSTEXPR14 TIterator find(TIterator first, TIterator last, const T& value)
529 {
530 while (first != last)
531 {
532 if (*first == value)
533 {
534 return first;
535 }
536
537 ++first;
538 }
539
540 return last;
541 }
542
543 //***************************************************************************
544 // fill
545#if ETL_USING_STL && ETL_USING_CPP20
546 template <typename TIterator, typename TValue>
547 constexpr void fill(TIterator first, TIterator last, const TValue& value)
548 {
549 std::fill(first, last, value);
550 }
551#else
552 template <typename TIterator, typename TValue>
553 ETL_CONSTEXPR14 void fill(TIterator first, TIterator last, const TValue& value)
554 {
555 while (first != last)
556 {
557 // This cast is necessary because the signedness can differ
558 *first = static_cast<typename etl::iterator_traits<TIterator>::value_type>(value);
559 ++first;
560 }
561 }
562#endif
563
564 //***************************************************************************
565 // fill_n
566#if ETL_USING_STL && ETL_USING_CPP20
567 template <typename TIterator, typename TSize, typename TValue>
568 constexpr TIterator fill_n(TIterator first, TSize count, const TValue& value)
569 {
570 return std::fill_n(first, count, value);
571 }
572#else
573 template <typename TIterator, typename TSize, typename TValue>
574 ETL_CONSTEXPR14 TIterator fill_n(TIterator first, TSize count, const TValue& value)
575 {
576 while (count != 0)
577 {
578 *first++ = value;
579 --count;
580 }
581
582 return first;
583 }
584#endif
585
586 //***************************************************************************
587 // count
588 //***************************************************************************
589 template <typename TIterator, typename T>
590 ETL_NODISCARD ETL_CONSTEXPR14 typename etl::iterator_traits<TIterator>::difference_type count(TIterator first, TIterator last, const T& value)
591 {
592 typename iterator_traits<TIterator>::difference_type n = 0;
593
594 while (first != last)
595 {
596 if (*first == value)
597 {
598 ++n;
599 }
600
601 ++first;
602 }
603
604 return n;
605 }
606
607 //***************************************************************************
608 // count_if
609 //***************************************************************************
610 template <typename TIterator, typename TUnaryPredicate>
611 ETL_NODISCARD ETL_CONSTEXPR14 typename etl::iterator_traits<TIterator>::difference_type count_if(TIterator first, TIterator last, TUnaryPredicate predicate)
612 {
613 typename iterator_traits<TIterator>::difference_type n = 0;
614
615 while (first != last)
616 {
617 if (predicate(*first))
618 {
619 ++n;
620 }
621
622 ++first;
623 }
624
625 return n;
626 }
627
628 //***************************************************************************
629 // equal
630#if ETL_USING_STL && ETL_USING_CPP20
631 // Three parameter
632 template <typename TIterator1, typename TIterator2>
633 [[nodiscard]]
634 constexpr bool equal(TIterator1 first1, TIterator1 last1, TIterator2 first2)
635 {
636 return std::equal(first1, last1, first2);
637 }
638
639 // Three parameter + predicate
640 template <typename TIterator1, typename TIterator2, typename TPredicate>
641 [[nodiscard]]
642 constexpr bool equal(TIterator1 first1, TIterator1 last1, TIterator2 first2, TPredicate predicate)
643 {
644 return std::equal(first1, last1, first2, predicate);
645 }
646
647 // Four parameter
648 template <typename TIterator1, typename TIterator2>
649 [[nodiscard]]
650 constexpr bool equal(TIterator1 first1, TIterator1 last1, TIterator2 first2, TIterator2 last2)
651 {
652 return std::equal(first1, last1, first2, last2);
653 }
654
655 // Four parameter + Predicate
656 template <typename TIterator1, typename TIterator2, typename TPredicate>
657 [[nodiscard]]
658 constexpr bool equal(TIterator1 first1, TIterator1 last1, TIterator2 first2, TIterator2 last2, TPredicate predicate)
659 {
660 return std::equal(first1, last1, first2, last2, predicate);
661 }
662
663#else
664
665 template <typename TIterator1, typename TIterator2>
666 ETL_NODISCARD ETL_CONSTEXPR14 bool equal(TIterator1 first1, TIterator1 last1, TIterator2 first2)
667 {
668 while (first1 != last1)
669 {
670 if (*first1 != *first2)
671 {
672 return false;
673 }
674
675 ++first1;
676 ++first2;
677 }
678
679 return true;
680 }
681
682 // Predicate
683 template <typename TIterator1, typename TIterator2, typename TPredicate>
684 ETL_NODISCARD ETL_CONSTEXPR14 bool equal(TIterator1 first1, TIterator1 last1, TIterator2 first2, TPredicate predicate)
685 {
686 while (first1 != last1)
687 {
688 if (!predicate(*first1, *first2))
689 {
690 return false;
691 }
692
693 ++first1;
694 ++first2;
695 }
696
697 return true;
698 }
699
700 // Four parameter
701 template <typename TIterator1, typename TIterator2>
702 ETL_NODISCARD ETL_CONSTEXPR14 bool equal(TIterator1 first1, TIterator1 last1, TIterator2 first2, TIterator2 last2)
703 {
704 while ((first1 != last1) && (first2 != last2))
705 {
706 if (*first1 != *first2)
707 {
708 return false;
709 }
710
711 ++first1;
712 ++first2;
713 }
714
715 return (first1 == last1) && (first2 == last2);
716 }
717
718 // Four parameter, Predicate
719 template <typename TIterator1, typename TIterator2, typename TPredicate>
720 ETL_NODISCARD ETL_CONSTEXPR14 bool equal(TIterator1 first1, TIterator1 last1, TIterator2 first2, TIterator2 last2, TPredicate predicate)
721 {
722 while ((first1 != last1) && (first2 != last2))
723 {
724 if (!predicate(*first1, *first2))
725 {
726 return false;
727 }
728
729 ++first1;
730 ++first2;
731 }
732
733 return (first1 == last1) && (first2 == last2);
734 }
735#endif
736
737 //***************************************************************************
738 // lexicographical_compare
739 //***************************************************************************
740 template <typename TIterator1, typename TIterator2, typename TCompare>
741 ETL_NODISCARD ETL_CONSTEXPR14 bool lexicographical_compare(TIterator1 first1, TIterator1 last1, TIterator2 first2, TIterator2 last2, TCompare compare)
742 {
743 while ((first1 != last1) && (first2 != last2))
744 {
745 if (compare(*first1, *first2))
746 {
747 return true;
748 }
749
750 if (compare(*first2, *first1))
751 {
752 return false;
753 }
754
755 ++first1;
756 ++first2;
757 }
758
759 return (first1 == last1) && (first2 != last2);
760 }
761
762 // lexicographical_compare
763 template <typename TIterator1, typename TIterator2>
764 ETL_NODISCARD ETL_CONSTEXPR14 bool lexicographical_compare(TIterator1 first1, TIterator1 last1, TIterator2 first2, TIterator2 last2)
765 {
766 typedef etl::less<typename etl::iterator_traits<TIterator1>::value_type> compare;
767
768 return etl::lexicographical_compare(first1, last1, first2, last2, compare());
769 }
770
771 //***************************************************************************
772 // min
773 //***************************************************************************
774 template <typename T, typename TCompare>
775 ETL_NODISCARD ETL_CONSTEXPR const T& min(const T& a, const T& b, TCompare compare)
776 {
777 return (compare(a, b)) ? a : b;
778 }
779
780 template <typename T>
781 ETL_NODISCARD ETL_CONSTEXPR const T& min(const T& a, const T& b)
782 {
783 typedef etl::less<T> compare;
784
785 return etl::min(a, b, compare());
786 }
787
788 //***************************************************************************
789 // max
790 //***************************************************************************
791 template <typename T, typename TCompare>
792 ETL_NODISCARD ETL_CONSTEXPR const T& max(const T& a, const T& b, TCompare compare)
793 {
794 return (compare(a, b)) ? b : a;
795 }
796
797 template <typename T>
798 ETL_NODISCARD ETL_CONSTEXPR const T& max(const T& a, const T& b)
799 {
800 typedef etl::less<T> compare;
801
802 return etl::max(a, b, compare());
803 }
804
805 //***************************************************************************
806 // for_each
807 //***************************************************************************
808 template <typename TIterator, typename TUnaryOperation>
809 ETL_CONSTEXPR14 TUnaryOperation for_each(TIterator first, TIterator last, TUnaryOperation unary_operation)
810 {
811 while (first != last)
812 {
813 unary_operation(*first);
814 ++first;
815 }
816
817 return unary_operation;
818 }
819
820 //***************************************************************************
821 // transform
822 //***************************************************************************
823 template <typename TIteratorIn, typename TIteratorOut, typename TUnaryOperation>
824 ETL_CONSTEXPR14 TIteratorOut transform(TIteratorIn first1, TIteratorIn last1, TIteratorOut d_first, TUnaryOperation unary_operation)
825 {
826 while (first1 != last1)
827 {
828 *d_first = unary_operation(*first1);
829
830 ++d_first;
831 ++first1;
832 }
833
834 return d_first;
835 }
836
837 template <typename TIteratorIn1, typename TIteratorIn2, typename TIteratorOut, typename TBinaryOperation>
838 ETL_CONSTEXPR14 TIteratorOut transform(TIteratorIn1 first1, TIteratorIn1 last1, TIteratorIn2 first2, TIteratorOut d_first,
839 TBinaryOperation binary_operation)
840 {
841 while (first1 != last1)
842 {
843 *d_first = binary_operation(*first1, *first2);
844
845 ++d_first;
846 ++first1;
847 ++first2;
848 }
849
850 return d_first;
851 }
852
853 //***************************************************************************
854 // replace
855 //***************************************************************************
856 template <typename TIterator, typename T>
857 ETL_CONSTEXPR14 void replace(TIterator first, TIterator last, const T& old_value, const T& new_value)
858 {
859 while (first != last)
860 {
861 if (*first == old_value)
862 {
863 *first = new_value;
864 }
865
866 ++first;
867 }
868 }
869
870 //***************************************************************************
871 // replace_if
872 //***************************************************************************
873 template <typename TIterator, typename TPredicate, typename T>
874 ETL_CONSTEXPR14 void replace_if(TIterator first, TIterator last, TPredicate predicate, const T& new_value)
875 {
876 while (first != last)
877 {
878 if (predicate(*first))
879 {
880 *first = new_value;
881 }
882
883 ++first;
884 }
885 }
886
887 //***************************************************************************
888 // Heap
889 //***************************************************************************
890 namespace private_heap
891 {
892 // Push Heap Helper
893 template <typename TIterator, typename TDistance, typename TValue, typename TCompare>
894 ETL_CONSTEXPR14 void push_heap(TIterator first, TDistance value_index, TDistance top_index, TValue value, TCompare compare)
895 {
896 TDistance parent = (value_index - 1) / 2;
897
899 while ((value_index > top_index) && compare(*(first + parent), value))
900 {
901 *(first + value_index) = ETL_MOVE(*(first + parent));
902 value_index = parent;
903 parent = (value_index - 1) / 2;
904 }
905
906 *(first + value_index) = ETL_MOVE(value);
908 }
909
910 // Adjust Heap Helper
911 template <typename TIterator, typename TDistance, typename TValue, typename TCompare>
912 ETL_CONSTEXPR14 void adjust_heap(TIterator first, TDistance value_index, TDistance length, TValue value, TCompare compare)
913 {
914 TDistance top_index = value_index;
915 TDistance child2nd = (2 * value_index) + 2;
916
918 while (child2nd < length)
919 {
920 if (compare(*(first + child2nd), *(first + (child2nd - 1))))
921 {
922 --child2nd;
923 }
924
925 *(first + value_index) = ETL_MOVE(*(first + child2nd));
926 value_index = child2nd;
927 child2nd = 2 * (child2nd + 1);
928 }
929
930 if (child2nd == length)
931 {
932 *(first + value_index) = ETL_MOVE(*(first + (child2nd - 1)));
933 value_index = child2nd - 1;
934 }
936
937 push_heap(first, value_index, top_index, ETL_MOVE(value), compare);
938 }
939
940 // Is Heap Helper
941 template <typename TIterator, typename TDistance, typename TCompare>
942 ETL_CONSTEXPR14 bool is_heap(const TIterator first, const TDistance n, TCompare compare)
943 {
944 TDistance parent = 0;
945
946 for (TDistance child = 1; child < n; ++child)
947 {
948 if (compare(*(first + parent), *(first + child)))
949 {
950 return false;
951 }
952
953 if ((child & 1) == 0)
954 {
955 ++parent;
956 }
957 }
958
959 return true;
960 }
961 } // namespace private_heap
962
963 // Pop Heap
964 template <typename TIterator, typename TCompare>
965 ETL_CONSTEXPR14 void pop_heap(TIterator first, TIterator last, TCompare compare)
966 {
967 typedef typename etl::iterator_traits<TIterator>::value_type value_t;
968 typedef typename etl::iterator_traits<TIterator>::difference_type distance_t;
969
970 const distance_t n = last - first;
971 if (n <= 1)
972 {
973 return;
974 }
975
976 value_t value = ETL_MOVE(*(last - 1));
977 *(last - 1) = ETL_MOVE(*first);
978
979 private_heap::adjust_heap(first, distance_t(0), distance_t(last - first - 1), ETL_MOVE(value), compare);
980 }
981
982 // Pop Heap
983 template <typename TIterator>
984 ETL_CONSTEXPR14 void pop_heap(TIterator first, TIterator last)
985 {
986 typedef etl::less<typename etl::iterator_traits<TIterator>::value_type> compare;
987
988 etl::pop_heap(first, last, compare());
989 }
990
991 // Push Heap
992 template <typename TIterator, typename TCompare>
993 ETL_CONSTEXPR14 void push_heap(TIterator first, TIterator last, TCompare compare)
994 {
995 typedef typename etl::iterator_traits<TIterator>::difference_type difference_t;
996 typedef typename etl::iterator_traits<TIterator>::value_type value_t;
997
998 private_heap::push_heap(first, difference_t(last - first - 1), difference_t(0), value_t(ETL_MOVE(*(last - 1))), compare);
999 }
1000
1001 // Push Heap
1002 template <typename TIterator>
1003 ETL_CONSTEXPR14 void push_heap(TIterator first, TIterator last)
1004 {
1005 typedef etl::less<typename etl::iterator_traits<TIterator>::value_type> compare;
1006
1007 etl::push_heap(first, last, compare());
1008 }
1009
1010 // Make Heap
1011 template <typename TIterator, typename TCompare>
1012 ETL_CONSTEXPR14 void make_heap(TIterator first, TIterator last, TCompare compare)
1013 {
1014 typedef typename etl::iterator_traits<TIterator>::difference_type difference_t;
1015
1016 if ((last - first) < 2)
1017 {
1018 return;
1019 }
1020
1021 difference_t length = last - first;
1022 difference_t parent = (length - 2) / 2;
1023
1024 while (true)
1025 {
1026 private_heap::adjust_heap(first, parent, length, ETL_MOVE(*(first + parent)), compare);
1027
1028 if (parent == 0)
1029 {
1030 return;
1031 }
1032
1033 --parent;
1034 }
1035 }
1036
1037 // Make Heap
1038 template <typename TIterator>
1039 ETL_CONSTEXPR14 void make_heap(TIterator first, TIterator last)
1040 {
1041 typedef etl::less<typename etl::iterator_traits<TIterator>::value_type> compare;
1042
1043 etl::make_heap(first, last, compare());
1044 }
1045
1046 // Is Heap
1047 template <typename TIterator>
1048 ETL_NODISCARD ETL_CONSTEXPR14 bool is_heap(TIterator first, TIterator last)
1049 {
1050 typedef etl::less<typename etl::iterator_traits<TIterator>::value_type> compare;
1051
1052 return private_heap::is_heap(first, last - first, compare());
1053 }
1054
1055 // Is Heap
1056 template <typename TIterator, typename TCompare>
1057 ETL_NODISCARD ETL_CONSTEXPR14 bool is_heap(TIterator first, TIterator last, TCompare compare)
1058 {
1059 return private_heap::is_heap(first, last - first, compare);
1060 }
1061
1062 // Sort Heap
1063 template <typename TIterator>
1064 ETL_CONSTEXPR14 void sort_heap(TIterator first, TIterator last)
1065 {
1066 while (first != last)
1067 {
1068 etl::pop_heap(first, last);
1069 --last;
1070 }
1071 }
1072
1073 // Sort Heap
1074 template <typename TIterator, typename TCompare>
1075 ETL_CONSTEXPR14 void sort_heap(TIterator first, TIterator last, TCompare compare)
1076 {
1077 while (first != last)
1078 {
1079 etl::pop_heap(first, last, compare);
1080 --last;
1081 }
1082 }
1083
1084 //***************************************************************************
1088 //***************************************************************************
1089 template <typename TIterator, typename TCompare>
1090 ETL_CONSTEXPR14 void partial_sort(TIterator first, TIterator middle, TIterator last, TCompare compare)
1091 {
1092 if (first == middle)
1093 {
1094 return;
1095 }
1096
1097 typedef typename etl::iterator_traits<TIterator>::value_type value_t;
1098 typedef typename etl::iterator_traits<TIterator>::difference_type difference_t;
1099
1100 etl::make_heap(first, middle, compare);
1101
1102 for (TIterator i = middle; i != last; ++i)
1103 {
1104 if (compare(*i, *first))
1105 {
1106 value_t value = ETL_MOVE(*i);
1107 *i = ETL_MOVE(*first);
1108
1109 private_heap::adjust_heap(first, difference_t(0), difference_t(middle - first), ETL_MOVE(value), compare);
1110 }
1111 }
1112
1113 etl::sort_heap(first, middle, compare);
1114 }
1115
1116 //***************************************************************************
1120 //***************************************************************************
1121 template <typename TIterator>
1122 ETL_CONSTEXPR14 void partial_sort(TIterator first, TIterator middle, TIterator last)
1123 {
1125
1126 etl::partial_sort(first, middle, last, compare());
1127 }
1128
1129 //***************************************************************************
1134 //***************************************************************************
1135 template <typename TInputIterator, typename TRandomAccessIterator, typename TCompare>
1136 ETL_CONSTEXPR14 TRandomAccessIterator partial_sort_copy(TInputIterator first, TInputIterator last, TRandomAccessIterator d_first,
1137 TRandomAccessIterator d_last, TCompare compare)
1138 {
1139 typedef typename etl::iterator_traits<TRandomAccessIterator>::value_type value_t;
1140 typedef typename etl::iterator_traits<TRandomAccessIterator>::difference_type difference_t;
1141
1142 TRandomAccessIterator result = d_first;
1143
1144 // Fill the destination range
1145 while ((first != last) && (result != d_last))
1146 {
1147 *result = *first;
1148 ++result;
1149 ++first;
1150 }
1151
1152 if (result == d_first)
1153 {
1154 return result;
1155 }
1156
1157 // Build a max-heap over the destination range
1158 etl::make_heap(d_first, result, compare);
1159
1160 // Process remaining input elements
1161 for (TInputIterator i = first; i != last; ++i)
1162 {
1163 if (compare(*i, *d_first))
1164 {
1165 value_t value = *i;
1166 private_heap::adjust_heap(d_first, difference_t(0), difference_t(result - d_first), ETL_MOVE(value), compare);
1167 }
1168 }
1169
1170 etl::sort_heap(d_first, result, compare);
1171
1172 return result;
1173 }
1174
1175 //***************************************************************************
1180 //***************************************************************************
1181 template <typename TInputIterator, typename TRandomAccessIterator>
1182 ETL_CONSTEXPR14 TRandomAccessIterator partial_sort_copy(TInputIterator first, TInputIterator last, TRandomAccessIterator d_first,
1183 TRandomAccessIterator d_last)
1184 {
1186
1187 return etl::partial_sort_copy(first, last, d_first, d_last, compare());
1188 }
1189
1190 //***************************************************************************
1191 // Search
1192 //***************************************************************************
1193 template <typename TIterator1, typename TIterator2, typename TCompare>
1194 ETL_NODISCARD ETL_CONSTEXPR14 TIterator1 search(TIterator1 first, TIterator1 last, TIterator2 search_first, TIterator2 search_last, TCompare compare)
1195 {
1196 while (true)
1197 {
1198 TIterator1 itr = first;
1199 TIterator2 search_itr = search_first;
1200
1201 while (true)
1202 {
1203 if (search_itr == search_last)
1204 {
1205 return first;
1206 }
1207
1208 if (itr == last)
1209 {
1210 return last;
1211 }
1212
1213 if (!compare(*itr, *search_itr))
1214 {
1215 break;
1216 }
1217
1218 ++itr;
1219 ++search_itr;
1220 }
1221
1222 ++first;
1223 }
1224 }
1225
1226 // Search
1227 template <typename TIterator1, typename TIterator2>
1228 ETL_NODISCARD ETL_CONSTEXPR14 TIterator1 search(TIterator1 first, TIterator1 last, TIterator2 search_first, TIterator2 search_last)
1229 {
1230 typedef etl::equal_to<typename etl::iterator_traits<TIterator1>::value_type> compare;
1231
1232 return etl::search(first, last, search_first, search_last, compare());
1233 }
1234
1235 //***************************************************************************
1236 // Rotate
1237 //***************************************************************************
1238 namespace private_algorithm
1239 {
1240 //*********************************
1241 // For random access iterators
1242 template <typename TIterator>
1243 ETL_CONSTEXPR14 typename etl::enable_if<etl::is_random_access_iterator<TIterator>::value, TIterator>::type
1244 rotate_general(TIterator first, TIterator middle, TIterator last)
1245 {
1246 if (first == middle)
1247 {
1248 return last;
1249 }
1250
1251 if (middle == last)
1252 {
1253 return first;
1254 }
1255
1256 typedef typename etl::iterator_traits<TIterator>::value_type value_type;
1257 typedef typename etl::iterator_traits<TIterator>::difference_type difference_type;
1258
1259 difference_type n = last - first;
1260 difference_type m = middle - first;
1261 difference_type gcd_nm = (n == 0 || m == 0) ? n + m : etl::gcd(n, m);
1262 TIterator result = first + (last - middle);
1263
1264 for (difference_type i = 0; i < gcd_nm; i++)
1265 {
1266 value_type temp = ETL_MOVE(*(first + i));
1267 difference_type j = i;
1268
1269 while (true)
1270 {
1271 difference_type k = j + m;
1272
1273 if (k >= n)
1274 {
1275 k = k - n;
1276 }
1277
1278 if (k == i)
1279 {
1280 break;
1281 }
1282
1283 *(first + j) = ETL_MOVE(*(first + k));
1284 j = k;
1285 }
1286
1287 *(first + j) = ETL_MOVE(temp);
1288 }
1289
1290 return result;
1291 }
1292
1293 //*********************************
1294 // For bidirectional iterators
1295 template <typename TIterator>
1296 ETL_CONSTEXPR14 typename etl::enable_if<etl::is_bidirectional_iterator<TIterator>::value, TIterator>::type
1297 rotate_general(TIterator first, TIterator middle, TIterator last)
1298 {
1299 if (first == middle)
1300 {
1301 return last;
1302 }
1303
1304 if (middle == last)
1305 {
1306 return first;
1307 }
1308
1309 TIterator result = first;
1310 etl::advance(result, etl::distance(middle, last));
1311
1312 reverse(first, middle);
1313 reverse(middle, last);
1314 reverse(first, last);
1315
1316 return result;
1317 }
1318
1319 //*********************************
1320 // For forward iterators
1321 template <typename TIterator>
1322 ETL_CONSTEXPR14 typename etl::enable_if<etl::is_forward_iterator<TIterator>::value, TIterator>::type rotate_general(TIterator first, TIterator middle,
1323 TIterator last)
1324 {
1325 if (first == middle)
1326 {
1327 return last;
1328 }
1329
1330 if (middle == last)
1331 {
1332 return first;
1333 }
1334
1335 TIterator next = middle;
1336 TIterator result = first;
1337 etl::advance(result, etl::distance(middle, last));
1338
1339 while (first != next)
1340 {
1341 using ETL_OR_STD::swap;
1342 swap(*first++, *next++);
1343
1344 if (next == last)
1345 {
1346 next = middle;
1347 }
1348 else if (first == middle)
1349 {
1350 middle = next;
1351 }
1352 }
1353
1354 return result;
1355 }
1356
1357 //*********************************
1358 // Simplified algorithm for rotate left by one
1359 template <typename TIterator>
1360 ETL_CONSTEXPR14 TIterator rotate_left_by_one(TIterator first, TIterator last)
1361 {
1362 typedef typename etl::iterator_traits<TIterator>::value_type value_type;
1363
1364 // Save the first item.
1365 value_type temp(ETL_MOVE(*first));
1366
1367 // Move the rest.
1369 TIterator result = etl::move(etl::next(first), last, first);
1371
1372 // Restore the first item in its rotated position.
1373 *result = ETL_MOVE(temp);
1374
1375 // The new position of the first item.
1376 return result;
1377 }
1378
1379 //*********************************
1380 // Simplified for algorithm rotate right by one
1381 template <typename TIterator>
1382 ETL_CONSTEXPR14 TIterator rotate_right_by_one(TIterator first, TIterator last)
1383 {
1384 typedef typename etl::iterator_traits<TIterator>::value_type value_type;
1385
1386 // Save the last item.
1387 TIterator previous = etl::prev(last);
1388 value_type temp(ETL_MOVE(*previous));
1389
1390 // Move the rest.
1391 TIterator result = etl::move_backward(first, previous, last);
1392
1393 // Restore the last item in its rotated position.
1394 *first = ETL_MOVE(temp);
1395
1396 // The new position of the first item.
1397 return result;
1398 }
1399 } // namespace private_algorithm
1400
1401 //*********************************
1402 template <typename TIterator>
1403 ETL_CONSTEXPR14 TIterator rotate(TIterator first, TIterator middle, TIterator last)
1404 {
1405 if (first == middle)
1406 {
1407 return last;
1408 }
1409 if (middle == last)
1410 {
1411 return first;
1412 }
1413
1414 if (etl::next(first) == middle)
1415 {
1416 return private_algorithm::rotate_left_by_one(first, last);
1417 }
1418
1419#if ETL_USING_CPP20
1420 if (etl::next(middle) == last)
1421 {
1422 if ETL_IF_CONSTEXPR (etl::is_bidirectional_iterator_concept< TIterator>::value)
1423 {
1424 return private_algorithm::rotate_right_by_one(first, last);
1425 }
1426 }
1427#endif
1428
1429 return private_algorithm::rotate_general(first, middle, last);
1430 }
1431
1432 //***************************************************************************
1433 // find_end
1434 //***************************************************************************
1435 // Predicate
1436 template <typename TIterator1, typename TIterator2, typename TPredicate>
1437 ETL_NODISCARD ETL_CONSTEXPR14 TIterator1 find_end(TIterator1 b, TIterator1 e, TIterator2 sb, TIterator2 se, TPredicate predicate)
1438 {
1439 if (sb == se)
1440 {
1441 return e;
1442 }
1443
1444 TIterator1 result = e;
1445
1446 while (true)
1447 {
1448 TIterator1 new_result = etl::search(b, e, sb, se, predicate);
1449
1450 if (new_result == e)
1451 {
1452 break;
1453 }
1454 else
1455 {
1456 result = new_result;
1457 b = result;
1458 ++b;
1459 }
1460 }
1461 return result;
1462 }
1463
1464 // Default
1465 template <typename TIterator1, typename TIterator2>
1466 ETL_NODISCARD ETL_CONSTEXPR14 TIterator1 find_end(TIterator1 b, TIterator1 e, TIterator2 sb, TIterator2 se)
1467 {
1468 typedef etl::equal_to<typename etl::iterator_traits<TIterator1>::value_type> predicate;
1469
1470 return find_end(b, e, sb, se, predicate());
1471 }
1472
1473 //***************************************************************************
1477 //***************************************************************************
1478 template <typename TIterator, typename TCompare>
1479 ETL_NODISCARD ETL_CONSTEXPR14 TIterator min_element(TIterator begin, TIterator end, TCompare compare)
1480 {
1481 TIterator minimum = begin;
1482
1483 if (begin != end)
1484 {
1485 ++begin;
1486
1487 while (begin != end)
1488 {
1489 if (compare(*begin, *minimum))
1490 {
1491 minimum = begin;
1492 }
1493
1494 ++begin;
1495 }
1496 }
1497
1498 return minimum;
1499 }
1500
1501 //***************************************************************************
1505 //***************************************************************************
1506 template <typename TIterator>
1507 ETL_NODISCARD ETL_CONSTEXPR14 TIterator min_element(TIterator begin, TIterator end)
1508 {
1509 typedef typename etl::iterator_traits<TIterator>::value_type value_t;
1510
1512 }
1513
1514 //***************************************************************************
1518 //***************************************************************************
1519 template <typename TIterator, typename TCompare>
1520 ETL_NODISCARD ETL_CONSTEXPR14 TIterator max_element(TIterator begin, TIterator end, TCompare compare)
1521 {
1522 TIterator maximum = begin;
1523
1524 if (begin != end)
1525 {
1526 ++begin;
1527
1528 while (begin != end)
1529 {
1530 if (compare(*maximum, *begin))
1531 {
1532 maximum = begin;
1533 }
1534
1535 ++begin;
1536 }
1537 }
1538
1539 return maximum;
1540 }
1541
1542 //***************************************************************************
1546 //***************************************************************************
1547 template <typename TIterator>
1548 ETL_NODISCARD ETL_CONSTEXPR14 TIterator max_element(TIterator begin, TIterator end)
1549 {
1550 typedef typename etl::iterator_traits<TIterator>::value_type value_t;
1551
1553 }
1554
1555 //***************************************************************************
1559 //***************************************************************************
1560 template <typename TIterator, typename TCompare>
1561 ETL_NODISCARD ETL_CONSTEXPR14 ETL_OR_STD::pair<TIterator, TIterator> minmax_element(TIterator begin, TIterator end, TCompare compare)
1562 {
1563 TIterator minimum = begin;
1564 TIterator maximum = begin;
1565
1566 if (begin != end)
1567 {
1568 ++begin;
1569
1570 while (begin != end)
1571 {
1572 if (compare(*begin, *minimum))
1573 {
1574 minimum = begin;
1575 }
1576
1577 if (!compare(*begin, *maximum))
1578 {
1579 maximum = begin;
1580 }
1581
1582 ++begin;
1583 }
1584 }
1585
1586 return ETL_OR_STD::pair<TIterator, TIterator>(minimum, maximum);
1587 }
1588
1589 //***************************************************************************
1593 //***************************************************************************
1594 template <typename TIterator>
1595 ETL_NODISCARD ETL_CONSTEXPR14 ETL_OR_STD::pair<TIterator, TIterator> minmax_element(TIterator begin, TIterator end)
1596 {
1597 typedef typename etl::iterator_traits<TIterator>::value_type value_t;
1598
1600 }
1601
1602 //***************************************************************************
1606 //***************************************************************************
1607 template <typename T>
1608 ETL_NODISCARD ETL_CONSTEXPR14 ETL_OR_STD::pair<const T&, const T&> minmax(const T& a, const T& b)
1609 {
1610 return (b < a) ? ETL_OR_STD::pair<const T&, const T&>(b, a) : ETL_OR_STD::pair<const T&, const T&>(a, b);
1611 }
1612
1613 //***************************************************************************
1617 //***************************************************************************
1618 template <typename T, typename TCompare>
1619 ETL_NODISCARD ETL_CONSTEXPR14 ETL_OR_STD::pair<const T&, const T&> minmax(const T& a, const T& b, TCompare compare)
1620 {
1621 return compare(b, a) ? ETL_OR_STD::pair<const T&, const T&>(b, a) : ETL_OR_STD::pair<const T&, const T&>(a, b);
1622 }
1623
1624 //***************************************************************************
1628 //***************************************************************************
1629 template <typename TIterator, typename TCompare>
1630 ETL_NODISCARD ETL_CONSTEXPR14 TIterator is_sorted_until(TIterator begin, TIterator end, TCompare compare)
1631 {
1632 if (begin != end)
1633 {
1634 TIterator next = begin;
1635
1636 while (++next != end)
1637 {
1638 if (compare(*next, *begin))
1639 {
1640 return next;
1641 }
1642
1643 ++begin;
1644 }
1645 }
1646
1647 return end;
1648 }
1649
1650 //***************************************************************************
1654 //***************************************************************************
1655 template <typename TIterator>
1656 ETL_NODISCARD ETL_CONSTEXPR14 TIterator is_sorted_until(TIterator begin, TIterator end)
1657 {
1659
1661 }
1662
1663 //***************************************************************************
1667 //***************************************************************************
1668 template <typename TIterator>
1669 ETL_NODISCARD ETL_CONSTEXPR14 bool is_sorted(TIterator begin, TIterator end)
1670 {
1671 return etl::is_sorted_until(begin, end) == end;
1672 }
1673
1674 //***************************************************************************
1678 //***************************************************************************
1679 template <typename TIterator, typename TCompare>
1680 ETL_NODISCARD ETL_CONSTEXPR14 bool is_sorted(TIterator begin, TIterator end, TCompare compare)
1681 {
1683 }
1684
1685 //***************************************************************************
1688 //***************************************************************************
1689 template <typename TIterator, typename TCompare>
1690 ETL_NODISCARD ETL_CONSTEXPR14 TIterator is_unique_sorted_until(TIterator begin, TIterator end, TCompare compare)
1691 {
1692 if (begin != end)
1693 {
1694 TIterator next = begin;
1695
1696 while (++next != end)
1697 {
1698 if (!compare(*begin, *next))
1699 {
1700 return next;
1701 }
1702
1703 ++begin;
1704 }
1705 }
1706
1707 return end;
1708 }
1709
1710 //***************************************************************************
1713 //***************************************************************************
1714 template <typename TIterator>
1715 ETL_NODISCARD ETL_CONSTEXPR14 TIterator is_unique_sorted_until(TIterator begin, TIterator end)
1716 {
1718
1720 }
1721
1722 //***************************************************************************
1725 //***************************************************************************
1726 template <typename TIterator>
1727 ETL_NODISCARD ETL_CONSTEXPR14 bool is_unique_sorted(TIterator begin, TIterator end)
1728 {
1730 }
1731
1732 //***************************************************************************
1735 //***************************************************************************
1736 template <typename TIterator, typename TCompare>
1737 ETL_NODISCARD ETL_CONSTEXPR14 bool is_unique_sorted(TIterator begin, TIterator end, TCompare compare)
1738 {
1740 }
1741
1742 //***************************************************************************
1746 //***************************************************************************
1747 template <typename TIterator, typename TUnaryPredicate>
1748 ETL_NODISCARD ETL_CONSTEXPR14 TIterator find_if_not(TIterator begin, TIterator end, TUnaryPredicate predicate)
1749 {
1750 while (begin != end)
1751 {
1752 if (!predicate(*begin))
1753 {
1754 return begin;
1755 }
1756
1757 ++begin;
1758 }
1759
1760 return end;
1761 }
1762
1763 //***************************************************************************
1767 //***************************************************************************
1768 template <typename TIterator, typename TBinaryPredicate>
1769 ETL_NODISCARD ETL_CONSTEXPR14 TIterator adjacent_find(TIterator first, TIterator last, TBinaryPredicate predicate)
1770 {
1771 if (first != last)
1772 {
1773 TIterator next = first;
1774 ++next;
1775
1776 while (next != last)
1777 {
1778 if (predicate(*first, *next))
1779 {
1780 return first;
1781 }
1782
1783 ++first;
1784 ++next;
1785 }
1786 }
1787
1788 return last;
1789 }
1790
1791 //***************************************************************************
1795 //***************************************************************************
1796 template <typename TIterator>
1797 ETL_NODISCARD ETL_CONSTEXPR14 TIterator adjacent_find(TIterator first, TIterator last)
1798 {
1800
1801 return etl::adjacent_find(first, last, predicate());
1802 }
1803
1804 //***************************************************************************
1808 //***************************************************************************
1809 template <typename TIterator1, typename TIterator2>
1810 ETL_NODISCARD ETL_CONSTEXPR14 bool is_permutation(TIterator1 begin1, TIterator1 end1, TIterator2 begin2)
1811 {
1812 if (begin1 != end1)
1813 {
1814 TIterator2 end2 = begin2;
1815
1816 etl::advance(end2, etl::distance(begin1, end1));
1817
1818 for (TIterator1 i = begin1; i != end1; ++i)
1819 {
1820 if (i == etl::find(begin1, i, *i))
1821 {
1822 size_t n = static_cast<size_t>(etl::count(begin2, end2, *i));
1823
1824 if (n == 0 || size_t(etl::count(i, end1, *i)) != n)
1825 {
1826 return false;
1827 }
1828 }
1829 }
1830 }
1831
1832 return true;
1833 }
1834
1835 //***************************************************************************
1839 //***************************************************************************
1840 template <typename TIterator1, typename TIterator2, typename TBinaryPredicate>
1841 ETL_NODISCARD ETL_CONSTEXPR14 bool is_permutation(TIterator1 begin1, TIterator1 end1, TIterator2 begin2, TBinaryPredicate predicate)
1842 {
1843 if (begin1 != end1)
1844 {
1845 TIterator2 end2 = begin2;
1846
1847 etl::advance(end2, etl::distance(begin1, end1));
1848
1849 for (TIterator1 i = begin1; i != end1; ++i)
1850 {
1851 const typename etl::binder1st<TBinaryPredicate> predicate_is_i = etl::bind1st(predicate, *i);
1852 if (i == etl::find_if(begin1, i, predicate_is_i))
1853 {
1854 size_t n = static_cast<size_t>(etl::count_if(begin2, end2, predicate_is_i));
1855
1856 if (n == 0 || size_t(etl::count_if(i, end1, predicate_is_i)) != n)
1857 {
1858 return false;
1859 }
1860 }
1861 }
1862 }
1863
1864 return true;
1865 }
1866
1867 //***************************************************************************
1871 //***************************************************************************
1872 template <typename TIterator1, typename TIterator2>
1873 ETL_NODISCARD ETL_CONSTEXPR14 bool is_permutation(TIterator1 begin1, TIterator1 end1, TIterator2 begin2, TIterator2 end2)
1874 {
1875 if (etl::distance(begin1, end1) != etl::distance(begin2, end2))
1876 {
1877 return false;
1878 }
1879
1880 if (begin1 != end1)
1881 {
1882 for (TIterator1 i = begin1; i != end1; ++i)
1883 {
1884 if (i == etl::find(begin1, i, *i))
1885 {
1886 size_t n = static_cast<size_t>(etl::count(begin2, end2, *i));
1887
1888 if (n == 0 || size_t(etl::count(i, end1, *i)) != n)
1889 {
1890 return false;
1891 }
1892 }
1893 }
1894 }
1895
1896 return true;
1897 }
1898
1899 //***************************************************************************
1903 //***************************************************************************
1904 template <typename TIterator1, typename TIterator2, typename TBinaryPredicate>
1905 ETL_NODISCARD ETL_CONSTEXPR14 bool is_permutation(TIterator1 begin1, TIterator1 end1, TIterator2 begin2, TIterator2 end2, TBinaryPredicate predicate)
1906 {
1907 if (etl::distance(begin1, end1) != etl::distance(begin2, end2))
1908 {
1909 return false;
1910 }
1911
1912 if (begin1 != end1)
1913 {
1914 for (TIterator1 i = begin1; i != end1; ++i)
1915 {
1916 const typename etl::binder1st<TBinaryPredicate> predicate_is_i = etl::bind1st(predicate, *i);
1917 if (i == etl::find_if(begin1, i, predicate_is_i))
1918 {
1919 size_t n = static_cast<size_t>(etl::count_if(begin2, end2, predicate_is_i));
1920
1921 if (n == 0 || size_t(etl::count_if(i, end1, predicate_is_i)) != n)
1922 {
1923 return false;
1924 }
1925 }
1926 }
1927 }
1928
1929 return true;
1930 }
1931
1932 //***************************************************************************
1936 //***************************************************************************
1937 template <typename TIterator, typename TCompare>
1938 ETL_CONSTEXPR14 bool next_permutation(TIterator first, TIterator last, TCompare compare)
1939 {
1940 if (first == last)
1941 {
1942 return false;
1943 }
1944
1945 TIterator i = last;
1946 --i;
1947
1948 if (first == i)
1949 {
1950 return false;
1951 }
1952
1953 while (true)
1954 {
1955 TIterator i1 = i;
1956 --i;
1957
1958 if (compare(*i, *i1))
1959 {
1960 TIterator j = last;
1961 --j;
1962
1963 while (!compare(*i, *j))
1964 {
1965 --j;
1966 }
1967
1968 etl::iter_swap(i, j);
1969 etl::reverse(i1, last);
1970 return true;
1971 }
1972
1973 if (i == first)
1974 {
1975 etl::reverse(first, last);
1976 return false;
1977 }
1978 }
1979 }
1980
1981 //***************************************************************************
1985 //***************************************************************************
1986 template <typename TIterator>
1987 ETL_CONSTEXPR14 bool next_permutation(TIterator first, TIterator last)
1988 {
1990 return etl::next_permutation(first, last, compare());
1991 }
1992
1993 //***************************************************************************
1997 //***************************************************************************
1998 template <typename TIterator, typename TCompare>
1999 ETL_CONSTEXPR14 bool prev_permutation(TIterator first, TIterator last, TCompare compare)
2000 {
2001 if (first == last)
2002 {
2003 return false;
2004 }
2005
2006 TIterator i = last;
2007 --i;
2008
2009 if (first == i)
2010 {
2011 return false;
2012 }
2013
2014 while (true)
2015 {
2016 TIterator i1 = i;
2017 --i;
2018
2019 if (compare(*i1, *i))
2020 {
2021 TIterator j = last;
2022 --j;
2023
2024 while (!compare(*j, *i))
2025 {
2026 --j;
2027 }
2028
2029 etl::iter_swap(i, j);
2030 etl::reverse(i1, last);
2031 return true;
2032 }
2033
2034 if (i == first)
2035 {
2036 etl::reverse(first, last);
2037 return false;
2038 }
2039 }
2040 }
2041
2042 //***************************************************************************
2046 //***************************************************************************
2047 template <typename TIterator>
2048 ETL_CONSTEXPR14 bool prev_permutation(TIterator first, TIterator last)
2049 {
2051 return etl::prev_permutation(first, last, compare());
2052 }
2053
2054 //***************************************************************************
2058 //***************************************************************************
2059 template <typename TIterator, typename TUnaryPredicate>
2060 ETL_NODISCARD ETL_CONSTEXPR14 bool is_partitioned(TIterator begin, TIterator end, TUnaryPredicate predicate)
2061 {
2062 while (begin != end)
2063 {
2064 if (!predicate(*begin))
2065 {
2066 break;
2067 }
2068
2069 ++begin;
2070 }
2071
2072 while (begin != end)
2073 {
2074 if (predicate(*begin))
2075 {
2076 return false;
2077 }
2078
2079 ++begin;
2080 }
2081
2082 return true;
2083 }
2084
2085 //***************************************************************************
2089 //***************************************************************************
2090 template <typename TIterator, typename TUnaryPredicate>
2091 ETL_NODISCARD ETL_CONSTEXPR14 TIterator partition_point(TIterator begin, TIterator end, TUnaryPredicate predicate)
2092 {
2093 typedef typename etl::iterator_traits<TIterator>::difference_type difference_t;
2094
2095 // binary search on a partitioned range
2096 for (difference_t length = etl::distance(begin, end); 0 < length;)
2097 {
2098 difference_t half = length / 2;
2099 TIterator middle = etl::next(begin, half);
2100 if (predicate(*middle))
2101 {
2102 begin = etl::next(middle);
2103 length -= (half + 1);
2104 }
2105 else
2106 {
2107 length = half;
2108 }
2109 }
2110
2111 return begin;
2112 }
2113
2114 //***************************************************************************
2119 //***************************************************************************
2120 template <typename TSource, typename TDestinationTrue, typename TDestinationFalse, typename TUnaryPredicate>
2121 ETL_CONSTEXPR14 ETL_OR_STD::pair<TDestinationTrue, TDestinationFalse> partition_copy(TSource begin, TSource end, TDestinationTrue destination_true,
2122 TDestinationFalse destination_false, TUnaryPredicate predicate)
2123 {
2124 while (begin != end)
2125 {
2126 if (predicate(*begin))
2127 {
2128 *destination_true = *begin;
2129 ++destination_true;
2130 }
2131 else
2132 {
2133 *destination_false = *begin;
2134 ++destination_false;
2135 }
2136
2137 ++begin;
2138 }
2139
2140 return ETL_OR_STD::pair<TDestinationTrue, TDestinationFalse>(destination_true, destination_false);
2141 }
2142
2143 //***************************************************************************
2147 //***************************************************************************
2148 template <typename TSource, typename TDestinationTrue, typename TDestinationFalse, typename TUnaryPredicate>
2149 ETL_CONSTEXPR14 ETL_OR_STD::pair<TDestinationTrue, TDestinationFalse> partition_move(TSource begin, TSource end, TDestinationTrue destination_true,
2150 TDestinationFalse destination_false, TUnaryPredicate predicate)
2151 {
2152 while (begin != end)
2153 {
2154 if (predicate(*begin))
2155 {
2156 *destination_true = etl::move(*begin);
2157 ++destination_true;
2158 }
2159 else
2160 {
2161 *destination_false = etl::move(*begin);
2162 ++destination_false;
2163 }
2164
2165 ++begin;
2166 }
2167
2168 return ETL_OR_STD::pair<TDestinationTrue, TDestinationFalse>(destination_true, destination_false);
2169 }
2170
2171 //***************************************************************************
2175 //***************************************************************************
2176 template <typename TIterator, typename TOutputIterator, typename TUnaryPredicate>
2177 ETL_CONSTEXPR14 TOutputIterator copy_if(TIterator begin, TIterator end, TOutputIterator out, TUnaryPredicate predicate)
2178 {
2179 while (begin != end)
2180 {
2181 if (predicate(*begin))
2182 {
2183 *out = *begin;
2184 ++out;
2185 }
2186
2187 ++begin;
2188 }
2189
2190 return out;
2191 }
2192
2193 //***************************************************************************
2197 //***************************************************************************
2198 template <typename TIterator, typename TUnaryPredicate>
2199 ETL_NODISCARD ETL_CONSTEXPR14 bool all_of(TIterator begin, TIterator end, TUnaryPredicate predicate)
2200 {
2201 return etl::find_if_not(begin, end, predicate) == end;
2202 }
2203
2204 //***************************************************************************
2208 //***************************************************************************
2209 template <typename TIterator, typename TUnaryPredicate>
2210 ETL_NODISCARD ETL_CONSTEXPR14 bool any_of(TIterator begin, TIterator end, TUnaryPredicate predicate)
2211 {
2212 return etl::find_if(begin, end, predicate) != end;
2213 }
2214
2215 //***************************************************************************
2219 //***************************************************************************
2220 template <typename TIterator, typename TUnaryPredicate>
2221 ETL_NODISCARD ETL_CONSTEXPR14 bool none_of(TIterator begin, TIterator end, TUnaryPredicate predicate)
2222 {
2223 return etl::find_if(begin, end, predicate) == end;
2224 }
2225
2226#if ETL_NOT_USING_STL
2227 //***************************************************************************
2231 //***************************************************************************
2232 template <typename TIterator, typename TCompare>
2233 void sort(TIterator first, TIterator last, TCompare compare)
2234 {
2235 etl::shell_sort(first, last, compare);
2236 }
2237
2238 //***************************************************************************
2241 //***************************************************************************
2242 template <typename TIterator>
2243 void sort(TIterator first, TIterator last)
2244 {
2245 etl::shell_sort(first, last, etl::less<typename etl::iterator_traits<TIterator>::value_type>());
2246 }
2247
2248 //***************************************************************************
2253 //***************************************************************************
2254 template <typename TIterator, typename TCompare>
2255 void stable_sort(TIterator first, TIterator last, TCompare compare)
2256 {
2257 etl::insertion_sort(first, last, compare);
2258 }
2259
2260 //***************************************************************************
2264 //***************************************************************************
2265 template <typename TIterator>
2266 void stable_sort(TIterator first, TIterator last)
2267 {
2268 etl::insertion_sort(first, last, etl::less<typename etl::iterator_traits<TIterator>::value_type>());
2269 }
2270#else
2271 //***************************************************************************
2275 //***************************************************************************
2276 template <typename TIterator, typename TCompare>
2277 void sort(TIterator first, TIterator last, TCompare compare)
2278 {
2279 std::sort(first, last, compare);
2280 }
2281
2282 //***************************************************************************
2285 //***************************************************************************
2286 template <typename TIterator>
2287 void sort(TIterator first, TIterator last)
2288 {
2289 std::sort(first, last);
2290 }
2291
2292 //***************************************************************************
2297 //***************************************************************************
2298 template <typename TIterator, typename TCompare>
2299 void stable_sort(TIterator first, TIterator last, TCompare compare)
2300 {
2301 std::stable_sort(first, last, compare);
2302 }
2303
2304 //***************************************************************************
2308 //***************************************************************************
2309 template <typename TIterator>
2310 void stable_sort(TIterator first, TIterator last)
2311 {
2312 std::stable_sort(first, last);
2313 }
2314#endif
2315
2316 //***************************************************************************
2319 //***************************************************************************
2320 template <typename TIterator, typename T>
2321 ETL_CONSTEXPR14 T accumulate(TIterator first, TIterator last, T sum)
2322 {
2323 while (first != last)
2324 {
2325 sum = static_cast<T>(ETL_MOVE(sum) + static_cast<T>(*first));
2326 ++first;
2327 }
2328
2329 return sum;
2330 }
2331
2332 //***************************************************************************
2335 //***************************************************************************
2336 template <typename TIterator, typename T, typename TBinaryOperation>
2337 ETL_CONSTEXPR14 T accumulate(TIterator first, TIterator last, T sum, TBinaryOperation operation)
2338 {
2339 while (first != last)
2340 {
2341 sum = operation(ETL_MOVE(sum), *first);
2342 ++first;
2343 }
2344
2345 return sum;
2346 }
2347
2348 //***************************************************************************
2351 //***************************************************************************
2352 template <typename T, typename TCompare>
2353 ETL_CONSTEXPR T clamp(const T& value, const T& low, const T& high, TCompare compare)
2354 {
2355 return compare(value, low) ? low : compare(high, value) ? high : value;
2356 }
2357
2358 template <typename T>
2359 ETL_CONSTEXPR T clamp(const T& value, const T& low, const T& high)
2360 {
2361 return clamp(value, low, high, etl::less<T>());
2362 }
2363
2364 template <typename T, T Low, T High, typename TCompare>
2365 ETL_CONSTEXPR T clamp(const T& value, TCompare compare)
2366 {
2367 return compare(value, Low) ? Low : compare(High, value) ? High : value;
2368 }
2369
2370 template <typename T, T Low, T High>
2371 ETL_CONSTEXPR T clamp(const T& value)
2372 {
2373 return clamp<T, Low, High>(value, etl::less<T>());
2374 }
2375
2376 //***************************************************************************
2379 //***************************************************************************
2380 template <typename TIterator, typename T>
2381 ETL_CONSTEXPR14 TIterator remove(TIterator first, TIterator last, const T& value)
2382 {
2383 first = etl::find(first, last, value);
2384
2385 if (first != last)
2386 {
2387 TIterator itr = first;
2388
2389 while (++itr != last)
2390 {
2391 if (!(*itr == value))
2392 {
2393 *first++ = ETL_MOVE(*itr);
2394 }
2395 }
2396 }
2397
2398 return first;
2399 }
2400
2401 //***************************************************************************
2404 //***************************************************************************
2405 template <typename TIterator, typename TUnaryPredicate>
2406 ETL_CONSTEXPR14 TIterator remove_if(TIterator first, TIterator last, TUnaryPredicate predicate)
2407 {
2408 first = etl::find_if(first, last, predicate);
2409
2410 if (first != last)
2411 {
2412 TIterator itr = first;
2413
2414 while (++itr != last)
2415 {
2416 if (!predicate(*itr))
2417 {
2418 *first++ = ETL_MOVE(*itr);
2419 }
2420 }
2421 }
2422
2423 return first;
2424 }
2425
2426 //***************************************************************************
2430 //***************************************************************************
2431 template <typename TIterator>
2432 ETL_CONSTEXPR14 TIterator unique(TIterator first, TIterator last)
2433 {
2434 if (first == last)
2435 {
2436 return last;
2437 }
2438
2439 TIterator result = first;
2440
2441 while (++first != last)
2442 {
2443 if (!(*result == *first) && (++result != first))
2444 {
2445 *result = ETL_MOVE(*first);
2446 }
2447 }
2448
2449 return ++result;
2450 }
2451
2452 //***************************************************************************
2457 //***************************************************************************
2458 template <typename TIterator, typename TBinaryPredicate>
2459 ETL_CONSTEXPR14 TIterator unique(TIterator first, TIterator last, TBinaryPredicate predicate)
2460 {
2461 if (first == last)
2462 {
2463 return last;
2464 }
2465
2466 TIterator result = first;
2467
2468 while (++first != last)
2469 {
2470 if (!predicate(*result, *first) && (++result != first))
2471 {
2472 *result = ETL_MOVE(*first);
2473 }
2474 }
2475
2476 return ++result;
2477 }
2478
2479 //***************************************************************************
2483 //***************************************************************************
2484 template <typename TInputIterator, typename TOutputIterator>
2485 ETL_CONSTEXPR14 TOutputIterator unique_copy(TInputIterator first, TInputIterator last, TOutputIterator d_first)
2486 {
2487 if (first == last)
2488 {
2489 return d_first;
2490 }
2491
2492 typename etl::iterator_traits<TInputIterator>::value_type prev = *first;
2493 *d_first = prev;
2494
2495 while (++first != last)
2496 {
2497 if (!(prev == *first))
2498 {
2499 prev = *first;
2500 *(++d_first) = prev;
2501 }
2502 }
2503
2504 return ++d_first;
2505 }
2506
2507 //***************************************************************************
2512 //***************************************************************************
2513 template <typename TInputIterator, typename TOutputIterator, typename TBinaryPredicate>
2514 ETL_CONSTEXPR14 TOutputIterator unique_copy(TInputIterator first, TInputIterator last, TOutputIterator d_first, TBinaryPredicate predicate)
2515 {
2516 if (first == last)
2517 {
2518 return d_first;
2519 }
2520
2521 typename etl::iterator_traits<TInputIterator>::value_type prev = *first;
2522 *d_first = prev;
2523
2524 while (++first != last)
2525 {
2526 if (!predicate(prev, *first))
2527 {
2528 prev = *first;
2529 *(++d_first) = prev;
2530 }
2531 }
2532
2533 return ++d_first;
2534 }
2535
2536 //***************************************************************************
2541 //***************************************************************************
2542 template <typename TInputIterator1, typename TInputIterator2, typename TOutputIterator, typename TCompare>
2543 ETL_CONSTEXPR14 TOutputIterator merge(TInputIterator1 first1, TInputIterator1 last1, TInputIterator2 first2, TInputIterator2 last2,
2544 TOutputIterator d_first, TCompare compare)
2545 {
2546 while ((first1 != last1) && (first2 != last2))
2547 {
2548 if (compare(*first2, *first1))
2549 {
2550 *d_first = *first2;
2551 ++first2;
2552 }
2553 else
2554 {
2555 *d_first = *first1;
2556 ++first1;
2557 }
2558 ++d_first;
2559 }
2560
2561 d_first = etl::copy(first1, last1, d_first);
2562 d_first = etl::copy(first2, last2, d_first);
2563
2564 return d_first;
2565 }
2566
2567 //***************************************************************************
2573 //***************************************************************************
2574 template <typename TInputIterator1, typename TInputIterator2, typename TOutputIterator>
2575 ETL_CONSTEXPR14 TOutputIterator merge(TInputIterator1 first1, TInputIterator1 last1, TInputIterator2 first2, TInputIterator2 last2,
2576 TOutputIterator d_first)
2577 {
2579
2580 return etl::merge(first1, last1, first2, last2, d_first, compare());
2581 }
2582
2583 //***************************************************************************
2593 //***************************************************************************
2594 template <typename TBidirectionalIterator, typename TCompare>
2595 void inplace_merge(TBidirectionalIterator first, TBidirectionalIterator middle, TBidirectionalIterator last, TCompare compare)
2596 {
2597 typedef typename etl::iterator_traits<TBidirectionalIterator>::difference_type difference_type;
2598
2599 difference_type len1 = etl::distance(first, middle);
2600 difference_type len2 = etl::distance(middle, last);
2601
2602 while ((len1 != 0) && (len2 != 0))
2603 {
2604 // Find where the first element of the right half belongs in the left
2605 // half. All elements in [first, cut1) are <= *middle, so they are already
2606 // in place.
2607 TBidirectionalIterator cut1 = etl::upper_bound(first, middle, *middle, compare);
2608 difference_type prefix = etl::distance(first, cut1);
2609 len1 -= prefix;
2610
2611 // If the entire left half is <= *middle, we are done.
2612 if (len1 == 0)
2613 {
2614 return;
2615 }
2616
2617 // Advance first past the already-placed prefix.
2618 first = cut1;
2619
2620 // Find where the first element of the (remaining) left half belongs in
2621 // the right half. All elements in [middle, cut2) are < *first, so they
2622 // need to be moved before *first.
2623 TBidirectionalIterator cut2 = etl::lower_bound(middle, last, *first, compare);
2624 difference_type run = etl::distance(middle, cut2);
2625 len2 -= run;
2626
2627 // Rotate the block [first, middle, cut2) so that [middle, cut2) moves
2628 // before [first, middle). After the rotate the elements from
2629 // [middle, cut2) (length = run) now occupy [first, first + run) and
2630 // are in their final position.
2631 etl::rotate(first, middle, cut2);
2632
2633 // Advance past the block we just placed.
2634 etl::advance(first, run);
2635 middle = cut2;
2636 }
2637 }
2638
2639 //***************************************************************************
2646 //***************************************************************************
2647 template <typename TBidirectionalIterator>
2648 void inplace_merge(TBidirectionalIterator first, TBidirectionalIterator middle, TBidirectionalIterator last)
2649 {
2651
2652 etl::inplace_merge(first, middle, last, compare());
2653 }
2654} // namespace etl
2655
2656//*****************************************************************************
2657// ETL extensions to the STL algorithms.
2658//*****************************************************************************
2659namespace etl
2660{
2661 //***************************************************************************
2671 //***************************************************************************
2672 template <typename TInputIterator, typename TOutputIterator>
2673 ETL_CONSTEXPR14
2674 typename etl::enable_if< etl::is_random_iterator<TInputIterator>::value && etl::is_random_iterator<TOutputIterator>::value, TOutputIterator>::type
2675 copy_s(TInputIterator i_begin, TInputIterator i_end, TOutputIterator o_begin, TOutputIterator o_end)
2676 {
2677 typedef typename iterator_traits<TInputIterator>::difference_type s_size_type;
2678 typedef typename iterator_traits<TOutputIterator>::difference_type d_size_type;
2679
2680#if ETL_USING_CPP11
2681 typedef typename etl::common_type<s_size_type, d_size_type>::type min_size_type;
2682#else
2683 typedef typename etl::largest_type<s_size_type, d_size_type>::type min_size_type;
2684#endif
2685
2686 s_size_type s_size = etl::distance(i_begin, i_end);
2687 d_size_type d_size = etl::distance(o_begin, o_end);
2688 min_size_type min_size = etl::min<min_size_type>(s_size, d_size);
2689
2690 return etl::copy(i_begin, i_begin + min_size, o_begin);
2691 }
2692
2693 //***************************************************************************
2703 //***************************************************************************
2704 template <typename TInputIterator, typename TOutputIterator>
2705 ETL_CONSTEXPR14 typename etl::enable_if< !etl::is_random_iterator<TInputIterator>::value || !etl::is_random_iterator<TOutputIterator>::value,
2706 TOutputIterator>::type
2707 copy_s(TInputIterator i_begin, TInputIterator i_end, TOutputIterator o_begin, TOutputIterator o_end)
2708 {
2709 while ((i_begin != i_end) && (o_begin != o_end))
2710 {
2711 *o_begin = *i_begin;
2712 ++o_begin;
2713 ++i_begin;
2714 }
2715
2716 return o_begin;
2717 }
2718
2719 //***************************************************************************
2723 //***************************************************************************
2724 template <typename TInputIterator, typename TSize, typename TOutputIterator>
2725 ETL_CONSTEXPR14 TOutputIterator copy_n_s(TInputIterator i_begin, TSize n, TOutputIterator o_begin, TOutputIterator o_end)
2726 {
2727 while ((n-- > 0) && (o_begin != o_end))
2728 {
2729 *o_begin = *i_begin;
2730 ++o_begin;
2731 ++i_begin;
2732 }
2733
2734 return o_begin;
2735 }
2736
2737 //***************************************************************************
2741 //***************************************************************************
2742 template <typename TInputIterator, typename TSize1, typename TOutputIterator, typename TSize2>
2743 ETL_CONSTEXPR14 TOutputIterator copy_n_s(TInputIterator i_begin, TSize1 n1, TOutputIterator o_begin, TSize2 n2)
2744 {
2745 while ((n1-- > 0) && (n2-- > 0))
2746 {
2747 *o_begin = *i_begin;
2748 ++o_begin;
2749 ++i_begin;
2750 }
2751
2752 return o_begin;
2753 }
2754
2755 //***************************************************************************
2760 //***************************************************************************
2761 template <typename TInputIterator, typename TOutputIterator, typename TUnaryPredicate>
2762 ETL_CONSTEXPR14 TOutputIterator copy_if_s(TInputIterator i_begin, TInputIterator i_end, TOutputIterator o_begin, TOutputIterator o_end,
2763 TUnaryPredicate predicate)
2764 {
2765 while ((i_begin != i_end) && (o_begin != o_end))
2766 {
2767 if (predicate(*i_begin))
2768 {
2769 *o_begin = *i_begin;
2770 ++o_begin;
2771 }
2772
2773 ++i_begin;
2774 }
2775
2776 return o_begin;
2777 }
2778
2779 //***************************************************************************
2783 //***************************************************************************
2784 template <typename TInputIterator, typename TSize, typename TOutputIterator, typename TUnaryPredicate>
2785 ETL_CONSTEXPR14 TOutputIterator copy_n_if(TInputIterator i_begin, TSize n, TOutputIterator o_begin, TUnaryPredicate predicate)
2786 {
2787 while (n-- > 0)
2788 {
2789 if (predicate(*i_begin))
2790 {
2791 *o_begin = *i_begin;
2792 ++o_begin;
2793 }
2794
2795 ++i_begin;
2796 }
2797
2798 return o_begin;
2799 }
2800
2801#if ETL_USING_CPP11
2802 //***************************************************************************
2812 //***************************************************************************
2813 template <typename TInputIterator, typename TOutputIterator>
2814 ETL_CONSTEXPR14
2815 typename etl::enable_if< etl::is_random_iterator<TInputIterator>::value && etl::is_random_iterator<TOutputIterator>::value, TOutputIterator>::type
2816 move_s(TInputIterator i_begin, TInputIterator i_end, TOutputIterator o_begin, TOutputIterator o_end)
2817 {
2818 using s_size_type = typename iterator_traits<TInputIterator>::difference_type;
2819 using d_size_type = typename iterator_traits<TOutputIterator>::difference_type;
2820 using min_size_type = typename etl::common_type<s_size_type, d_size_type>::type;
2821
2822 s_size_type s_size = etl::distance(i_begin, i_end);
2823 d_size_type d_size = etl::distance(o_begin, o_end);
2824 min_size_type min_size = etl::min<min_size_type>(s_size, d_size);
2825
2827 return etl::move(i_begin, i_begin + min_size, o_begin);
2829 }
2830
2831 //***************************************************************************
2841 //***************************************************************************
2842 template <typename TInputIterator, typename TOutputIterator>
2843 ETL_CONSTEXPR14 typename etl::enable_if< !etl::is_random_iterator<TInputIterator>::value || !etl::is_random_iterator<TOutputIterator>::value,
2844 TOutputIterator>::type
2845 move_s(TInputIterator i_begin, TInputIterator i_end, TOutputIterator o_begin, TOutputIterator o_end)
2846 {
2847 while ((i_begin != i_end) && (o_begin != o_end))
2848 {
2849 *o_begin = etl::move(*i_begin);
2850 ++i_begin;
2851 ++o_begin;
2852 }
2853
2854 return o_begin;
2855 }
2856#else
2857 //***************************************************************************
2868 //***************************************************************************
2869 template <typename TInputIterator, typename TOutputIterator>
2870 TOutputIterator move_s(TInputIterator i_begin, TInputIterator i_end, TOutputIterator o_begin, TOutputIterator o_end)
2871 {
2872 // Move not supported. Defer to copy.
2873 return etl::copy_s(i_begin, i_end, o_begin, o_end);
2874 }
2875#endif
2876
2877 //***************************************************************************
2882 //***************************************************************************
2883 template <typename TIterator, typename TValue>
2884 ETL_NODISCARD ETL_CONSTEXPR14 TIterator binary_find(TIterator begin, TIterator end, const TValue& value)
2885 {
2886 TIterator it = etl::lower_bound(begin, end, value);
2887
2888 if ((it == end) || (*it != value))
2889 {
2890 it = end;
2891 }
2892
2893 return it;
2894 }
2895
2896 //***************************************************************************
2901 //***************************************************************************
2902 template <typename TIterator, typename TValue, typename TBinaryPredicate, typename TBinaryEquality>
2903 ETL_NODISCARD ETL_CONSTEXPR14 TIterator binary_find(TIterator begin, TIterator end, const TValue& value, TBinaryPredicate predicate, TBinaryEquality equality)
2904 {
2905 TIterator it = etl::lower_bound(begin, end, value, predicate);
2906
2907 if ((it == end) || !equality(*it, value))
2908 {
2909 it = end;
2910 }
2911
2912 return it;
2913 }
2914
2915 //***************************************************************************
2918 //***************************************************************************
2919 template <typename TIterator, typename TUnaryFunction, typename TUnaryPredicate>
2920 ETL_CONSTEXPR14 TUnaryFunction for_each_if(TIterator begin, const TIterator end, TUnaryFunction function, TUnaryPredicate predicate)
2921 {
2922 while (begin != end)
2923 {
2924 if (predicate(*begin))
2925 {
2926 function(*begin);
2927 }
2928
2929 ++begin;
2930 }
2931
2932 return function;
2933 }
2934
2935 //***************************************************************************
2938 //***************************************************************************
2939 template <typename TIterator, typename TSize, typename TUnaryFunction>
2940 ETL_CONSTEXPR14 TIterator for_each_n(TIterator begin, TSize n, TUnaryFunction function)
2941 {
2942 while (n-- > 0)
2943 {
2944 function(*begin);
2945 ++begin;
2946 }
2947
2948 return begin;
2949 }
2950
2951 //***************************************************************************
2955 //***************************************************************************
2956 template <typename TIterator, typename TSize, typename TUnaryFunction, typename TUnaryPredicate>
2957 ETL_CONSTEXPR14 TIterator for_each_n_if(TIterator begin, TSize n, TUnaryFunction function, TUnaryPredicate predicate)
2958 {
2959 while (n-- > 0)
2960 {
2961 if (predicate(*begin))
2962 {
2963 function(*begin);
2964 }
2965
2966 ++begin;
2967 }
2968
2969 return begin;
2970 }
2971
2972 //***************************************************************************
2977 //***************************************************************************
2978 template <typename TInputIterator, typename TOutputIterator, typename TUnaryFunction>
2979 ETL_CONSTEXPR14 TOutputIterator transform_s(TInputIterator i_begin, TInputIterator i_end, TOutputIterator o_begin, TOutputIterator o_end,
2980 TUnaryFunction function)
2981 {
2982 while ((i_begin != i_end) && (o_begin != o_end))
2983 {
2984 *o_begin = function(*i_begin);
2985 ++i_begin;
2986 ++o_begin;
2987 }
2988
2989 return o_begin;
2990 }
2991
2992 //***************************************************************************
2997 //***************************************************************************
2998 template <typename TInputIterator, typename TSize, typename TOutputIterator, typename TUnaryFunction>
2999 ETL_CONSTEXPR14 void transform_n(TInputIterator i_begin, TSize n, TOutputIterator o_begin, TUnaryFunction function)
3000 {
3001 TInputIterator i_end(i_begin);
3002 etl::advance(i_end, n);
3003
3004 etl::transform(i_begin, i_end, o_begin, function);
3005 }
3006
3007 //***************************************************************************
3012 //***************************************************************************
3013 template <typename TInputIterator1, typename TInputIterator2, typename TSize, typename TOutputIterator, typename TBinaryFunction>
3014 ETL_CONSTEXPR14 void transform_n(TInputIterator1 i_begin1, TInputIterator2 i_begin2, TSize n, TOutputIterator o_begin, TBinaryFunction function)
3015 {
3016 TInputIterator1 i_end1(i_begin1);
3017 etl::advance(i_end1, n);
3018
3019 etl::transform(i_begin1, i_end1, i_begin2, o_begin, function);
3020 }
3021
3022 //***************************************************************************
3025 //***************************************************************************
3026 template <typename TInputIterator, typename TOutputIterator, typename TUnaryFunction, typename TUnaryPredicate>
3027 ETL_CONSTEXPR14 TOutputIterator transform_if(TInputIterator i_begin, const TInputIterator i_end, TOutputIterator o_begin, TUnaryFunction function,
3028 TUnaryPredicate predicate)
3029 {
3030 while (i_begin != i_end)
3031 {
3032 if (predicate(*i_begin))
3033 {
3034 *o_begin = function(*i_begin);
3035 ++o_begin;
3036 }
3037
3038 ++i_begin;
3039 }
3040
3041 return o_begin;
3042 }
3043
3044 //***************************************************************************
3047 //***************************************************************************
3048 template <typename TInputIterator1, typename TInputIterator2, typename TOutputIterator, typename TBinaryFunction, typename TBinaryPredicate>
3049 ETL_CONSTEXPR14 TOutputIterator transform_if(TInputIterator1 i_begin1, const TInputIterator1 i_end1, TInputIterator2 i_begin2, TOutputIterator o_begin,
3050 TBinaryFunction function, TBinaryPredicate predicate)
3051 {
3052 while (i_begin1 != i_end1)
3053 {
3054 if (predicate(*i_begin1, *i_begin2))
3055 {
3056 *o_begin = function(*i_begin1, *i_begin2);
3057 ++o_begin;
3058 }
3059
3060 ++i_begin1;
3061 ++i_begin2;
3062 }
3063
3064 return o_begin;
3065 }
3066
3067 //***************************************************************************
3070 //***************************************************************************
3071 template <typename TInputIterator, typename TSize, typename TOutputIterator, typename TUnaryFunction, typename TUnaryPredicate>
3072 ETL_CONSTEXPR14 TOutputIterator transform_n_if(TInputIterator i_begin, TSize n, TOutputIterator o_begin, TUnaryFunction function,
3073 TUnaryPredicate predicate)
3074 {
3075 while (n-- > 0)
3076 {
3077 if (predicate(*i_begin))
3078 {
3079 *o_begin = function(*i_begin);
3080 ++o_begin;
3081 }
3082
3083 ++i_begin;
3084 }
3085
3086 return o_begin;
3087 }
3088
3089 //***************************************************************************
3092 //***************************************************************************
3093 template <typename TInputIterator1, typename TInputIterator2, typename TSize, typename TOutputIterator, typename TBinaryFunction,
3094 typename TBinaryPredicate>
3095 ETL_CONSTEXPR14 TOutputIterator transform_n_if(TInputIterator1 i_begin1, TInputIterator2 i_begin2, TSize n, TOutputIterator o_begin,
3096 TBinaryFunction function, TBinaryPredicate predicate)
3097 {
3098 while (n-- > 0)
3099 {
3100 if (predicate(*i_begin1, *i_begin2))
3101 {
3102 *o_begin++ = function(*i_begin1, *i_begin2);
3103 }
3104
3105 ++i_begin1;
3106 ++i_begin2;
3107 }
3108
3109 return o_begin;
3110 }
3111
3112 //***************************************************************************
3116 //***************************************************************************
3117 template <typename TSource, typename TDestinationTrue, typename TDestinationFalse, typename TUnaryFunctionTrue, typename TUnaryFunctionFalse,
3118 typename TUnaryPredicate>
3119 ETL_CONSTEXPR14 ETL_OR_STD::pair<TDestinationTrue, TDestinationFalse>
3120 partition_transform(TSource begin, TSource end, TDestinationTrue destination_true, TDestinationFalse destination_false,
3121 TUnaryFunctionTrue function_true, TUnaryFunctionFalse function_false, TUnaryPredicate predicate)
3122 {
3123 while (begin != end)
3124 {
3125 if (predicate(*begin))
3126 {
3127 *destination_true = function_true(*begin);
3128 ++destination_true;
3129 }
3130 else
3131 {
3132 *destination_false = function_false(*begin);
3133 ++destination_false;
3134 }
3135
3136 ++begin;
3137 }
3138
3139 return ETL_OR_STD::pair<TDestinationTrue, TDestinationFalse>(destination_true, destination_false);
3140 }
3141
3142 //***************************************************************************
3146 //***************************************************************************
3147 template <typename TSource1, typename TSource2, typename TDestinationTrue, typename TDestinationFalse, typename TBinaryFunctionTrue,
3148 typename TBinaryFunctionFalse, typename TBinaryPredicate>
3149 ETL_CONSTEXPR14 ETL_OR_STD::pair<TDestinationTrue, TDestinationFalse>
3150 partition_transform(TSource1 begin1, TSource1 end1, TSource2 begin2, TDestinationTrue destination_true, TDestinationFalse destination_false,
3151 TBinaryFunctionTrue function_true, TBinaryFunctionFalse function_false, TBinaryPredicate predicate)
3152 {
3153 while (begin1 != end1)
3154 {
3155 if (predicate(*begin1, *begin2))
3156 {
3157 *destination_true = function_true(*begin1, *begin2);
3158 ++destination_true;
3159 }
3160 else
3161 {
3162 *destination_false = function_false(*begin1, *begin2);
3163 ++destination_false;
3164 }
3165
3166 ++begin1;
3167 ++begin2;
3168 }
3169
3170 return ETL_OR_STD::pair<TDestinationTrue, TDestinationFalse>(destination_true, destination_false);
3171 }
3172
3173 //***************************************************************************
3177 //***************************************************************************
3178 template <typename TIterator, typename TCompare>
3179#if ETL_USING_STD_NAMESPACE
3180 ETL_CONSTEXPR20
3181#else
3182 ETL_CONSTEXPR14
3183#endif
3184 void
3185 shell_sort(TIterator first, TIterator last, TCompare compare)
3186 {
3187 if (first == last)
3188 {
3189 return;
3190 }
3191
3192 typedef typename etl::iterator_traits<TIterator>::difference_type difference_t;
3193
3194 difference_t n = etl::distance(first, last);
3195
3196 for (difference_t i = n / 2; i > 0; i /= 2)
3197 {
3198 for (difference_t j = i; j < n; ++j)
3199 {
3200 for (difference_t k = j - i; k >= 0; k -= i)
3201 {
3202 TIterator itr1 = first;
3203 TIterator itr2 = first;
3204
3205 etl::advance(itr1, k);
3206 etl::advance(itr2, k + i);
3207
3208 if (compare(*itr2, *itr1))
3209 {
3210 etl::iter_swap(itr1, itr2);
3211 }
3212 }
3213 }
3214 }
3215 }
3216
3217 //***************************************************************************
3220 //***************************************************************************
3221 template <typename TIterator>
3222#if ETL_USING_STD_NAMESPACE
3223 ETL_CONSTEXPR20
3224#else
3225 ETL_CONSTEXPR14
3226#endif
3227 void
3228 shell_sort(TIterator first, TIterator last)
3229 {
3230 etl::shell_sort(first, last, etl::less<typename etl::iterator_traits<TIterator>::value_type>());
3231 }
3232
3233 //***************************************************************************
3237 //***************************************************************************
3238 template <typename TIterator, typename TCompare>
3239 ETL_CONSTEXPR14 void insertion_sort(TIterator first, TIterator last, TCompare compare)
3240 {
3241 for (TIterator itr = first; itr != last; ++itr)
3242 {
3243 etl::rotate(etl::upper_bound(first, itr, *itr, compare), itr, etl::next(itr));
3244 }
3245 }
3246
3247 //***************************************************************************
3250 //***************************************************************************
3251 template <typename TIterator>
3252 ETL_CONSTEXPR14 void insertion_sort(TIterator first, TIterator last)
3253 {
3254 etl::insertion_sort(first, last, etl::less<typename etl::iterator_traits<TIterator>::value_type>());
3255 }
3256
3257 //***************************************************************************
3258 namespace private_algorithm
3259 {
3260 template <typename TIterator>
3261 ETL_CONSTEXPR14 typename etl::enable_if<etl::is_forward_iterator<TIterator>::value, TIterator>::type get_before_last(TIterator first_, TIterator last_)
3262 {
3263 TIterator last = first_;
3264 TIterator lastplus1 = first_;
3265 ++lastplus1;
3266
3267 while (lastplus1 != last_)
3268 {
3269 ++last;
3270 ++lastplus1;
3271 }
3272
3273 return last;
3274 }
3275
3276 template <typename TIterator>
3277 ETL_CONSTEXPR14 typename etl::enable_if<etl::is_bidirectional_iterator<TIterator>::value, TIterator>::type get_before_last(TIterator /*first_*/,
3278 TIterator last_)
3279 {
3280 TIterator last = last_;
3281 --last;
3282
3283 return last;
3284 }
3285
3286 template <typename TIterator>
3287 ETL_CONSTEXPR14 typename etl::enable_if<etl::is_random_access_iterator<TIterator>::value, TIterator>::type get_before_last(TIterator /*first_*/,
3288 TIterator last_)
3289 {
3290 return last_ - 1;
3291 }
3292 } // namespace private_algorithm
3293
3294 //***************************************************************************
3298 //***************************************************************************
3299 template <typename TIterator, typename TCompare>
3300 ETL_CONSTEXPR20 void selection_sort(TIterator first, TIterator last, TCompare compare)
3301 {
3302 if (first == last)
3303 {
3304 return;
3305 }
3306
3307 TIterator min;
3308 const TIterator ilast = private_algorithm::get_before_last(first, last);
3309 const TIterator jlast = last;
3310
3311 for (TIterator i = first; i != ilast; ++i)
3312 {
3313 min = i;
3314
3315 TIterator j = i;
3316 ++j;
3317
3318 for (; j != jlast; ++j)
3319 {
3320 if (compare(*j, *min))
3321 {
3322 min = j;
3323 }
3324 }
3325
3326 using ETL_OR_STD::swap; // Allow ADL
3327 if (min != i)
3328 {
3329 swap(*i, *min);
3330 }
3331 }
3332 }
3333
3334 //***************************************************************************
3337 //***************************************************************************
3338 template <typename TIterator>
3339 ETL_CONSTEXPR20 void selection_sort(TIterator first, TIterator last)
3340 {
3341 selection_sort(first, last, etl::less<typename etl::iterator_traits<TIterator>::value_type>());
3342 }
3343
3344 //***************************************************************************
3348 //***************************************************************************
3349 template <typename TIterator, typename TCompare>
3350 ETL_CONSTEXPR14 void heap_sort(TIterator first, TIterator last, TCompare compare)
3351 {
3352 etl::make_heap(first, last, compare);
3353 etl::sort_heap(first, last, compare);
3354 }
3355
3356 //***************************************************************************
3359 //***************************************************************************
3360 template <typename TIterator>
3361 ETL_CONSTEXPR14 void heap_sort(TIterator first, TIterator last)
3362 {
3363 etl::make_heap(first, last);
3364 etl::sort_heap(first, last);
3365 }
3366
3367 //***************************************************************************
3369 //***************************************************************************
3370#if ETL_USING_CPP11
3371 template <typename T>
3372 ETL_NODISCARD
3373 constexpr const T& multimax(const T& a, const T& b)
3374 {
3375 return a < b ? b : a;
3376 }
3377
3378 template <typename T, typename... Tx>
3379 ETL_NODISCARD
3380 constexpr const T& multimax(const T& t, const Tx&... tx)
3381 {
3382 return multimax(t, multimax(tx...));
3383 }
3384#endif
3385
3386 //***************************************************************************
3389 //***************************************************************************
3390#if ETL_USING_CPP11
3391 template <typename TCompare, typename T>
3392 ETL_NODISCARD
3393 constexpr const T& multimax_compare(TCompare compare, const T& a, const T& b)
3394 {
3395 return compare(a, b) ? b : a;
3396 }
3397
3398 template <typename TCompare, typename T, typename... Tx>
3399 ETL_NODISCARD
3400 constexpr const T& multimax_compare(TCompare compare, const T& t, const Tx&... tx)
3401 {
3402 return multimax_compare(compare, t, multimax_compare(compare, tx...));
3403 }
3404#endif
3405
3406 //***************************************************************************
3408 //***************************************************************************
3409#if ETL_USING_CPP11
3410 template <typename T>
3411 ETL_NODISCARD
3412 constexpr const T& multimin(const T& a, const T& b)
3413 {
3414 return a < b ? a : b;
3415 }
3416
3417 template <typename T, typename... Tx>
3418 ETL_NODISCARD
3419 constexpr const T& multimin(const T& t, const Tx&... tx)
3420 {
3421 return multimin(t, multimin(tx...));
3422 }
3423#endif
3424
3425 //***************************************************************************
3428 //***************************************************************************
3429#if ETL_USING_CPP11
3430 template <typename TCompare, typename T>
3431 ETL_NODISCARD
3432 constexpr const T& multimin_compare(TCompare compare, const T& a, const T& b)
3433 {
3434 return compare(a, b) ? a : b;
3435 }
3436
3437 template <typename TCompare, typename T, typename... Tx>
3438 ETL_NODISCARD
3439 constexpr const T& multimin_compare(TCompare compare, const T& t, const Tx&... tx)
3440 {
3441 return multimin_compare(compare, t, multimin_compare(compare, tx...));
3442 }
3443#endif
3444
3445 //***************************************************************************
3447 //***************************************************************************
3448#if ETL_USING_CPP11
3449 template <typename TIterator>
3450 ETL_NODISCARD
3451 constexpr const TIterator& multimax_iter(const TIterator& a, const TIterator& b)
3452 {
3453 return *a < *b ? b : a;
3454 }
3455
3456 template <typename TIterator, typename... TIteratorx>
3457 ETL_NODISCARD
3458 constexpr const TIterator& multimax_iter(const TIterator& t, const TIteratorx&... tx)
3459 {
3460 return multimax_iter(t, multimax_iter(tx...));
3461 }
3462#endif
3463
3464 //***************************************************************************
3467 //***************************************************************************
3468#if ETL_USING_CPP11
3469 template <typename TCompare, typename TIterator>
3470 ETL_NODISCARD
3471 constexpr const TIterator& multimax_iter_compare(TCompare compare, const TIterator& a, const TIterator& b)
3472 {
3473 return compare(*a, *b) ? b : a;
3474 }
3475
3476 template <typename TCompare, typename TIterator, typename... TIteratorx>
3477 ETL_NODISCARD
3478 constexpr const TIterator& multimax_iter_compare(TCompare compare, const TIterator& t, const TIteratorx&... tx)
3479 {
3480 return multimax_iter_compare(compare, t, multimax_iter_compare(compare, tx...));
3481 }
3482#endif
3483
3484 //***************************************************************************
3486 //***************************************************************************
3487#if ETL_USING_CPP11
3488 template <typename TIterator>
3489 ETL_NODISCARD
3490 constexpr const TIterator& multimin_iter(const TIterator& a, const TIterator& b)
3491 {
3492 return *a < *b ? a : b;
3493 }
3494
3495 template <typename TIterator, typename... Tx>
3496 ETL_NODISCARD
3497 constexpr const TIterator& multimin_iter(const TIterator& t, const Tx&... tx)
3498 {
3499 return multimin_iter(t, multimin_iter(tx...));
3500 }
3501#endif
3502
3503 //***************************************************************************
3506 //***************************************************************************
3507#if ETL_USING_CPP11
3508 template <typename TCompare, typename TIterator>
3509 ETL_NODISCARD
3510 constexpr const TIterator& multimin_iter_compare(TCompare compare, const TIterator& a, const TIterator& b)
3511 {
3512 return compare(*a, *b) ? a : b;
3513 }
3514
3515 template <typename TCompare, typename TIterator, typename... Tx>
3516 ETL_NODISCARD
3517 constexpr const TIterator& multimin_iter_compare(TCompare compare, const TIterator& t, const Tx&... tx)
3518 {
3519 return multimin_iter_compare(compare, t, multimin_iter_compare(compare, tx...));
3520 }
3521#endif
3522
3523 //***************************************************************************
3527 //***************************************************************************
3528 template <typename TIterator, typename TPredicate>
3529 ETL_CONSTEXPR14 typename etl::enable_if<etl::is_forward_iterator<TIterator>::value, TIterator>::type partition(TIterator first, TIterator last,
3530 TPredicate predicate)
3531 {
3532 first = etl::find_if_not(first, last, predicate);
3533
3534 if (first == last)
3535 {
3536 return first;
3537 }
3538
3539 for (TIterator i = etl::next(first); i != last; ++i)
3540 {
3541 if (predicate(*i))
3542 {
3543 using ETL_OR_STD::swap;
3544 swap(*i, *first);
3545 ++first;
3546 }
3547 }
3548
3549 return first;
3550 }
3551
3552 //***************************************************************************
3556 //***************************************************************************
3557 template <typename TIterator, typename TPredicate>
3558 ETL_CONSTEXPR14 typename etl::enable_if< etl::is_bidirectional_iterator_concept<TIterator>::value, TIterator>::type
3559 partition(TIterator first, TIterator last, TPredicate predicate)
3560 {
3561 while (first != last)
3562 {
3563 first = etl::find_if_not(first, last, predicate);
3564
3565 if (first == last)
3566 {
3567 break;
3568 }
3569
3570 last = etl::find_if(etl::reverse_iterator<TIterator>(last), etl::reverse_iterator<TIterator>(first), predicate).base();
3571
3572 if (first == last)
3573 {
3574 break;
3575 }
3576
3577 --last;
3578 using ETL_OR_STD::swap;
3579 swap(*first, *last);
3580 ++first;
3581 }
3582
3583 return first;
3584 }
3585
3586 //***************************************************************************
3590 //***************************************************************************
3591 template <typename TIterator, typename TPredicate>
3592 ETL_CONSTEXPR14 TIterator stable_partition(TIterator first, TIterator last, TPredicate predicate)
3593 {
3594 typename etl::iterator_traits<TIterator>::difference_type n = etl::distance(first, last);
3595
3596 if (n <= 1)
3597 {
3598 // Empty or single-element range: trivially partitioned either way.
3599 return first;
3600 }
3601
3602 TIterator mid = first;
3603 etl::advance(mid, n / 2);
3604
3605 etl::stable_partition(first, mid, predicate);
3606 etl::stable_partition(mid, last, predicate);
3607
3608 TIterator left_partition_start = etl::find_if_not(first, last, predicate);
3609 TIterator right_partition_start = etl::find_if(left_partition_start, last, predicate);
3610 TIterator right_partition_end = etl::find_if_not(right_partition_start, last, predicate);
3611
3612 return etl::rotate(left_partition_start, right_partition_start, right_partition_end);
3613 }
3614
3615 //***************************************************************************
3619 //***************************************************************************
3620 template <typename TIterator, typename TPredicate>
3621 ETL_CONSTEXPR14 TIterator stable_partition(TIterator first, TIterator last, TIterator buffer_first, TIterator buffer_last, TPredicate predicate)
3622 {
3623 typename etl::iterator_traits<TIterator>::difference_type n = etl::distance(first, last);
3624
3625 ETL_ASSERT((n <= etl::distance(buffer_first, buffer_last)), ETL_ERROR(stable_partition_buffer_too_small));
3626
3627 if (n <= 1)
3628 {
3629 // Empty or single-element range.
3630 return first;
3631 }
3632
3633 TIterator input_first = first;
3634 TIterator buffer_true = buffer_first;
3635
3636 // Find where the partition point will be in the buffer.
3637 typename etl::iterator_traits<TIterator>::difference_type true_count = etl::count_if(first, last, predicate);
3638 TIterator buffer_false = buffer_first + true_count;
3639
3640 // Move them to the correct places in the temporary buffer.
3641 while (first != last)
3642 {
3643 if (predicate(*first))
3644 {
3645 *buffer_true++ = etl::move(*first);
3646 }
3647 else
3648 {
3649 *buffer_false++ = etl::move(*first);
3650 }
3651
3652 ++first;
3653 }
3654
3655 // Move them back to the original range.
3656 TIterator buffer_end = buffer_first;
3657 etl::advance(buffer_end, n);
3658 etl::move(buffer_first, buffer_end, input_first);
3659
3660 etl::advance(input_first, true_count);
3661
3662 return input_first;
3663 }
3664
3665 //*********************************************************
3666 namespace private_algorithm
3667 {
3668 using ETL_OR_STD::swap;
3669
3670 template <typename TIterator, typename TCompare>
3671#if (ETL_USING_CPP20 && ETL_USING_STL) || (ETL_USING_CPP14 && ETL_NOT_USING_STL && !defined(ETL_IN_UNIT_TEST))
3672 constexpr
3673#endif
3674 TIterator
3675 nth_partition(TIterator first, TIterator last, TCompare compare)
3676 {
3677 typedef typename etl::iterator_traits<TIterator>::value_type value_type;
3678
3679 value_type pivot_value = ETL_MOVE(*last);
3680
3681 TIterator i = first;
3682
3683 for (TIterator j = first; j < last; ++j)
3684 {
3685 if (!compare(pivot_value, *j)) // Hack to get '*j <= pivot_value' in
3686 // terms of 'pivot_value < *j'
3687 {
3688 swap(*i, *j);
3689 ++i;
3690 }
3691 }
3692
3693 swap(*i, *last);
3694
3695 return i;
3696 }
3697 } // namespace private_algorithm
3698
3699 //*********************************************************
3702 //*********************************************************
3703#if ETL_USING_CPP11
3704 template <typename TIterator, typename TCompare = etl::less<typename etl::iterator_traits<TIterator>::value_type>>
3705 #if (ETL_USING_CPP20 && ETL_USING_STL) || (ETL_USING_CPP14 && ETL_NOT_USING_STL && !defined(ETL_IN_UNIT_TEST))
3706 constexpr
3707 #endif
3708 typename etl::enable_if< etl::is_random_access_iterator_concept<TIterator>::value, void>::type
3709 nth_element(TIterator first, TIterator nth, TIterator last, TCompare compare = TCompare())
3710 {
3711 if (first == last)
3712 {
3713 return;
3714 }
3715
3716 // 'last' must point to the actual last value.
3717 --last;
3718
3719 while (first <= last)
3720 {
3721 TIterator p = private_algorithm::nth_partition(first, last, compare);
3722
3723 if (p == nth)
3724 {
3725 return;
3726 }
3727 else if (p > nth)
3728 {
3729 last = p - 1;
3730 }
3731 else
3732 {
3733 first = p + 1;
3734 }
3735 }
3736 }
3737
3738#else
3739
3740 //*********************************************************
3741 template <typename TIterator, typename TCompare>
3742 typename etl::enable_if< etl::is_random_access_iterator_concept<TIterator>::value, void>::type nth_element(TIterator first, TIterator nth,
3743 TIterator last, TCompare compare)
3744 {
3745 if (first == last)
3746 {
3747 return;
3748 }
3749
3750 // 'last' must point to the actual last value.
3751 --last;
3752
3753 while (first <= last)
3754 {
3755 TIterator p = private_algorithm::nth_partition(first, last, compare);
3756
3757 if (p == nth)
3758 {
3759 return;
3760 }
3761 else if (p > nth)
3762 {
3763 last = p - 1;
3764 }
3765 else
3766 {
3767 first = p + 1;
3768 }
3769 }
3770 }
3771
3772 //*********************************************************
3773 template <typename TIterator>
3774 typename etl::enable_if< etl::is_random_access_iterator_concept<TIterator>::value, void>::type nth_element(TIterator first, TIterator nth,
3775 TIterator last)
3776 {
3778
3779 nth_element(first, nth, last, compare_t());
3780 }
3781#endif
3782
3783#if ETL_USING_CPP17
3784
3785 namespace ranges
3786 {
3787 template <class I, class F>
3788 struct in_fun_result
3789 {
3790 ETL_NO_UNIQUE_ADDRESS I in;
3791 ETL_NO_UNIQUE_ADDRESS F fun;
3792
3793 template <class I2, class F2>
3794 constexpr operator in_fun_result<I2, F2>() const&
3795 {
3796 return {in, fun};
3797 }
3798
3799 template <class I2, class F2>
3800 constexpr operator in_fun_result<I2, F2>() &&
3801 {
3802 return {etl::move(in), etl::move(fun)};
3803 }
3804 };
3805
3806 template <class I1, class I2>
3807 struct in_in_result
3808 {
3809 ETL_NO_UNIQUE_ADDRESS I1 in1;
3810 ETL_NO_UNIQUE_ADDRESS I2 in2;
3811
3812 template <class II1, class II2>
3813 constexpr operator in_in_result<II1, II2>() const&
3814 {
3815 return {in1, in2};
3816 }
3817
3818 template <class II1, class II2>
3819 constexpr operator in_in_result<II1, II2>() &&
3820 {
3821 return {etl::move(in1), etl::move(in2)};
3822 }
3823 };
3824
3825 template <class I, class O>
3826 struct in_out_result
3827 {
3828 ETL_NO_UNIQUE_ADDRESS I in;
3829 ETL_NO_UNIQUE_ADDRESS O out;
3830
3831 template <class I2, class O2>
3832 constexpr operator in_out_result<I2, O2>() const&
3833 {
3834 return {in, out};
3835 }
3836
3837 template <class I2, class O2>
3838 constexpr operator in_out_result<I2, O2>() &&
3839 {
3840 return {etl::move(in), etl::move(out)};
3841 }
3842 };
3843
3844 template <class I1, class I2, class O>
3845 struct in_in_out_result
3846 {
3847 ETL_NO_UNIQUE_ADDRESS I1 in1;
3848 ETL_NO_UNIQUE_ADDRESS I2 in2;
3849 ETL_NO_UNIQUE_ADDRESS O out;
3850
3851 template <class II1, class II2, class OO>
3852 constexpr operator in_in_out_result<II1, II2, OO>() const&
3853 {
3854 return {in1, in2, out};
3855 }
3856
3857 template <class II1, class II2, class OO>
3858 constexpr operator in_in_out_result<II1, II2, OO>() &&
3859 {
3860 return {etl::move(in1), etl::move(in2), etl::move(out)};
3861 }
3862 };
3863
3864 template <class I, class O1, class O2>
3865 struct in_out_out_result
3866 {
3867 ETL_NO_UNIQUE_ADDRESS I in;
3868 ETL_NO_UNIQUE_ADDRESS O1 out1;
3869 ETL_NO_UNIQUE_ADDRESS O2 out2;
3870
3871 template <class II, class OO1, class OO2>
3872 constexpr operator in_out_out_result<II, OO1, OO2>() const&
3873 {
3874 return {in, out1, out2};
3875 }
3876
3877 template <class II, class OO1, class OO2>
3878 constexpr operator in_out_out_result<II, OO1, OO2>() &&
3879 {
3880 return {etl::move(in), etl::move(out1), etl::move(out2)};
3881 }
3882 };
3883
3884 template <class I>
3885 struct in_found_result
3886 {
3887 ETL_NO_UNIQUE_ADDRESS I in;
3888 bool found;
3889
3890 template <class I2>
3891 constexpr operator in_found_result<I2>() const&
3892 {
3893 return {in, found};
3894 }
3895
3896 template <class I2>
3897 constexpr operator in_found_result<I2>() &&
3898 {
3899 return {etl::move(in), found};
3900 }
3901 };
3902
3903 template <class O, class T>
3904 struct out_value_result
3905 {
3906 ETL_NO_UNIQUE_ADDRESS O out;
3907 ETL_NO_UNIQUE_ADDRESS T value;
3908
3909 template <class O2, class T2>
3910 constexpr operator out_value_result<O2, T2>() const&
3911 {
3912 return {out, value};
3913 }
3914
3915 template <class O2, class T2>
3916 constexpr operator out_value_result<O2, T2>() &&
3917 {
3918 return {etl::move(out), etl::move(value)};
3919 }
3920 };
3921
3922 template <class O, class T>
3923 using iota_result = out_value_result<O, T>;
3924
3925 template <class I, class O>
3926 using copy_result = in_out_result<I, O>;
3927
3928 template <class I, class O>
3929 using copy_n_result = in_out_result<I, O>;
3930
3931 template <class I, class O>
3932 using copy_if_result = in_out_result<I, O>;
3933
3934 template <class I, class O>
3935 using copy_backward_result = in_out_result<I, O>;
3936
3937 template <class I, class O>
3938 using uninitialized_copy_result = in_out_result<I, O>;
3939
3940 template <class I, class O>
3941 using uninitialized_copy_n_result = in_out_result<I, O>;
3942
3943 template <class I, class O>
3944 using uninitialized_move_result = in_out_result<I, O>;
3945
3946 template <class I, class O>
3947 using uninitialized_move_n_result = in_out_result<I, O>;
3948
3949 template <class I, class O>
3950 using move_result = in_out_result<I, O>;
3951
3952 template <class I, class O>
3953 using move_backward_result = in_out_result<I, O>;
3954
3955 template <class I1, class I2>
3956 using mismatch_result = in_in_result<I1, I2>;
3957
3958 template <class I1, class I2>
3959 using swap_ranges_result = in_in_result<I1, I2>;
3960
3961 template <class I, class O>
3962 using unary_transform_result = in_out_result<I, O>;
3963
3964 template <class I1, class I2, class O>
3965 using binary_transform_result = in_in_out_result<I1, I2, O>;
3966
3967 template <class I, class O>
3968 using replace_copy_result = in_out_result<I, O>;
3969
3970 template <class I, class O>
3971 using replace_copy_if_result = in_out_result<I, O>;
3972
3973 template <class I, class O>
3974 using remove_copy_result = in_out_result<I, O>;
3975
3976 template <class I, class O>
3977 using unique_copy_result = in_out_result<I, O>;
3978
3979 template <class I, class O>
3980 using rotate_copy_result = in_out_result<I, O>;
3981
3982 template <class I, class O>
3983 using partial_sort_copy_result = in_out_result<I, O>;
3984
3985 template <class I, class O1, class O2>
3986 using partition_copy_result = in_out_out_result<I, O1, O2>;
3987
3988 template <class I1, class I2, class O>
3989 using set_union_result = in_in_out_result<I1, I2, O>;
3990
3991 template <class I1, class I2, class O>
3992 using set_intersection_result = in_in_out_result<I1, I2, O>;
3993
3994 template <class I, class O>
3995 using set_difference_result = in_out_result<I, O>;
3996
3997 template <class I1, class I2, class O>
3998 using set_symmetric_difference_result = in_in_out_result<I1, I2, O>;
3999
4000 template <class I1, class I2, class O>
4001 using merge_result = in_in_out_result<I1, I2, O>;
4002
4003 template <class I>
4004 using next_permutation_result = in_found_result<I>;
4005
4006 template <class I>
4007 using prev_permutation_result = in_found_result<I>;
4008
4009 template <class T>
4010 struct min_max_result
4011 {
4012 T min;
4013 T max;
4014
4015 template <class T2>
4016 constexpr operator min_max_result<T2>() const&
4017 {
4018 return {min, max};
4019 }
4020
4021 template <class T2>
4022 constexpr operator min_max_result<T2>() &&
4023 {
4024 return {etl::move(min), etl::move(max)};
4025 }
4026 };
4027
4028 template <class T>
4029 using minmax_result = min_max_result<T>;
4030
4031 template <class I>
4032 using minmax_element_result = min_max_result<I>;
4033
4034 template <class I, class F>
4035 using for_each_result = in_fun_result<I, F>;
4036
4037 struct for_each_fn
4038 {
4039 template <class I, class S, class Fun, class Proj = etl::identity, typename = etl::enable_if_t<!etl::is_range_v<I>>>
4040 constexpr ranges::for_each_result<I, Fun> operator()(I first, S last, Fun f, Proj proj = {}) const
4041 {
4042 for (; first != last; ++first)
4043 {
4044 etl::invoke(f, etl::invoke(proj, *first));
4045 }
4046 return {etl::move(first), etl::move(f)};
4047 }
4048
4049 template <class R, class Fun, class Proj = etl::identity, typename = etl::enable_if_t<etl::is_range_v<R>>>
4050 constexpr ranges::for_each_result<ranges::borrowed_iterator_t<R>, Fun> operator()(R&& r, Fun f, Proj proj = {}) const
4051 {
4052 return (*this)(ranges::begin(r), ranges::end(r), etl::move(f), etl::ref(proj));
4053 }
4054 };
4055
4056 inline constexpr for_each_fn for_each;
4057
4058 template <class I, class F>
4059 using for_each_n_result = in_fun_result<I, F>;
4060
4061 struct for_each_n_fn
4062 {
4063 template <class I, class Fun, class Proj = etl::identity, typename = etl::enable_if_t<!etl::is_range_v<I>>>
4064 constexpr for_each_n_result<I, Fun> operator()(I first, etl::iter_difference_t<I> n, Fun fun, Proj proj = Proj{}) const
4065 {
4066 for (; n-- > 0; ++first)
4067 {
4068 etl::invoke(fun, etl::invoke(proj, *first));
4069 }
4070 return {etl::move(first), etl::move(fun)};
4071 }
4072 };
4073
4074 inline constexpr for_each_n_fn for_each_n{};
4075
4076 struct find_fn
4077 {
4078 template <class I, class S, class T, class Proj = etl::identity, typename = etl::enable_if_t<!etl::is_range_v<I>>>
4079 constexpr I operator()(I first, S last, const T& value, Proj proj = {}) const
4080 {
4081 for (; first != last; ++first)
4082 {
4083 if (etl::invoke(proj, *first) == value)
4084 {
4085 return first;
4086 }
4087 }
4088 return first;
4089 }
4090
4091 template <class R, class T, class Proj = etl::identity, typename = etl::enable_if_t<etl::is_range_v<R>>>
4092 constexpr ranges::borrowed_iterator_t<R> operator()(R&& r, const T& value, Proj proj = {}) const
4093 {
4094 return (*this)(ranges::begin(r), ranges::end(r), value, etl::ref(proj));
4095 }
4096 };
4097
4098 inline constexpr find_fn find;
4099
4100 struct find_if_fn
4101 {
4102 template <class I, class S, class Pred, class Proj = etl::identity, typename = etl::enable_if_t<!etl::is_range_v<I>>>
4103 constexpr I operator()(I first, S last, Pred pred, Proj proj = {}) const
4104 {
4105 for (; first != last; ++first)
4106 {
4107 if (etl::invoke(pred, etl::invoke(proj, *first)))
4108 {
4109 return first;
4110 }
4111 }
4112 return first;
4113 }
4114
4115 template <class R, class Pred, class Proj = etl::identity, typename = etl::enable_if_t<etl::is_range_v<R>>>
4116 constexpr ranges::borrowed_iterator_t<R> operator()(R&& r, Pred pred, Proj proj = {}) const
4117 {
4118 return (*this)(ranges::begin(r), ranges::end(r), etl::ref(pred), etl::ref(proj));
4119 }
4120 };
4121
4122 inline constexpr find_if_fn find_if;
4123
4124 struct find_if_not_fn
4125 {
4126 template <class I, class S, class Pred, class Proj = etl::identity, typename = etl::enable_if_t<!etl::is_range_v<I>>>
4127 constexpr I operator()(I first, S last, Pred pred, Proj proj = {}) const
4128 {
4129 for (; first != last; ++first)
4130 {
4131 if (!etl::invoke(pred, etl::invoke(proj, *first)))
4132 {
4133 return first;
4134 }
4135 }
4136 return first;
4137 }
4138
4139 template <class R, class Pred, class Proj = etl::identity, typename = etl::enable_if_t<etl::is_range_v<R>>>
4140 constexpr ranges::borrowed_iterator_t<R> operator()(R&& r, Pred pred, Proj proj = {}) const
4141 {
4142 return (*this)(ranges::begin(r), ranges::end(r), etl::ref(pred), etl::ref(proj));
4143 }
4144 };
4145
4146 inline constexpr find_if_not_fn find_if_not;
4147
4148 struct search_fn
4149 {
4150 template <class I1, class S1, class I2, class S2, class Pred = ranges::equal_to, class Proj1 = etl::identity, class Proj2 = etl::identity,
4151 typename = etl::enable_if_t<!etl::is_range_v<I1>>>
4152 constexpr ranges::subrange<I1> operator()(I1 first1, S1 last1, I2 first2, S2 last2, Pred pred = {}, Proj1 proj1 = {}, Proj2 proj2 = {}) const
4153 {
4154 for (;; ++first1)
4155 {
4156 I1 it1 = first1;
4157 for (I2 it2 = first2;; ++it1, ++it2)
4158 {
4159 if (it2 == last2)
4160 {
4161 return {first1, it1};
4162 }
4163 if (it1 == last1)
4164 {
4165 return {it1, it1};
4166 }
4167 if (!etl::invoke(pred, etl::invoke(proj1, *it1), etl::invoke(proj2, *it2)))
4168 {
4169 break;
4170 }
4171 }
4172 }
4173 }
4174
4175 template <class R1, class R2, class Pred = ranges::equal_to, class Proj1 = etl::identity, class Proj2 = etl::identity,
4176 typename = etl::enable_if_t<etl::is_range_v<R1>>>
4177 constexpr ranges::borrowed_subrange_t<R1> operator()(R1&& r1, R2&& r2, Pred pred = {}, Proj1 proj1 = {}, Proj2 proj2 = {}) const
4178 {
4179 return (*this)(ranges::begin(r1), ranges::end(r1), ranges::begin(r2), ranges::end(r2), etl::move(pred), etl::move(proj1), etl::move(proj2));
4180 }
4181 };
4182
4183 inline constexpr search_fn search{};
4184
4185 struct search_n_fn
4186 {
4187 template <class I, class S, class T = etl::iter_value_t<I>, class Pred = ranges::equal_to, class Proj = etl::identity,
4188 typename = etl::enable_if_t<!etl::is_range_v<I>>>
4189 constexpr ranges::subrange<I> operator()(I first, S last, etl::iter_difference_t<I> count, const T& value, Pred pred = {}, Proj proj = {}) const
4190 {
4191 if (count <= 0)
4192 {
4193 return {first, first};
4194 }
4195
4196 for (; first != last; ++first)
4197 {
4198 if (etl::invoke(pred, etl::invoke(proj, *first), value))
4199 {
4200 I start = first;
4201 etl::iter_difference_t<I> n = 1;
4202
4203 for (;;)
4204 {
4205 if (n >= count)
4206 {
4207 return {start, ++first};
4208 }
4209 ++first;
4210 if (first == last)
4211 {
4212 return {first, first};
4213 }
4214 if (!etl::invoke(pred, etl::invoke(proj, *first), value))
4215 {
4216 break;
4217 }
4218 ++n;
4219 }
4220 }
4221 }
4222 return {first, first};
4223 }
4224
4225 template <class R, class T = etl::ranges::range_value_t<R>, class Pred = ranges::equal_to, class Proj = etl::identity,
4226 typename = etl::enable_if_t<etl::is_range_v<R>>>
4227 constexpr ranges::borrowed_subrange_t<R> operator()(R&& r, ranges::range_difference_t<R> count, const T& value, Pred pred = {},
4228 Proj proj = {}) const
4229 {
4230 return (*this)(ranges::begin(r), ranges::end(r), count, value, etl::move(pred), etl::move(proj));
4231 }
4232 };
4233
4234 inline constexpr search_n_fn search_n{};
4235
4236 struct find_end_fn
4237 {
4238 template <class I1, class S1, class I2, class S2, class Pred = ranges::equal_to, class Proj1 = etl::identity, class Proj2 = etl::identity,
4239 typename = etl::enable_if_t<!etl::is_range_v<I1>>>
4240 constexpr ranges::subrange<I1> operator()(I1 first1, S1 last1, I2 first2, S2 last2, Pred pred = {}, Proj1 proj1 = {}, Proj2 proj2 = {}) const
4241 {
4242 if (first2 == last2)
4243 {
4244 auto last_it = ranges::next(first1, last1);
4245 return {last_it, last_it};
4246 }
4247 auto result = ranges::search(etl::move(first1), last1, first2, last2, pred, proj1, proj2);
4248
4249 if (result.empty())
4250 {
4251 return result;
4252 }
4253
4254 for (;;)
4255 {
4256 auto new_result = ranges::search(etl::next(result.begin()), last1, first2, last2, pred, proj1, proj2);
4257 if (new_result.empty())
4258 {
4259 return result;
4260 }
4261 else
4262 {
4263 result = etl::move(new_result);
4264 }
4265 }
4266 }
4267
4268 template <class R1, class R2, class Pred = ranges::equal_to, class Proj1 = etl::identity, class Proj2 = etl::identity,
4269 typename = etl::enable_if_t<etl::is_range_v<R1>>>
4270 constexpr ranges::borrowed_subrange_t<R1> operator()(R1&& r1, R2&& r2, Pred pred = {}, Proj1 proj1 = {}, Proj2 proj2 = {}) const
4271 {
4272 return (*this)(ranges::begin(r1), ranges::end(r1), ranges::begin(r2), ranges::end(r2), etl::move(pred), etl::move(proj1), etl::move(proj2));
4273 }
4274 };
4275
4276 inline constexpr find_end_fn find_end{};
4277
4278 struct find_first_of_fn
4279 {
4280 template <class I1, class S1, class I2, class S2, class Pred = ranges::equal_to, class Proj1 = etl::identity, class Proj2 = etl::identity,
4281 typename = etl::enable_if_t<!etl::is_range_v<I1>>>
4282 constexpr I1 operator()(I1 first1, S1 last1, I2 first2, S2 last2, Pred pred = {}, Proj1 proj1 = {}, Proj2 proj2 = {}) const
4283 {
4284 for (; first1 != last1; ++first1)
4285 {
4286 for (auto i = first2; i != last2; ++i)
4287 {
4288 if (etl::invoke(pred, etl::invoke(proj1, *first1), etl::invoke(proj2, *i)))
4289 {
4290 return first1;
4291 }
4292 }
4293 }
4294 return first1;
4295 }
4296
4297 template <class R1, class R2, class Pred = ranges::equal_to, class Proj1 = etl::identity, class Proj2 = etl::identity,
4298 typename = etl::enable_if_t<etl::is_range_v<R1>>>
4299 constexpr ranges::borrowed_iterator_t<R1> operator()(R1&& r1, R2&& r2, Pred pred = {}, Proj1 proj1 = {}, Proj2 proj2 = {}) const
4300 {
4301 return (*this)(ranges::begin(r1), ranges::end(r1), ranges::begin(r2), ranges::end(r2), etl::move(pred), etl::move(proj1), etl::move(proj2));
4302 }
4303 };
4304
4305 inline constexpr find_first_of_fn find_first_of{};
4306
4307 struct adjacent_find_fn
4308 {
4309 template <class I, class S, class Proj = etl::identity, class Pred = ranges::equal_to, typename = etl::enable_if_t<!etl::is_range_v<I>>>
4310 constexpr I operator()(I first, S last, Pred pred = {}, Proj proj = {}) const
4311 {
4312 if (first == last)
4313 {
4314 return first;
4315 }
4316 auto next_it = ranges::next(first);
4317 for (; next_it != last; ++next_it, ++first)
4318 {
4319 if (etl::invoke(pred, etl::invoke(proj, *first), etl::invoke(proj, *next_it)))
4320 {
4321 return first;
4322 }
4323 }
4324 return next_it;
4325 }
4326
4327 template <class R, class Proj = etl::identity, class Pred = ranges::equal_to, typename = etl::enable_if_t<etl::is_range_v<R>>>
4328 constexpr ranges::borrowed_iterator_t<R> operator()(R&& r, Pred pred = {}, Proj proj = {}) const
4329 {
4330 return (*this)(ranges::begin(r), ranges::end(r), etl::ref(pred), etl::ref(proj));
4331 }
4332 };
4333
4334 inline constexpr adjacent_find_fn adjacent_find;
4335
4336 struct count_fn
4337 {
4338 template <class I, class S, class Proj = etl::identity, class T = etl::projected_value_t<I, Proj>,
4339 typename = etl::enable_if_t<!etl::is_range_v<I>>>
4340 constexpr etl::iter_difference_t<I> operator()(I first, S last, const T& value, Proj proj = {}) const
4341 {
4342 etl::iter_difference_t<I> counter = 0;
4343 for (; first != last; ++first)
4344 {
4345 if (etl::invoke(proj, *first) == value)
4346 {
4347 ++counter;
4348 }
4349 }
4350 return counter;
4351 }
4352
4353 template <class R, class Proj = etl::identity, class T = etl::projected_value_t<ranges::iterator_t<R>, Proj>,
4354 typename = etl::enable_if_t<etl::is_range_v<R>>>
4355 constexpr ranges::range_difference_t<R> operator()(R&& r, const T& value, Proj proj = {}) const
4356 {
4357 return (*this)(ranges::begin(r), ranges::end(r), value, etl::ref(proj));
4358 }
4359 };
4360
4361 inline constexpr count_fn count;
4362
4363 struct count_if_fn
4364 {
4365 template <class I, class S, class Pred, class Proj = etl::identity, typename = etl::enable_if_t<!etl::is_range_v<I>>>
4366 constexpr etl::iter_difference_t<I> operator()(I first, S last, Pred pred, Proj proj = {}) const
4367 {
4368 etl::iter_difference_t<I> counter = 0;
4369 for (; first != last; ++first)
4370 {
4371 if (etl::invoke(pred, etl::invoke(proj, *first)))
4372 {
4373 ++counter;
4374 }
4375 }
4376 return counter;
4377 }
4378
4379 template <class R, class Proj = etl::identity, class Pred, typename = etl::enable_if_t<etl::is_range_v<R>>>
4380 constexpr ranges::range_difference_t<R> operator()(R&& r, Pred pred, Proj proj = {}) const
4381 {
4382 return (*this)(ranges::begin(r), ranges::end(r), etl::ref(pred), etl::ref(proj));
4383 }
4384 };
4385
4386 inline constexpr count_if_fn count_if;
4387
4388 struct all_of_fn
4389 {
4390 template <class I, class S, class Pred, class Proj = etl::identity, typename = etl::enable_if_t<!etl::is_range_v<I>>>
4391 constexpr bool operator()(I first, S last, Pred pred, Proj proj = {}) const
4392 {
4393 return ranges::find_if_not(first, last, etl::ref(pred), etl::ref(proj)) == last;
4394 }
4395
4396 template <class R, class Pred, class Proj = etl::identity, typename = etl::enable_if_t<etl::is_range_v<R>>>
4397 constexpr bool operator()(R&& r, Pred pred, Proj proj = {}) const
4398 {
4399 return operator()(ranges::begin(r), ranges::end(r), etl::ref(pred), etl::ref(proj));
4400 }
4401 };
4402
4403 inline constexpr all_of_fn all_of;
4404
4405 struct any_of_fn
4406 {
4407 template <class I, class S, class Pred, class Proj = etl::identity, typename = etl::enable_if_t<!etl::is_range_v<I>>>
4408 constexpr bool operator()(I first, S last, Pred pred, Proj proj = {}) const
4409 {
4410 return ranges::find_if(first, last, etl::ref(pred), etl::ref(proj)) != last;
4411 }
4412
4413 template <class R, class Pred, class Proj = etl::identity, typename = etl::enable_if_t<etl::is_range_v<R>>>
4414 constexpr bool operator()(R&& r, Pred pred, Proj proj = {}) const
4415 {
4416 return operator()(ranges::begin(r), ranges::end(r), etl::ref(pred), etl::ref(proj));
4417 }
4418 };
4419
4420 inline constexpr any_of_fn any_of;
4421
4422 struct none_of_fn
4423 {
4424 template <class I, class S, class Pred, class Proj = etl::identity, typename = etl::enable_if_t<!etl::is_range_v<I>>>
4425 constexpr bool operator()(I first, S last, Pred pred, Proj proj = {}) const
4426 {
4427 return ranges::find_if(first, last, etl::ref(pred), etl::ref(proj)) == last;
4428 }
4429
4430 template <class R, class Pred, class Proj = etl::identity, typename = etl::enable_if_t<etl::is_range_v<R>>>
4431 constexpr bool operator()(R&& r, Pred pred, Proj proj = {}) const
4432 {
4433 return operator()(ranges::begin(r), ranges::end(r), etl::ref(pred), etl::ref(proj));
4434 }
4435 };
4436
4437 inline constexpr none_of_fn none_of;
4438
4439 struct mismatch_fn
4440 {
4441 template <class I1, class S1, class I2, class S2, class Pred = ranges::equal_to, class Proj1 = etl::identity, class Proj2 = etl::identity,
4442 typename = etl::enable_if_t<!etl::is_range_v<I1>>>
4443 constexpr ranges::mismatch_result<I1, I2> operator()(I1 first1, S1 last1, I2 first2, S2 last2, Pred pred = {}, Proj1 proj1 = {},
4444 Proj2 proj2 = {}) const
4445 {
4446 for (; first1 != last1 && first2 != last2; ++first1, ++first2)
4447 {
4448 if (!etl::invoke(pred, etl::invoke(proj1, *first1), etl::invoke(proj2, *first2)))
4449 {
4450 break;
4451 }
4452 }
4453 return {etl::move(first1), etl::move(first2)};
4454 }
4455
4456 template <class R1, class R2, class Pred = ranges::equal_to, class Proj1 = etl::identity, class Proj2 = etl::identity,
4457 typename = etl::enable_if_t<etl::is_range_v<R1>>>
4458 constexpr ranges::mismatch_result<ranges::borrowed_iterator_t<R1>, ranges::borrowed_iterator_t<R2>>
4459 operator()(R1&& r1, R2&& r2, Pred pred = {}, Proj1 proj1 = {}, Proj2 proj2 = {}) const
4460 {
4461 return (*this)(ranges::begin(r1), ranges::end(r1), ranges::begin(r2), ranges::end(r2), etl::move(pred), etl::move(proj1), etl::move(proj2));
4462 }
4463 };
4464
4465 inline constexpr mismatch_fn mismatch{};
4466
4467 struct equal_fn
4468 {
4469 template <class I1, class S1, class I2, class S2, class Pred = ranges::equal_to, class Proj1 = etl::identity, class Proj2 = etl::identity,
4470 typename = etl::enable_if_t<!etl::is_range_v<I1>>>
4471 constexpr bool operator()(I1 first1, S1 last1, I2 first2, S2 last2, Pred pred = {}, Proj1 proj1 = {}, Proj2 proj2 = {}) const
4472 {
4473 for (; first1 != last1 && first2 != last2; ++first1, ++first2)
4474 {
4475 if (!etl::invoke(pred, etl::invoke(proj1, *first1), etl::invoke(proj2, *first2)))
4476 {
4477 return false;
4478 }
4479 }
4480 return first1 == last1 && first2 == last2;
4481 }
4482
4483 template <class R1, class R2, class Pred = ranges::equal_to, class Proj1 = etl::identity, class Proj2 = etl::identity,
4484 typename = etl::enable_if_t<etl::is_range_v<R1>>>
4485 constexpr bool operator()(R1&& r1, R2&& r2, Pred pred = {}, Proj1 proj1 = {}, Proj2 proj2 = {}) const
4486 {
4487 return (*this)(ranges::begin(r1), ranges::end(r1), ranges::begin(r2), ranges::end(r2), etl::move(pred), etl::move(proj1), etl::move(proj2));
4488 }
4489 };
4490
4491 inline constexpr equal_fn equal{};
4492
4493 struct is_permutation_fn
4494 {
4495 template <class I1, class S1, class I2, class S2, class Pred = ranges::equal_to, class Proj1 = etl::identity, class Proj2 = etl::identity,
4496 typename = etl::enable_if_t<!etl::is_range_v<I1>>>
4497 constexpr bool operator()(I1 first1, S1 last1, I2 first2, S2 last2, Pred pred = {}, Proj1 proj1 = {}, Proj2 proj2 = {}) const
4498 {
4499 // Skip common prefix
4500 for (; first1 != last1 && first2 != last2; ++first1, ++first2)
4501 {
4502 if (!etl::invoke(pred, etl::invoke(proj1, *first1), etl::invoke(proj2, *first2)))
4503 {
4504 break;
4505 }
4506 }
4507
4508 if (first1 == last1)
4509 {
4510 return first2 == last2;
4511 }
4512
4513 if (first2 == last2)
4514 {
4515 return false;
4516 }
4517
4518 // Check remaining elements
4519 for (I1 i = first1; i != last1; ++i)
4520 {
4521 // Check if we already counted this element
4522 bool already_seen = false;
4523 for (I1 j = first1; j != i; ++j)
4524 {
4525 if (etl::invoke(pred, etl::invoke(proj1, *i), etl::invoke(proj1, *j)))
4526 {
4527 already_seen = true;
4528 break;
4529 }
4530 }
4531
4532 if (already_seen)
4533 {
4534 continue;
4535 }
4536
4537 // Count occurrences in range2
4538 auto count2 = etl::iter_difference_t<I2>(0);
4539 for (I2 k = first2; k != last2; ++k)
4540 {
4541 if (etl::invoke(pred, etl::invoke(proj1, *i), etl::invoke(proj2, *k)))
4542 {
4543 ++count2;
4544 }
4545 }
4546
4547 if (count2 == 0)
4548 {
4549 return false;
4550 }
4551
4552 // Count occurrences in range1
4553 auto count1 = etl::iter_difference_t<I1>(0);
4554 for (I1 k = i; k != last1; ++k)
4555 {
4556 if (etl::invoke(pred, etl::invoke(proj1, *i), etl::invoke(proj1, *k)))
4557 {
4558 ++count1;
4559 }
4560 }
4561
4562 if (count1 != count2)
4563 {
4564 return false;
4565 }
4566 }
4567
4568 return true;
4569 }
4570
4571 template <class R1, class R2, class Pred = ranges::equal_to, class Proj1 = etl::identity, class Proj2 = etl::identity,
4572 typename = etl::enable_if_t<etl::is_range_v<R1>>>
4573 constexpr bool operator()(R1&& r1, R2&& r2, Pred pred = {}, Proj1 proj1 = {}, Proj2 proj2 = {}) const
4574 {
4575 return (*this)(ranges::begin(r1), ranges::end(r1), ranges::begin(r2), ranges::end(r2), etl::move(pred), etl::move(proj1), etl::move(proj2));
4576 }
4577 };
4578
4579 inline constexpr is_permutation_fn is_permutation{};
4580
4581 struct starts_with_fn
4582 {
4583 template <class I1, class S1, class I2, class S2, class Pred = ranges::equal_to, class Proj1 = etl::identity, class Proj2 = etl::identity,
4584 typename = etl::enable_if_t<!etl::is_range_v<I1>>>
4585 constexpr bool operator()(I1 first1, S1 last1, I2 first2, S2 last2, Pred pred = {}, Proj1 proj1 = {}, Proj2 proj2 = {}) const
4586 {
4587 for (; first2 != last2; ++first1, ++first2)
4588 {
4589 if (first1 == last1 || !etl::invoke(pred, etl::invoke(proj1, *first1), etl::invoke(proj2, *first2)))
4590 {
4591 return false;
4592 }
4593 }
4594 return true;
4595 }
4596
4597 template <class R1, class R2, class Pred = ranges::equal_to, class Proj1 = etl::identity, class Proj2 = etl::identity,
4598 typename = etl::enable_if_t<etl::is_range_v<R1>>>
4599 constexpr bool operator()(R1&& r1, R2&& r2, Pred pred = {}, Proj1 proj1 = {}, Proj2 proj2 = {}) const
4600 {
4601 return (*this)(ranges::begin(r1), ranges::end(r1), ranges::begin(r2), ranges::end(r2), etl::move(pred), etl::move(proj1), etl::move(proj2));
4602 }
4603 };
4604
4605 inline constexpr starts_with_fn starts_with{};
4606
4607 struct ends_with_fn
4608 {
4609 template <class I1, class S1, class I2, class S2, class Pred = ranges::equal_to, class Proj1 = etl::identity, class Proj2 = etl::identity,
4610 typename = etl::enable_if_t<!etl::is_range_v<I1>>>
4611 constexpr bool operator()(I1 first1, S1 last1, I2 first2, S2 last2, Pred pred = {}, Proj1 proj1 = {}, Proj2 proj2 = {}) const
4612 {
4613 auto n1 = etl::distance(first1, last1);
4614 auto n2 = etl::distance(first2, last2);
4615
4616 if (n2 > n1)
4617 {
4618 return false;
4619 }
4620
4621 ranges::advance(first1, n1 - n2);
4622
4623 return starts_with(first1, last1, first2, last2, etl::move(pred), etl::move(proj1), etl::move(proj2));
4624 }
4625
4626 template <class R1, class R2, class Pred = ranges::equal_to, class Proj1 = etl::identity, class Proj2 = etl::identity,
4627 typename = etl::enable_if_t<etl::is_range_v<R1>>>
4628 constexpr bool operator()(R1&& r1, R2&& r2, Pred pred = {}, Proj1 proj1 = {}, Proj2 proj2 = {}) const
4629 {
4630 return (*this)(ranges::begin(r1), ranges::end(r1), ranges::begin(r2), ranges::end(r2), etl::move(pred), etl::move(proj1), etl::move(proj2));
4631 }
4632 };
4633
4634 inline constexpr ends_with_fn ends_with{};
4635
4636 struct lexicographical_compare_fn
4637 {
4638 template <class I1, class S1, class I2, class S2, class Comp = ranges::less, class Proj1 = etl::identity, class Proj2 = etl::identity,
4639 typename = etl::enable_if_t<!etl::is_range_v<I1>>>
4640 constexpr bool operator()(I1 first1, S1 last1, I2 first2, S2 last2, Comp comp = {}, Proj1 proj1 = {}, Proj2 proj2 = {}) const
4641 {
4642 for (; first1 != last1 && first2 != last2; ++first1, ++first2)
4643 {
4644 if (etl::invoke(comp, etl::invoke(proj1, *first1), etl::invoke(proj2, *first2)))
4645 {
4646 return true;
4647 }
4648
4649 if (etl::invoke(comp, etl::invoke(proj2, *first2), etl::invoke(proj1, *first1)))
4650 {
4651 return false;
4652 }
4653 }
4654 return first1 == last1 && first2 != last2;
4655 }
4656
4657 template <class R1, class R2, class Comp = ranges::less, class Proj1 = etl::identity, class Proj2 = etl::identity,
4658 typename = etl::enable_if_t<etl::is_range_v<R1>>>
4659 constexpr bool operator()(R1&& r1, R2&& r2, Comp comp = {}, Proj1 proj1 = {}, Proj2 proj2 = {}) const
4660 {
4661 return (*this)(ranges::begin(r1), ranges::end(r1), ranges::begin(r2), ranges::end(r2), etl::move(comp), etl::move(proj1), etl::move(proj2));
4662 }
4663 };
4664
4665 inline constexpr lexicographical_compare_fn lexicographical_compare{};
4666
4667 template <class I, class T>
4668 struct in_value_result
4669 {
4670 ETL_NO_UNIQUE_ADDRESS I in;
4671 ETL_NO_UNIQUE_ADDRESS T value;
4672
4673 template <class I2, class T2>
4674 constexpr operator in_value_result<I2, T2>() const&
4675 {
4676 return {in, value};
4677 }
4678
4679 template <class I2, class T2>
4680 constexpr operator in_value_result<I2, T2>() &&
4681 {
4682 return {etl::move(in), etl::move(value)};
4683 }
4684 };
4685
4686 template <class I, class T>
4687 using fold_left_with_iter_result = in_value_result<I, T>;
4688
4689 struct fold_left_fn
4690 {
4691 template <class I, class S, class T, class F, typename = etl::enable_if_t<!etl::is_range_v<I>>>
4692 constexpr auto operator()(I first, S last, T init, F f) const -> etl::decay_t<etl::invoke_result_t<F&, T, etl::iter_reference_t<I>>>
4693 {
4694 using U = etl::decay_t<etl::invoke_result_t<F&, T, etl::iter_reference_t<I>>>;
4695 U accum = etl::move(init);
4696 for (; first != last; ++first)
4697 {
4698 accum = etl::invoke(f, etl::move(accum), *first);
4699 }
4700 return accum;
4701 }
4702
4703 template <class R, class T, class F, typename = etl::enable_if_t<etl::is_range_v<R>>>
4704 constexpr auto operator()(R&& r, T init, F f) const -> etl::decay_t< etl::invoke_result_t<F&, T, etl::ranges::range_reference_t<R>>>
4705 {
4706 return (*this)(ranges::begin(r), ranges::end(r), etl::move(init), etl::move(f));
4707 }
4708 };
4709
4710 inline constexpr fold_left_fn fold_left{};
4711
4712 struct fold_left_with_iter_fn
4713 {
4714 template <class I, class S, class T, class F, typename = etl::enable_if_t<!etl::is_range_v<I>>>
4715 constexpr auto operator()(I first, S last, T init,
4716 F f) const -> fold_left_with_iter_result< I, etl::decay_t<etl::invoke_result_t<F&, T, etl::iter_reference_t<I>>>>
4717 {
4718 using U = etl::decay_t<etl::invoke_result_t<F&, T, etl::iter_reference_t<I>>>;
4719 U accum = etl::move(init);
4720 for (; first != last; ++first)
4721 {
4722 accum = etl::invoke(f, etl::move(accum), *first);
4723 }
4724 return {etl::move(first), etl::move(accum)};
4725 }
4726
4727 template <class R, class T, class F, typename = etl::enable_if_t<etl::is_range_v<R>>>
4728 constexpr auto operator()(R&& r, T init, F f) const
4729 -> fold_left_with_iter_result< ranges::borrowed_iterator_t<R>, etl::decay_t< etl::invoke_result_t<F&, T, etl::ranges::range_reference_t<R>>>>
4730 {
4731 return (*this)(ranges::begin(r), ranges::end(r), etl::move(init), etl::move(f));
4732 }
4733 };
4734
4735 inline constexpr fold_left_with_iter_fn fold_left_with_iter{};
4736
4737 struct fold_left_first_fn
4738 {
4739 template <class I, class S, class F, typename = etl::enable_if_t<!etl::is_range_v<I>>>
4740 constexpr auto operator()(I first, S last, F f) const -> etl::decay_t<etl::invoke_result_t<F&, etl::iter_value_t<I>, etl::iter_reference_t<I>>>
4741 {
4742 using U = etl::decay_t<etl::invoke_result_t<F&, etl::iter_value_t<I>, etl::iter_reference_t<I>>>;
4743 if (first == last)
4744 {
4745 return U{};
4746 }
4747 U accum = *first;
4748 ++first;
4749 for (; first != last; ++first)
4750 {
4751 accum = etl::invoke(f, etl::move(accum), *first);
4752 }
4753 return accum;
4754 }
4755
4756 template <class R, class F, typename = etl::enable_if_t<etl::is_range_v<R>>>
4757 constexpr auto operator()(R&& r,
4758 F f) const -> etl::decay_t<etl::invoke_result_t<F&, etl::ranges::range_value_t<R>, etl::ranges::range_reference_t<R>>>
4759 {
4760 return (*this)(ranges::begin(r), ranges::end(r), etl::move(f));
4761 }
4762 };
4763
4764 inline constexpr fold_left_first_fn fold_left_first{};
4765
4766 struct fold_left_first_with_iter_fn
4767 {
4768 template <class I, class S, class F, typename = etl::enable_if_t<!etl::is_range_v<I>>>
4769 constexpr auto operator()(I first, S last, F f) const
4770 -> fold_left_with_iter_result< I, etl::decay_t<etl::invoke_result_t<F&, etl::iter_value_t<I>, etl::iter_reference_t<I>>>>
4771 {
4772 using U = etl::decay_t<etl::invoke_result_t<F&, etl::iter_value_t<I>, etl::iter_reference_t<I>>>;
4773 if (first == last)
4774 {
4775 return {etl::move(first), U{}};
4776 }
4777 U accum = *first;
4778 ++first;
4779 for (; first != last; ++first)
4780 {
4781 accum = etl::invoke(f, etl::move(accum), *first);
4782 }
4783 return {etl::move(first), etl::move(accum)};
4784 }
4785
4786 template <class R, class F, typename = etl::enable_if_t<etl::is_range_v<R>>>
4787 constexpr auto operator()(R&& r, F f) const
4788 -> fold_left_with_iter_result< ranges::borrowed_iterator_t<R>,
4789 etl::decay_t<etl::invoke_result_t<F&, etl::ranges::range_value_t<R>, etl::ranges::range_reference_t<R>>>>
4790 {
4791 return (*this)(ranges::begin(r), ranges::end(r), etl::move(f));
4792 }
4793 };
4794
4795 inline constexpr fold_left_first_with_iter_fn fold_left_first_with_iter{};
4796
4797 struct fold_right_fn
4798 {
4799 template <class I, class S, class T, class F, typename = etl::enable_if_t<!etl::is_range_v<I>>>
4800 constexpr auto operator()(I first, S last, T init, F f) const -> etl::decay_t<etl::invoke_result_t<F&, etl::iter_reference_t<I>, T>>
4801 {
4802 using U = etl::decay_t<etl::invoke_result_t<F&, etl::iter_reference_t<I>, T>>;
4803 U accum = etl::move(init);
4804 I tail = ranges::next(first, last);
4805 while (tail != first)
4806 {
4807 tail = ranges::prev(tail);
4808 accum = etl::invoke(f, *tail, etl::move(accum));
4809 }
4810 return accum;
4811 }
4812
4813 template <class R, class T, class F, typename = etl::enable_if_t<etl::is_range_v<R>>>
4814 constexpr auto operator()(R&& r, T init, F f) const -> etl::decay_t< etl::invoke_result_t<F&, etl::ranges::range_reference_t<R>, T>>
4815 {
4816 return (*this)(ranges::begin(r), ranges::end(r), etl::move(init), etl::move(f));
4817 }
4818 };
4819
4820 inline constexpr fold_right_fn fold_right{};
4821
4822 struct fold_right_last_fn
4823 {
4824 template <class I, class S, class F, typename = etl::enable_if_t<!etl::is_range_v<I>>>
4825 constexpr auto operator()(I first, S last, F f) const -> etl::decay_t<etl::invoke_result_t<F&, etl::iter_reference_t<I>, etl::iter_value_t<I>>>
4826 {
4827 using U = etl::decay_t<etl::invoke_result_t<F&, etl::iter_reference_t<I>, etl::iter_value_t<I>>>;
4828 I tail = ranges::next(first, last);
4829 if (tail == first)
4830 {
4831 return U{};
4832 }
4833 tail = ranges::prev(tail);
4834 U accum = *tail;
4835 while (tail != first)
4836 {
4837 tail = ranges::prev(tail);
4838 accum = etl::invoke(f, *tail, etl::move(accum));
4839 }
4840 return accum;
4841 }
4842
4843 template <class R, class F, typename = etl::enable_if_t<etl::is_range_v<R>>>
4844 constexpr auto
4845 operator()(R&& r, F f) const -> etl::decay_t<etl::invoke_result_t< F&, etl::ranges::range_reference_t<R>, etl::ranges::range_value_t<R>>>
4846 {
4847 return (*this)(ranges::begin(r), ranges::end(r), etl::move(f));
4848 }
4849 };
4850
4851 inline constexpr fold_right_last_fn fold_right_last{};
4852
4853 struct copy_fn
4854 {
4855 template <class I, class S, class O, typename = etl::enable_if_t<!etl::is_range_v<I>>>
4856 constexpr ranges::copy_result<I, O> operator()(I first, S last, O result) const
4857 {
4858 for (; first != last; ++first, ++result)
4859 {
4860 *result = *first;
4861 }
4862 return {etl::move(first), etl::move(result)};
4863 }
4864
4865 template <class R, class O, typename = etl::enable_if_t<etl::is_range_v<R>>>
4866 constexpr ranges::copy_result<ranges::borrowed_iterator_t<R>, O> operator()(R&& r, O result) const
4867 {
4868 return (*this)(ranges::begin(r), ranges::end(r), etl::move(result));
4869 }
4870 };
4871
4872 inline constexpr copy_fn copy{};
4873
4874 struct copy_n_fn
4875 {
4876 template <class I, class O>
4877 constexpr ranges::copy_n_result<I, O> operator()(I first, etl::iter_difference_t<I> n, O result) const
4878 {
4879 for (etl::iter_difference_t<I> i = 0; i < n; ++i, ++first, ++result)
4880 {
4881 *result = *first;
4882 }
4883 return {etl::move(first), etl::move(result)};
4884 }
4885 };
4886
4887 inline constexpr copy_n_fn copy_n{};
4888
4889 struct copy_if_fn
4890 {
4891 template <class I, class S, class O, class Pred, class Proj = etl::identity, typename = etl::enable_if_t<!etl::is_range_v<I>>>
4892 constexpr ranges::copy_if_result<I, O> operator()(I first, S last, O result, Pred pred, Proj proj = {}) const
4893 {
4894 for (; first != last; ++first)
4895 {
4896 if (etl::invoke(pred, etl::invoke(proj, *first)))
4897 {
4898 *result = *first;
4899 ++result;
4900 }
4901 }
4902 return {etl::move(first), etl::move(result)};
4903 }
4904
4905 template <class R, class O, class Pred, class Proj = etl::identity, typename = etl::enable_if_t<etl::is_range_v<R>>>
4906 constexpr ranges::copy_if_result<ranges::borrowed_iterator_t<R>, O> operator()(R&& r, O result, Pred pred, Proj proj = {}) const
4907 {
4908 return (*this)(ranges::begin(r), ranges::end(r), etl::move(result), etl::ref(pred), etl::ref(proj));
4909 }
4910 };
4911
4912 inline constexpr copy_if_fn copy_if{};
4913
4914 struct copy_backward_fn
4915 {
4916 template <class I1, class S1, class I2, typename = etl::enable_if_t<!etl::is_range_v<I1>>>
4917 constexpr ranges::copy_backward_result<I1, I2> operator()(I1 first, S1 last, I2 result) const
4918 {
4919 I1 last_it = ranges::next(first, last);
4920 I1 tail = last_it;
4921 while (first != tail)
4922 {
4923 *(--result) = *(--tail);
4924 }
4925 return {etl::move(last_it), etl::move(result)};
4926 }
4927
4928 template <class R, class I, typename = etl::enable_if_t<etl::is_range_v<R>>>
4929 constexpr ranges::copy_backward_result<ranges::borrowed_iterator_t<R>, I> operator()(R&& r, I result) const
4930 {
4931 return (*this)(ranges::begin(r), ranges::end(r), etl::move(result));
4932 }
4933 };
4934
4935 inline constexpr copy_backward_fn copy_backward{};
4936
4937 struct move_fn
4938 {
4939 template <class I, class S, class O, typename = etl::enable_if_t<!etl::is_range_v<I>>>
4940 constexpr ranges::move_result<I, O> operator()(I first, S last, O result) const
4941 {
4942 for (; first != last; ++first, ++result)
4943 {
4944 *result = etl::move(*first);
4945 }
4946 return {etl::move(first), etl::move(result)};
4947 }
4948
4949 template <class R, class O, typename = etl::enable_if_t<etl::is_range_v<R>>>
4950 constexpr ranges::move_result<ranges::borrowed_iterator_t<R>, O> operator()(R&& r, O result) const
4951 {
4952 return (*this)(ranges::begin(r), ranges::end(r), etl::move(result));
4953 }
4954 };
4955
4956 inline constexpr move_fn move{};
4957
4958 struct move_backward_fn
4959 {
4960 template <class I1, class S1, class I2, typename = etl::enable_if_t<!etl::is_range_v<I1>>>
4961 constexpr ranges::move_backward_result<I1, I2> operator()(I1 first, S1 last, I2 result) const
4962 {
4963 I1 last_it = ranges::next(first, last);
4964 I1 tail = last_it;
4965 while (first != tail)
4966 {
4967 *(--result) = etl::move(*(--tail));
4968 }
4969 return {etl::move(last_it), etl::move(result)};
4970 }
4971
4972 template <class R, class I, typename = etl::enable_if_t<etl::is_range_v<R>>>
4973 constexpr ranges::move_backward_result<ranges::borrowed_iterator_t<R>, I> operator()(R&& r, I result) const
4974 {
4975 return (*this)(ranges::begin(r), ranges::end(r), etl::move(result));
4976 }
4977 };
4978
4979 inline constexpr move_backward_fn move_backward{};
4980
4981 struct swap_ranges_fn
4982 {
4983 template <class I1, class S1, class I2, class S2, typename = etl::enable_if_t<!etl::is_range_v<I1>>>
4984 constexpr ranges::swap_ranges_result<I1, I2> operator()(I1 first1, S1 last1, I2 first2, S2 last2) const
4985 {
4986 for (; first1 != last1 && first2 != last2; ++first1, ++first2)
4987 {
4988 etl::iter_swap(first1, first2);
4989 }
4990 return {etl::move(first1), etl::move(first2)};
4991 }
4992
4993 template <class R1, class R2, typename = etl::enable_if_t<etl::is_range_v<R1>>>
4994 constexpr ranges::swap_ranges_result<ranges::borrowed_iterator_t<R1>, ranges::borrowed_iterator_t<R2>> operator()(R1&& r1, R2&& r2) const
4995 {
4996 return (*this)(ranges::begin(r1), ranges::end(r1), ranges::begin(r2), ranges::end(r2));
4997 }
4998 };
4999
5000 inline constexpr swap_ranges_fn swap_ranges{};
5001
5002 struct replace_fn
5003 {
5004 template <class I, class S, class T1, class T2, class Proj = etl::identity, typename = etl::enable_if_t<!etl::is_range_v<I>>>
5005 constexpr I operator()(I first, S last, const T1& old_value, const T2& new_value, Proj proj = {}) const
5006 {
5007 for (; first != last; ++first)
5008 {
5009 if (etl::invoke(proj, *first) == old_value)
5010 {
5011 *first = new_value;
5012 }
5013 }
5014 return first;
5015 }
5016
5017 template <class R, class T1, class T2, class Proj = etl::identity, typename = etl::enable_if_t<etl::is_range_v<R>>>
5018 constexpr ranges::borrowed_iterator_t<R> operator()(R&& r, const T1& old_value, const T2& new_value, Proj proj = {}) const
5019 {
5020 return (*this)(ranges::begin(r), ranges::end(r), old_value, new_value, etl::ref(proj));
5021 }
5022 };
5023
5024 inline constexpr replace_fn replace{};
5025
5026 struct replace_if_fn
5027 {
5028 template <class I, class S, class Pred, class T, class Proj = etl::identity, typename = etl::enable_if_t<!etl::is_range_v<I>>>
5029 constexpr I operator()(I first, S last, Pred pred, const T& new_value, Proj proj = {}) const
5030 {
5031 for (; first != last; ++first)
5032 {
5033 if (etl::invoke(pred, etl::invoke(proj, *first)))
5034 {
5035 *first = new_value;
5036 }
5037 }
5038 return first;
5039 }
5040
5041 template <class R, class Pred, class T, class Proj = etl::identity, typename = etl::enable_if_t<etl::is_range_v<R>>>
5042 constexpr ranges::borrowed_iterator_t<R> operator()(R&& r, Pred pred, const T& new_value, Proj proj = {}) const
5043 {
5044 return (*this)(ranges::begin(r), ranges::end(r), etl::ref(pred), new_value, etl::ref(proj));
5045 }
5046 };
5047
5048 inline constexpr replace_if_fn replace_if{};
5049
5050 struct replace_copy_fn
5051 {
5052 template <class I, class S, class O, class T1, class T2, class Proj = etl::identity, typename = etl::enable_if_t<!etl::is_range_v<I>>>
5053 constexpr ranges::replace_copy_result<I, O> operator()(I first, S last, O result, const T1& old_value, const T2& new_value,
5054 Proj proj = {}) const
5055 {
5056 for (; first != last; ++first, ++result)
5057 {
5058 if (etl::invoke(proj, *first) == old_value)
5059 {
5060 *result = new_value;
5061 }
5062 else
5063 {
5064 *result = *first;
5065 }
5066 }
5067 return {etl::move(first), etl::move(result)};
5068 }
5069
5070 template <class R, class O, class T1, class T2, class Proj = etl::identity, typename = etl::enable_if_t<etl::is_range_v<R>>>
5071 constexpr ranges::replace_copy_result<ranges::borrowed_iterator_t<R>, O> operator()(R&& r, O result, const T1& old_value, const T2& new_value,
5072 Proj proj = {}) const
5073 {
5074 return (*this)(ranges::begin(r), ranges::end(r), etl::move(result), old_value, new_value, etl::ref(proj));
5075 }
5076 };
5077
5078 inline constexpr replace_copy_fn replace_copy{};
5079
5080 struct replace_copy_if_fn
5081 {
5082 template <class I, class S, class O, class Pred, class T, class Proj = etl::identity, typename = etl::enable_if_t<!etl::is_range_v<I>>>
5083 constexpr ranges::replace_copy_if_result<I, O> operator()(I first, S last, O result, Pred pred, const T& new_value, Proj proj = {}) const
5084 {
5085 for (; first != last; ++first, ++result)
5086 {
5087 if (etl::invoke(pred, etl::invoke(proj, *first)))
5088 {
5089 *result = new_value;
5090 }
5091 else
5092 {
5093 *result = *first;
5094 }
5095 }
5096 return {etl::move(first), etl::move(result)};
5097 }
5098
5099 template <class R, class O, class Pred, class T, class Proj = etl::identity, typename = etl::enable_if_t<etl::is_range_v<R>>>
5100 constexpr ranges::replace_copy_if_result<ranges::borrowed_iterator_t<R>, O> operator()(R&& r, O result, Pred pred, const T& new_value,
5101 Proj proj = {}) const
5102 {
5103 return (*this)(ranges::begin(r), ranges::end(r), etl::move(result), etl::ref(pred), new_value, etl::ref(proj));
5104 }
5105 };
5106
5107 inline constexpr replace_copy_if_fn replace_copy_if{};
5108
5109 struct remove_fn
5110 {
5111 template <class I, class S, class T, class Proj = etl::identity, typename = etl::enable_if_t<!etl::is_range_v<I>>>
5112 constexpr ranges::subrange<I> operator()(I first, S last, const T& value, Proj proj = {}) const
5113 {
5114 first = ranges::find(first, last, value, etl::ref(proj));
5115
5116 if (first != last)
5117 {
5118 I result = first;
5119
5120 for (I it = result; ++it != last;)
5121 {
5122 if (!(etl::invoke(proj, *it) == value))
5123 {
5124 *result = etl::move(*it);
5125 ++result;
5126 }
5127 }
5128
5129 return {result, last};
5130 }
5131
5132 return {first, last};
5133 }
5134
5135 template <class R, class T, class Proj = etl::identity, typename = etl::enable_if_t<etl::is_range_v<R>>>
5136 constexpr ranges::borrowed_subrange_t<R> operator()(R&& r, const T& value, Proj proj = {}) const
5137 {
5138 return (*this)(ranges::begin(r), ranges::end(r), value, etl::ref(proj));
5139 }
5140 };
5141
5142 inline constexpr remove_fn remove{};
5143
5144 struct remove_if_fn
5145 {
5146 template <class I, class S, class Pred, class Proj = etl::identity, typename = etl::enable_if_t<!etl::is_range_v<I>>>
5147 constexpr ranges::subrange<I> operator()(I first, S last, Pred pred, Proj proj = {}) const
5148 {
5149 first = ranges::find_if(first, last, etl::ref(pred), etl::ref(proj));
5150
5151 if (first != last)
5152 {
5153 I result = first;
5154
5155 for (I it = result; ++it != last;)
5156 {
5157 if (!etl::invoke(pred, etl::invoke(proj, *it)))
5158 {
5159 *result = etl::move(*it);
5160 ++result;
5161 }
5162 }
5163
5164 return {result, last};
5165 }
5166
5167 return {first, last};
5168 }
5169
5170 template <class R, class Pred, class Proj = etl::identity, typename = etl::enable_if_t<etl::is_range_v<R>>>
5171 constexpr ranges::borrowed_subrange_t<R> operator()(R&& r, Pred pred, Proj proj = {}) const
5172 {
5173 return (*this)(ranges::begin(r), ranges::end(r), etl::ref(pred), etl::ref(proj));
5174 }
5175 };
5176
5177 inline constexpr remove_if_fn remove_if{};
5178
5179 struct remove_copy_fn
5180 {
5181 template <class I, class S, class O, class T, class Proj = etl::identity, typename = etl::enable_if_t<!etl::is_range_v<I>>>
5182 constexpr ranges::remove_copy_result<I, O> operator()(I first, S last, O result, const T& value, Proj proj = {}) const
5183 {
5184 for (; first != last; ++first)
5185 {
5186 if (!(etl::invoke(proj, *first) == value))
5187 {
5188 *result = *first;
5189 ++result;
5190 }
5191 }
5192 return {etl::move(first), etl::move(result)};
5193 }
5194
5195 template <class R, class O, class T, class Proj = etl::identity, typename = etl::enable_if_t<etl::is_range_v<R>>>
5196 constexpr ranges::remove_copy_result<ranges::borrowed_iterator_t<R>, O> operator()(R&& r, O result, const T& value, Proj proj = {}) const
5197 {
5198 return (*this)(ranges::begin(r), ranges::end(r), etl::move(result), value, etl::ref(proj));
5199 }
5200 };
5201
5202 inline constexpr remove_copy_fn remove_copy{};
5203
5204 struct fill_fn
5205 {
5206 template <class I, class S, class T, typename = etl::enable_if_t<!etl::is_range_v<I>>>
5207 constexpr I operator()(I first, S last, const T& value) const
5208 {
5209 for (; first != last; ++first)
5210 {
5211 *first = value;
5212 }
5213 return first;
5214 }
5215
5216 template <class R, class T, typename = etl::enable_if_t<etl::is_range_v<R>>>
5217 constexpr ranges::borrowed_iterator_t<R> operator()(R&& r, const T& value) const
5218 {
5219 return (*this)(ranges::begin(r), ranges::end(r), value);
5220 }
5221 };
5222
5223 inline constexpr fill_fn fill{};
5224
5225 struct fill_n_fn
5226 {
5227 template <class I, class T>
5228 constexpr I operator()(I first, etl::iter_difference_t<I> n, const T& value) const
5229 {
5230 for (; n-- > 0; ++first)
5231 {
5232 *first = value;
5233 }
5234 return first;
5235 }
5236 };
5237
5238 inline constexpr fill_n_fn fill_n{};
5239
5240 struct generate_fn
5241 {
5242 template <class I, class S, class F, typename = etl::enable_if_t<!etl::is_range_v<I>>>
5243 constexpr I operator()(I first, S last, F gen) const
5244 {
5245 for (; first != last; ++first)
5246 {
5247 *first = gen();
5248 }
5249 return first;
5250 }
5251
5252 template <class R, class F, typename = etl::enable_if_t<etl::is_range_v<R>>>
5253 constexpr ranges::borrowed_iterator_t<R> operator()(R&& r, F gen) const
5254 {
5255 return (*this)(ranges::begin(r), ranges::end(r), etl::ref(gen));
5256 }
5257 };
5258
5259 inline constexpr generate_fn generate{};
5260
5261 struct generate_n_fn
5262 {
5263 template <class I, class F>
5264 constexpr I operator()(I first, etl::iter_difference_t<I> n, F gen) const
5265 {
5266 for (; n-- > 0; ++first)
5267 {
5268 *first = gen();
5269 }
5270 return first;
5271 }
5272 };
5273
5274 inline constexpr generate_n_fn generate_n{};
5275
5276 struct iota_fn
5277 {
5278 template <class O, class S, class T, typename = etl::enable_if_t<!etl::is_range_v<O>>>
5279 constexpr ranges::iota_result<O, T> operator()(O first, S last, T value) const
5280 {
5281 while (first != last)
5282 {
5283 *first = value;
5284 ++first;
5285 ++value;
5286 }
5287 return {etl::move(first), etl::move(value)};
5288 }
5289
5290 template <class R, class T, typename = etl::enable_if_t<etl::is_range_v<R>>>
5291 constexpr ranges::iota_result<ranges::borrowed_iterator_t<R>, T> operator()(R&& r, T value) const
5292 {
5293 return (*this)(ranges::begin(r), ranges::end(r), etl::move(value));
5294 }
5295 };
5296
5297 inline constexpr iota_fn iota{};
5298
5299 struct unique_fn
5300 {
5301 template <class I, class S, class Pred = ranges::equal_to, class Proj = etl::identity, typename = etl::enable_if_t<!etl::is_range_v<I>>>
5302 constexpr ranges::subrange<I> operator()(I first, S last, Pred pred = {}, Proj proj = {}) const
5303 {
5304 first = ranges::adjacent_find(first, last, etl::ref(pred), etl::ref(proj));
5305
5306 if (first != last)
5307 {
5308 I result = first;
5309 ++first;
5310
5311 while (++first != last)
5312 {
5313 if (!etl::invoke(pred, etl::invoke(proj, *result), etl::invoke(proj, *first)))
5314 {
5315 *++result = etl::move(*first);
5316 }
5317 }
5318
5319 return {++result, last};
5320 }
5321
5322 return {first, last};
5323 }
5324
5325 template <class R, class Pred = ranges::equal_to, class Proj = etl::identity, typename = etl::enable_if_t<etl::is_range_v<R>>>
5326 constexpr ranges::borrowed_subrange_t<R> operator()(R&& r, Pred pred = {}, Proj proj = {}) const
5327 {
5328 return (*this)(ranges::begin(r), ranges::end(r), etl::ref(pred), etl::ref(proj));
5329 }
5330 };
5331
5332 inline constexpr unique_fn unique{};
5333
5334 struct unique_copy_fn
5335 {
5336 template <class I, class S, class O, class Pred = ranges::equal_to, class Proj = etl::identity,
5337 typename = etl::enable_if_t<!etl::is_range_v<I>>>
5338 constexpr ranges::unique_copy_result<I, O> operator()(I first, S last, O result, Pred pred = {}, Proj proj = {}) const
5339 {
5340 if (first != last)
5341 {
5342 *result = *first;
5343 ++result;
5344
5345 auto previous = first;
5346 ++first;
5347
5348 for (; first != last; ++first)
5349 {
5350 if (!etl::invoke(pred, etl::invoke(proj, *previous), etl::invoke(proj, *first)))
5351 {
5352 *result = *first;
5353 ++result;
5354 }
5355 previous = first;
5356 }
5357 }
5358
5359 return {etl::move(first), etl::move(result)};
5360 }
5361
5362 template <class R, class O, class Pred = ranges::equal_to, class Proj = etl::identity, typename = etl::enable_if_t<etl::is_range_v<R>>>
5363 constexpr ranges::unique_copy_result<ranges::borrowed_iterator_t<R>, O> operator()(R&& r, O result, Pred pred = {}, Proj proj = {}) const
5364 {
5365 return (*this)(ranges::begin(r), ranges::end(r), etl::move(result), etl::ref(pred), etl::ref(proj));
5366 }
5367 };
5368
5369 inline constexpr unique_copy_fn unique_copy{};
5370
5371 struct transform_fn
5372 {
5373 // Unary: iterator + sentinel
5374 template <class I, class S, class O, class F, class Proj = etl::identity, typename = etl::enable_if_t<!etl::is_range_v<I>>>
5375 constexpr ranges::unary_transform_result<I, O> operator()(I first, S last, O result, F op, Proj proj = {}) const
5376 {
5377 for (; first != last; ++first, ++result)
5378 {
5379 *result = etl::invoke(op, etl::invoke(proj, *first));
5380 }
5381 return {etl::move(first), etl::move(result)};
5382 }
5383
5384 // Unary: range
5385 template < class R, class O, class F, class Proj = etl::identity, typename = etl::enable_if_t<etl::is_range_v<R> && !etl::is_range_v<O>>>
5386 constexpr ranges::unary_transform_result<ranges::borrowed_iterator_t<R>, O> operator()(R&& r, O result, F op, Proj proj = {}) const
5387 {
5388 return (*this)(ranges::begin(r), ranges::end(r), etl::move(result), etl::ref(op), etl::ref(proj));
5389 }
5390
5391 // Binary: iterator + sentinel
5392 template <class I1, class S1, class I2, class S2, class O, class F, class Proj1 = etl::identity, class Proj2 = etl::identity,
5393 typename = etl::enable_if_t<!etl::is_range_v<I1>>>
5394 constexpr ranges::binary_transform_result<I1, I2, O> operator()(I1 first1, S1 last1, I2 first2, S2 last2, O result, F op, Proj1 proj1 = {},
5395 Proj2 proj2 = {}) const
5396 {
5397 for (; first1 != last1 && first2 != last2; ++first1, ++first2, ++result)
5398 {
5399 *result = etl::invoke(op, etl::invoke(proj1, *first1), etl::invoke(proj2, *first2));
5400 }
5401 return {etl::move(first1), etl::move(first2), etl::move(result)};
5402 }
5403
5404 // Binary: range
5405 template < class R1, class R2, class O, class F, class Proj1 = etl::identity, class Proj2 = etl::identity,
5406 typename = etl::enable_if_t<etl::is_range_v<R1> && etl::is_range_v<R2>>>
5407 constexpr ranges::binary_transform_result< ranges::borrowed_iterator_t<R1>, ranges::borrowed_iterator_t<R2>, O>
5408 operator()(R1&& r1, R2&& r2, O result, F op, Proj1 proj1 = {}, Proj2 proj2 = {}) const
5409 {
5410 return (*this)(ranges::begin(r1), ranges::end(r1), ranges::begin(r2), ranges::end(r2), etl::move(result), etl::ref(op), etl::ref(proj1),
5411 etl::ref(proj2));
5412 }
5413 };
5414
5415 inline constexpr transform_fn transform{};
5416
5417 struct reverse_fn
5418 {
5419 template <class I, class S, typename = etl::enable_if_t<!etl::is_range_v<I>>>
5420 constexpr I operator()(I first, S last) const
5421 {
5422 I tail = ranges::next(first, last);
5423 I result = tail;
5424
5425 for (; first != tail && first != --tail; ++first)
5426 {
5427 etl::iter_swap(first, tail);
5428 }
5429
5430 return result;
5431 }
5432
5433 template <class R, typename = etl::enable_if_t<etl::is_range_v<R>>>
5434 constexpr ranges::borrowed_iterator_t<R> operator()(R&& r) const
5435 {
5436 return (*this)(ranges::begin(r), ranges::end(r));
5437 }
5438 };
5439
5440 inline constexpr reverse_fn reverse{};
5441
5442 template <class I, class O>
5443 using reverse_copy_result = in_out_result<I, O>;
5444
5445 struct reverse_copy_fn
5446 {
5447 template <class I, class S, class O, typename = etl::enable_if_t<!etl::is_range_v<I>>>
5448 constexpr ranges::reverse_copy_result<I, O> operator()(I first, S last, O result) const
5449 {
5450 I tail = ranges::next(first, last);
5451 I end_it = tail;
5452
5453 while (tail != first)
5454 {
5455 *result = *--tail;
5456 ++result;
5457 }
5458
5459 return {etl::move(end_it), etl::move(result)};
5460 }
5461
5462 template <class R, class O, typename = etl::enable_if_t<etl::is_range_v<R>>>
5463 constexpr ranges::reverse_copy_result<ranges::borrowed_iterator_t<R>, O> operator()(R&& r, O result) const
5464 {
5465 return (*this)(ranges::begin(r), ranges::end(r), etl::move(result));
5466 }
5467 };
5468
5469 inline constexpr reverse_copy_fn reverse_copy{};
5470
5471 template <class I>
5472 using rotate_result = ranges::subrange<I>;
5473
5474 struct rotate_fn
5475 {
5476 template <class I, class S, typename = etl::enable_if_t<!etl::is_range_v<I>>>
5477 constexpr ranges::rotate_result<I> operator()(I first, I middle, S last) const
5478 {
5479 if (first == middle)
5480 {
5481 I last_it = ranges::next(first, last);
5482 return {last_it, last_it};
5483 }
5484
5485 I last_it = ranges::next(first, last);
5486
5487 if (middle == last_it)
5488 {
5489 return {first, last_it};
5490 }
5491
5492 I new_first = etl::rotate(first, middle, last_it);
5493 return {etl::move(new_first), etl::move(last_it)};
5494 }
5495
5496 template <class R, typename = etl::enable_if_t<etl::is_range_v<R>>>
5497 constexpr ranges::rotate_result<ranges::borrowed_iterator_t<R>> operator()(R&& r, ranges::iterator_t<R> middle) const
5498 {
5499 return (*this)(ranges::begin(r), etl::move(middle), ranges::end(r));
5500 }
5501 };
5502
5503 inline constexpr rotate_fn rotate{};
5504
5505 struct rotate_copy_fn
5506 {
5507 template <class I, class S, class O, typename = etl::enable_if_t<!etl::is_range_v<I>>>
5508 constexpr ranges::rotate_copy_result<I, O> operator()(I first, I middle, S last, O result) const
5509 {
5510 I last_it = ranges::next(first, last);
5511 O end_out = etl::copy(middle, last_it, result);
5512 end_out = etl::copy(first, middle, end_out);
5513 return {etl::move(last_it), etl::move(end_out)};
5514 }
5515
5516 template <class R, class O, typename = etl::enable_if_t<etl::is_range_v<R>>>
5517 constexpr ranges::rotate_copy_result<ranges::borrowed_iterator_t<R>, O> operator()(R&& r, ranges::iterator_t<R> middle, O result) const
5518 {
5519 return (*this)(ranges::begin(r), etl::move(middle), ranges::end(r), etl::move(result));
5520 }
5521 };
5522
5523 inline constexpr rotate_copy_fn rotate_copy{};
5524
5525 struct shift_left_fn
5526 {
5527 template <class I, class S, typename = etl::enable_if_t<!etl::is_range_v<I>>>
5528 constexpr ranges::subrange<I> operator()(I first, S last, etl::iter_difference_t<I> n) const
5529 {
5530 I last_it = ranges::next(first, last);
5531
5532 if (n <= 0)
5533 {
5534 return {first, last_it};
5535 }
5536
5537 I mid = first;
5538 if (ranges::advance(mid, n, last_it) != 0)
5539 {
5540 return {first, first};
5541 }
5542
5543 I result = ranges::move(mid, last_it, first).out;
5544 return {first, etl::move(result)};
5545 }
5546
5547 template <class R, typename = etl::enable_if_t<etl::is_range_v<R>>>
5548 constexpr ranges::borrowed_subrange_t<R> operator()(R&& r, etl::ranges::range_difference_t<R> n) const
5549 {
5550 return (*this)(ranges::begin(r), ranges::end(r), n);
5551 }
5552 };
5553
5554 inline constexpr shift_left_fn shift_left{};
5555
5556 struct shift_right_fn
5557 {
5558 template <class I, class S, typename = etl::enable_if_t<!etl::is_range_v<I>>>
5559 constexpr ranges::subrange<I> operator()(I first, S last, etl::iter_difference_t<I> n) const
5560 {
5561 I last_it = ranges::next(first, last);
5562
5563 if (n <= 0)
5564 {
5565 return {first, last_it};
5566 }
5567
5568 I trail = last_it;
5569 if (ranges::advance(trail, -n, first) != 0)
5570 {
5571 return {last_it, last_it};
5572 }
5573
5574 I new_first = ranges::move_backward(first, trail, last_it).out;
5575 return {etl::move(new_first), etl::move(last_it)};
5576 }
5577
5578 template <class R, typename = etl::enable_if_t<etl::is_range_v<R>>>
5579 constexpr ranges::borrowed_subrange_t<R> operator()(R&& r, etl::ranges::range_difference_t<R> n) const
5580 {
5581 return (*this)(ranges::begin(r), ranges::end(r), n);
5582 }
5583 };
5584
5585 inline constexpr shift_right_fn shift_right{};
5586
5587 struct shuffle_fn
5588 {
5589 template <class I, class S, class Gen, typename = etl::enable_if_t<!etl::is_range_v<I>>>
5590 I operator()(I first, S last, Gen&& gen) const
5591 {
5592 ETL_STATIC_ASSERT(etl::is_random_access_iterator<I>::value, "shuffle requires random access iterators");
5593
5594 using diff_t = etl::iter_difference_t<I>;
5595 using udiff_t = etl::make_unsigned_t<diff_t>;
5596 using gen_t = etl::remove_reference_t<Gen>;
5597 using uresult_t = decltype(gen());
5598
5599 I last_it = ranges::next(first, last);
5600 diff_t n = last_it - first;
5601
5602 if (n <= 1)
5603 {
5604 return last_it;
5605 }
5606
5607 for (diff_t i = n - 1; i > 0; --i)
5608 {
5609 // Generate a uniformly distributed random index in [0, i]
5610 // using rejection sampling to avoid modulo bias.
5611 udiff_t range = static_cast<udiff_t>(i);
5612 constexpr uresult_t gmin = gen_t::min();
5613 constexpr uresult_t gmax = gen_t::max();
5614 constexpr uresult_t grange = gmax - gmin;
5615
5616 uresult_t j;
5617
5618 if ETL_IF_CONSTEXPR (grange == static_cast<uresult_t>(-1))
5619 {
5620 // Generator covers full range of uresult_t, just use modulo with
5621 // rejection
5622 uresult_t limit = (static_cast<uresult_t>(-1) / (static_cast<uresult_t>(range) + 1)) * (static_cast<uresult_t>(range) + 1);
5623 do {
5624 j = static_cast<uresult_t>(gen() - gmin);
5625 } while (j >= limit);
5626 j %= (static_cast<uresult_t>(range) + 1);
5627 }
5628 else
5629 {
5630 uresult_t limit = (grange / (static_cast<uresult_t>(range) + 1)) * (static_cast<uresult_t>(range) + 1);
5631 do {
5632 j = static_cast<uresult_t>(gen() - gmin);
5633 } while (j >= limit);
5634 j %= (static_cast<uresult_t>(range) + 1);
5635 }
5636
5637 etl::iter_swap(first + i, first + static_cast<diff_t>(j));
5638 }
5639
5640 return last_it;
5641 }
5642
5643 template <class R, class Gen, typename = etl::enable_if_t<etl::is_range_v<R>>>
5644 ranges::borrowed_iterator_t<R> operator()(R&& r, Gen&& gen) const
5645 {
5646 ETL_STATIC_ASSERT(etl::is_random_access_iterator<ranges::iterator_t<R>>::value, "shuffle requires a range with random access iterators");
5647
5648 return (*this)(ranges::begin(r), ranges::end(r), static_cast<Gen&&>(gen));
5649 }
5650 };
5651
5652 inline constexpr shuffle_fn shuffle{};
5653
5654 struct sample_fn
5655 {
5656 template <class I, class S, class O, class Gen, typename = etl::enable_if_t<!etl::is_range_v<I>>>
5657 O operator()(I first, S last, O out, etl::iter_difference_t<I> n, Gen&& gen) const
5658 {
5659 using diff_t = etl::iter_difference_t<I>;
5660 using udiff_t = etl::make_unsigned_t<diff_t>;
5661 using gen_t = etl::remove_reference_t<Gen>;
5662 using uresult_t = decltype(gen());
5663
5664 if (n <= 0)
5665 {
5666 return out;
5667 }
5668
5669 // Compute the size of [first, last).
5670 I first_copy = first;
5671 diff_t pop_size = 0;
5672 for (I it = first_copy; it != last; ++it)
5673 {
5674 ++pop_size;
5675 }
5676
5677 if (pop_size <= n)
5678 {
5679 // Copy all elements.
5680 for (; first != last; ++first, ++out)
5681 {
5682 *out = *first;
5683 }
5684 return out;
5685 }
5686
5687 // Selection sampling (Algorithm S / Vitter).
5688 // For each element, decide whether to include it.
5689 diff_t remaining = pop_size;
5690 diff_t needed = n;
5691
5692 for (; first != last && needed > 0; ++first, --remaining)
5693 {
5694 // Generate a uniformly distributed random number in [0, remaining).
5695 udiff_t range = static_cast<udiff_t>(remaining - 1);
5696 constexpr uresult_t gmin = gen_t::min();
5697 constexpr uresult_t gmax = gen_t::max();
5698 constexpr uresult_t grange = gmax - gmin;
5699
5700 uresult_t j;
5701
5702 if ETL_IF_CONSTEXPR (grange == static_cast<uresult_t>(-1))
5703 {
5704 if (range == 0)
5705 {
5706 j = 0;
5707 }
5708 else
5709 {
5710 uresult_t limit = (static_cast<uresult_t>(-1) / (static_cast<uresult_t>(range) + 1)) * (static_cast<uresult_t>(range) + 1);
5711 do {
5712 j = static_cast<uresult_t>(gen() - gmin);
5713 } while (j >= limit);
5714 j %= (static_cast<uresult_t>(range) + 1);
5715 }
5716 }
5717 else
5718 {
5719 if (range == 0)
5720 {
5721 j = 0;
5722 }
5723 else
5724 {
5725 uresult_t limit = (grange / (static_cast<uresult_t>(range) + 1)) * (static_cast<uresult_t>(range) + 1);
5726 do {
5727 j = static_cast<uresult_t>(gen() - gmin);
5728 } while (j >= limit);
5729 j %= (static_cast<uresult_t>(range) + 1);
5730 }
5731 }
5732
5733 if (static_cast<diff_t>(j) < needed)
5734 {
5735 *out = *first;
5736 ++out;
5737 --needed;
5738 }
5739 }
5740
5741 return out;
5742 }
5743
5744 template <class R, class O, class Gen, typename = etl::enable_if_t<etl::is_range_v<R>>>
5745 O operator()(R&& r, O out, etl::ranges::range_difference_t<R> n, Gen&& gen) const
5746 {
5747 return (*this)(ranges::begin(r), ranges::end(r), etl::move(out), n, static_cast<Gen&&>(gen));
5748 }
5749 };
5750
5751 inline constexpr sample_fn sample{};
5752
5753 struct sort_fn
5754 {
5755 template <class I, class S, class Comp = ranges::less, class Proj = etl::identity, typename = etl::enable_if_t<!etl::is_range_v<I>>>
5756 constexpr I operator()(I first, S last, Comp comp = {}, Proj proj = {}) const
5757 {
5758 ETL_STATIC_ASSERT(etl::is_random_access_iterator<I>::value, "sort requires random access iterators");
5759
5760 I last_it = ranges::next(first, last);
5761
5762 if (first == last_it)
5763 {
5764 return last_it;
5765 }
5766
5767 // Shell sort with projection support
5768 auto n = etl::distance(first, last_it);
5769
5770 for (auto gap = n / 2; gap > 0; gap /= 2)
5771 {
5772 for (auto i = gap; i < n; ++i)
5773 {
5774 auto temp = etl::move(*(first + i));
5775 auto j = i;
5776
5777 while (j >= gap && etl::invoke(comp, etl::invoke(proj, temp), etl::invoke(proj, *(first + (j - gap)))))
5778 {
5779 *(first + j) = etl::move(*(first + (j - gap)));
5780 j -= gap;
5781 }
5782
5783 *(first + j) = etl::move(temp);
5784 }
5785 }
5786
5787 return last_it;
5788 }
5789
5790 template <class R, class Comp = ranges::less, class Proj = etl::identity, typename = etl::enable_if_t<etl::is_range_v<R>>>
5791 constexpr ranges::borrowed_iterator_t<R> operator()(R&& r, Comp comp = {}, Proj proj = {}) const
5792 {
5793 ETL_STATIC_ASSERT(etl::is_random_access_iterator<ranges::iterator_t<R>>::value, "sort requires a range with random access iterators");
5794
5795 return (*this)(ranges::begin(r), ranges::end(r), etl::move(comp), etl::move(proj));
5796 }
5797 };
5798
5799 inline constexpr sort_fn sort{};
5800
5801 struct stable_sort_fn
5802 {
5803 template <class I, class S, class Comp = ranges::less, class Proj = etl::identity, typename = etl::enable_if_t<!etl::is_range_v<I>>>
5804 constexpr I operator()(I first, S last, Comp comp = {}, Proj proj = {}) const
5805 {
5806 I last_it = ranges::next(first, last);
5807
5808 if (first == last_it)
5809 {
5810 return last_it;
5811 }
5812
5813 // Insertion sort with projection support (stable)
5814 for (I i = ranges::next(first); i != last_it; ++i)
5815 {
5816 auto temp = etl::move(*i);
5817 I j = i;
5818
5819 while (j != first)
5820 {
5821 I prev_j = ranges::prev(j);
5822 if (etl::invoke(comp, etl::invoke(proj, temp), etl::invoke(proj, *prev_j)))
5823 {
5824 *j = etl::move(*prev_j);
5825 j = prev_j;
5826 }
5827 else
5828 {
5829 break;
5830 }
5831 }
5832
5833 *j = etl::move(temp);
5834 }
5835
5836 return last_it;
5837 }
5838
5839 template <class R, class Comp = ranges::less, class Proj = etl::identity, typename = etl::enable_if_t<etl::is_range_v<R>>>
5840 constexpr ranges::borrowed_iterator_t<R> operator()(R&& r, Comp comp = {}, Proj proj = {}) const
5841 {
5842 return (*this)(ranges::begin(r), ranges::end(r), etl::move(comp), etl::move(proj));
5843 }
5844 };
5845
5846 inline constexpr stable_sort_fn stable_sort{};
5847
5848 struct partial_sort_fn
5849 {
5850 template <class I, class S, class Comp = ranges::less, class Proj = etl::identity, typename = etl::enable_if_t<!etl::is_range_v<I>>>
5851 constexpr I operator()(I first, I middle, S last, Comp comp = {}, Proj proj = {}) const
5852 {
5853 ETL_STATIC_ASSERT(etl::is_random_access_iterator<I>::value, "partial_sort requires random access iterators");
5854
5856
5857 I last_it = ranges::next(first, last);
5858
5859 if (first == middle || first == last_it)
5860 {
5861 return last_it;
5862 }
5863
5864 // Build a max-heap on [first, middle)
5865 auto heap_size = etl::distance(first, middle);
5866
5867 // Heapify: process from the last parent down to 0
5868 for (auto start = (heap_size - 1) / 2; start >= 0; --start)
5869 {
5870 sift_down(first, start, heap_size, comp, proj);
5871 }
5872
5873 // For each element in [middle, last_it), if it is smaller than the heap
5874 // root, swap it in and re-heapify
5875 for (I it = middle; it != last_it; ++it)
5876 {
5877 if (etl::invoke(comp, etl::invoke(proj, *it), etl::invoke(proj, *first)))
5878 {
5879 etl::iter_swap(it, first);
5880 sift_down(first, decltype(heap_size){0}, heap_size, comp, proj);
5881 }
5882 }
5883
5884 // Sort the heap to produce a sorted [first, middle)
5885 // Repeatedly extract the max from the heap
5886 for (auto heap_end = heap_size - 1; heap_end > 0; --heap_end)
5887 {
5888 etl::iter_swap(first, first + heap_end);
5889 sift_down(first, decltype(heap_size){0}, heap_end, comp, proj);
5890 }
5891
5892 return last_it;
5893
5895 }
5896
5897 template <class R, class Comp = ranges::less, class Proj = etl::identity, typename = etl::enable_if_t<etl::is_range_v<R>>>
5898 constexpr ranges::borrowed_iterator_t<R> operator()(R&& r, ranges::iterator_t<R> middle, Comp comp = {}, Proj proj = {}) const
5899 {
5900 ETL_STATIC_ASSERT(etl::is_random_access_iterator<ranges::iterator_t<R>>::value, "partial_sort requires a range with random access iterators");
5901
5902 return (*this)(ranges::begin(r), etl::move(middle), ranges::end(r), etl::move(comp), etl::move(proj));
5903 }
5904
5905 private:
5906
5907 template <class I, class DiffType, class Comp, class Proj>
5908 static constexpr void sift_down(I first, DiffType index, DiffType heap_size, Comp& comp, Proj& proj)
5909 {
5910 while (true)
5911 {
5912 auto largest = index;
5913 auto left = 2 * index + 1;
5914 auto right = 2 * index + 2;
5915
5916 if (left < heap_size && etl::invoke(comp, etl::invoke(proj, *(first + largest)), etl::invoke(proj, *(first + left))))
5917 {
5918 largest = left;
5919 }
5920
5921 if (right < heap_size && etl::invoke(comp, etl::invoke(proj, *(first + largest)), etl::invoke(proj, *(first + right))))
5922 {
5923 largest = right;
5924 }
5925
5926 if (largest == index)
5927 {
5928 break;
5929 }
5930
5931 etl::iter_swap(first + index, first + largest);
5932 index = largest;
5933 }
5934 }
5935 };
5936
5937 inline constexpr partial_sort_fn partial_sort{};
5938
5939 struct partial_sort_copy_fn
5940 {
5941 template <class I1, class S1, class I2, class S2, class Comp = ranges::less, class Proj1 = etl::identity, class Proj2 = etl::identity,
5942 typename = etl::enable_if_t<!etl::is_range_v<I1>>>
5943 constexpr ranges::partial_sort_copy_result<I1, I2> operator()(I1 first, S1 last, I2 result_first, S2 result_last, Comp comp = {},
5944 Proj1 proj1 = {}, Proj2 proj2 = {}) const
5945 {
5946 ETL_STATIC_ASSERT(etl::is_random_access_iterator<I2>::value, "partial_sort_copy requires the output to be random access iterators");
5947
5949
5950 I1 in_last = ranges::next(first, last);
5951 I2 out_last = ranges::next(result_first, result_last);
5952
5953 I2 r = result_first;
5954
5955 // Copy elements from the input range into the output range
5956 for (I1 it = first; it != in_last && r != out_last; ++it, ++r)
5957 {
5958 *r = *it;
5959 }
5960
5961 auto heap_size = etl::distance(result_first, r);
5962
5963 if (heap_size == 0)
5964 {
5965 return {etl::move(in_last), etl::move(r)};
5966 }
5967
5968 // Build a max-heap on [result_first, r)
5969 for (auto start = (heap_size - 1) / 2; start >= 0; --start)
5970 {
5971 sift_down(result_first, start, heap_size, comp, proj2);
5972 }
5973
5974 // For remaining elements in [first + heap_size, in_last), if smaller
5975 // than the heap root, swap it in and re-heapify
5976 I1 it = first;
5977 etl::advance(it, heap_size);
5978 for (; it != in_last; ++it)
5979 {
5980 if (etl::invoke(comp, etl::invoke(proj1, *it), etl::invoke(proj2, *result_first)))
5981 {
5982 *result_first = *it;
5983 sift_down(result_first, decltype(heap_size){0}, heap_size, comp, proj2);
5984 }
5985 }
5986
5987 // Sort the heap to produce a sorted output range
5988 for (auto heap_end = heap_size - 1; heap_end > 0; --heap_end)
5989 {
5990 etl::iter_swap(result_first, result_first + heap_end);
5991 sift_down(result_first, decltype(heap_size){0}, heap_end, comp, proj2);
5992 }
5994
5995 return {etl::move(in_last), etl::move(r)};
5996 }
5997
5998 template <class R1, class R2, class Comp = ranges::less, class Proj1 = etl::identity, class Proj2 = etl::identity,
5999 typename = etl::enable_if_t<etl::is_range_v<R1>>>
6000 constexpr ranges::partial_sort_copy_result< ranges::borrowed_iterator_t<R1>, ranges::borrowed_iterator_t<R2>>
6001 operator()(R1&& r, R2&& result_r, Comp comp = {}, Proj1 proj1 = {}, Proj2 proj2 = {}) const
6002 {
6003 ETL_STATIC_ASSERT(etl::is_random_access_iterator<ranges::iterator_t<R2>>::value,
6004 "partial_sort_copy requires the output range to have random access iterators");
6005
6006 return (*this)(ranges::begin(r), ranges::end(r), ranges::begin(result_r), ranges::end(result_r), etl::move(comp), etl::move(proj1),
6007 etl::move(proj2));
6008 }
6009
6010 private:
6011
6012 template <class I, class DiffType, class Comp, class Proj>
6013 static constexpr void sift_down(I first, DiffType index, DiffType heap_size, Comp& comp, Proj& proj)
6014 {
6015 while (true)
6016 {
6017 auto largest = index;
6018 auto left = 2 * index + 1;
6019 auto right = 2 * index + 2;
6020
6021 if (left < heap_size && etl::invoke(comp, etl::invoke(proj, *(first + largest)), etl::invoke(proj, *(first + left))))
6022 {
6023 largest = left;
6024 }
6025
6026 if (right < heap_size && etl::invoke(comp, etl::invoke(proj, *(first + largest)), etl::invoke(proj, *(first + right))))
6027 {
6028 largest = right;
6029 }
6030
6031 if (largest == index)
6032 {
6033 break;
6034 }
6035
6036 etl::iter_swap(first + index, first + largest);
6037 index = largest;
6038 }
6039 }
6040 };
6041
6042 inline constexpr partial_sort_copy_fn partial_sort_copy{};
6043
6044 struct nth_element_fn
6045 {
6046 template <class I, class S, class Comp = ranges::less, class Proj = etl::identity, typename = etl::enable_if_t<!etl::is_range_v<I>>>
6047 constexpr I operator()(I first, I nth, S last, Comp comp = {}, Proj proj = {}) const
6048 {
6049 ETL_STATIC_ASSERT(etl::is_random_access_iterator<I>::value, "nth_element requires random access iterators");
6050
6051 I last_it = ranges::next(first, last);
6052
6053 if (first == last_it || ranges::next(first) == last_it)
6054 {
6055 return last_it;
6056 }
6057
6058 I lo = first;
6059 I hi = ranges::prev(last_it);
6060
6061 while (lo <= hi)
6062 {
6063 I p = nth_partition(lo, hi, comp, proj);
6064
6065 if (p == nth)
6066 {
6067 return last_it;
6068 }
6069 else if (p > nth)
6070 {
6071 hi = ranges::prev(p);
6072 }
6073 else
6074 {
6075 lo = ranges::next(p);
6076 }
6077 }
6078
6079 return last_it;
6080 }
6081
6082 template <class R, class Comp = ranges::less, class Proj = etl::identity, typename = etl::enable_if_t<etl::is_range_v<R>>>
6083 constexpr ranges::borrowed_iterator_t<R> operator()(R&& r, ranges::iterator_t<R> nth, Comp comp = {}, Proj proj = {}) const
6084 {
6085 ETL_STATIC_ASSERT(etl::is_random_access_iterator<ranges::iterator_t<R>>::value, "nth_element requires a range with random access iterators");
6086
6087 return (*this)(ranges::begin(r), etl::move(nth), ranges::end(r), etl::move(comp), etl::move(proj));
6088 }
6089
6090 private:
6091
6092 template <class I, class Comp, class Proj>
6093 static constexpr I nth_partition(I first, I last, Comp& comp, Proj& proj)
6094 {
6095 if (first == last)
6096 {
6097 return first;
6098 }
6099
6100 if (last - first == 1)
6101 {
6102 if (etl::invoke(comp, etl::invoke(proj, *last), etl::invoke(proj, *first)))
6103 {
6104 etl::iter_swap(first, last);
6105 }
6106 return first;
6107 }
6108
6109 // Median-of-three pivot selection
6110 I mid = first + (last - first) / 2;
6111
6112 if (etl::invoke(comp, etl::invoke(proj, *mid), etl::invoke(proj, *first)))
6113 {
6114 etl::iter_swap(first, mid);
6115 }
6116
6117 if (etl::invoke(comp, etl::invoke(proj, *last), etl::invoke(proj, *first)))
6118 {
6119 etl::iter_swap(first, last);
6120 }
6121
6122 if (etl::invoke(comp, etl::invoke(proj, *mid), etl::invoke(proj, *last)))
6123 {
6124 etl::iter_swap(mid, last);
6125 }
6126
6127 // Pivot is now at *last
6128 I i = first;
6129 I j = last;
6130
6131 while (true)
6132 {
6133 while (etl::invoke(comp, etl::invoke(proj, *i), etl::invoke(proj, *last)))
6134 {
6135 ++i;
6136 }
6137
6138 --j;
6139
6140 while (i < j && etl::invoke(comp, etl::invoke(proj, *last), etl::invoke(proj, *j)))
6141 {
6142 --j;
6143 }
6144
6145 if (i >= j)
6146 {
6147 break;
6148 }
6149
6150 etl::iter_swap(i, j);
6151 ++i;
6152 }
6153
6154 etl::iter_swap(i, last);
6155 return i;
6156 }
6157 };
6158
6159 inline constexpr nth_element_fn nth_element{};
6160
6161 struct partition_fn
6162 {
6163 template <class I, class S, class Pred, class Proj = etl::identity, typename = etl::enable_if_t<!etl::is_range_v<I>>>
6164 constexpr ranges::subrange<I> operator()(I first, S last, Pred pred, Proj proj = {}) const
6165 {
6166 first = ranges::find_if_not(first, last, etl::ref(pred), etl::ref(proj));
6167
6168 if (first == last)
6169 {
6170 return {first, first};
6171 }
6172
6173 for (I i = ranges::next(first); i != last; ++i)
6174 {
6175 if (etl::invoke(pred, etl::invoke(proj, *i)))
6176 {
6177 etl::iter_swap(i, first);
6178 ++first;
6179 }
6180 }
6181
6182 return {first, ranges::next(first, last)};
6183 }
6184
6185 template <class R, class Pred, class Proj = etl::identity, typename = etl::enable_if_t<etl::is_range_v<R>>>
6186 constexpr ranges::borrowed_subrange_t<R> operator()(R&& r, Pred pred, Proj proj = {}) const
6187 {
6188 return (*this)(ranges::begin(r), ranges::end(r), etl::ref(pred), etl::ref(proj));
6189 }
6190 };
6191
6192 inline constexpr partition_fn partition{};
6193
6194 struct is_partitioned_fn
6195 {
6196 template <class I, class S, class Pred, class Proj = etl::identity, typename = etl::enable_if_t<!etl::is_range_v<I>>>
6197 constexpr bool operator()(I first, S last, Pred pred, Proj proj = {}) const
6198 {
6199 for (; first != last; ++first)
6200 {
6201 if (!etl::invoke(pred, etl::invoke(proj, *first)))
6202 {
6203 break;
6204 }
6205 }
6206
6207 for (; first != last; ++first)
6208 {
6209 if (etl::invoke(pred, etl::invoke(proj, *first)))
6210 {
6211 return false;
6212 }
6213 }
6214
6215 return true;
6216 }
6217
6218 template <class R, class Pred, class Proj = etl::identity, typename = etl::enable_if_t<etl::is_range_v<R>>>
6219 constexpr bool operator()(R&& r, Pred pred, Proj proj = {}) const
6220 {
6221 return (*this)(ranges::begin(r), ranges::end(r), etl::ref(pred), etl::ref(proj));
6222 }
6223 };
6224
6225 inline constexpr is_partitioned_fn is_partitioned{};
6226
6227 struct partition_copy_fn
6228 {
6229 template <class I, class S, class O1, class O2, class Pred, class Proj = etl::identity, typename = etl::enable_if_t<!etl::is_range_v<I>>>
6230 constexpr ranges::partition_copy_result<I, O1, O2> operator()(I first, S last, O1 out_true, O2 out_false, Pred pred, Proj proj = {}) const
6231 {
6232 for (; first != last; ++first)
6233 {
6234 if (etl::invoke(pred, etl::invoke(proj, *first)))
6235 {
6236 *out_true = *first;
6237 ++out_true;
6238 }
6239 else
6240 {
6241 *out_false = *first;
6242 ++out_false;
6243 }
6244 }
6245
6246 return {etl::move(first), etl::move(out_true), etl::move(out_false)};
6247 }
6248
6249 template <class R, class O1, class O2, class Pred, class Proj = etl::identity, typename = etl::enable_if_t<etl::is_range_v<R>>>
6250 constexpr ranges::partition_copy_result<ranges::borrowed_iterator_t<R>, O1, O2> operator()(R&& r, O1 out_true, O2 out_false, Pred pred,
6251 Proj proj = {}) const
6252 {
6253 return (*this)(ranges::begin(r), ranges::end(r), etl::move(out_true), etl::move(out_false), etl::ref(pred), etl::ref(proj));
6254 }
6255 };
6256
6257 inline constexpr partition_copy_fn partition_copy{};
6258
6259 struct partition_point_fn
6260 {
6261 template <class I, class S, class Pred, class Proj = etl::identity, typename = etl::enable_if_t<!etl::is_range_v<I>>>
6262 constexpr I operator()(I first, S last, Pred pred, Proj proj = {}) const
6263 {
6264 for (; first != last; ++first)
6265 {
6266 if (!etl::invoke(pred, etl::invoke(proj, *first)))
6267 {
6268 return first;
6269 }
6270 }
6271
6272 return first;
6273 }
6274
6275 template <class R, class Pred, class Proj = etl::identity, typename = etl::enable_if_t<etl::is_range_v<R>>>
6276 constexpr ranges::borrowed_iterator_t<R> operator()(R&& r, Pred pred, Proj proj = {}) const
6277 {
6278 return (*this)(ranges::begin(r), ranges::end(r), etl::ref(pred), etl::ref(proj));
6279 }
6280 };
6281
6282 inline constexpr partition_point_fn partition_point{};
6283
6284 struct stable_partition_fn
6285 {
6286 template <class I, class S, class Pred, class Proj = etl::identity, typename = etl::enable_if_t<!etl::is_range_v<I>>>
6287 constexpr ranges::subrange<I> operator()(I first, S last, Pred pred, Proj proj = {}) const
6288 {
6289 // Find the first element that does not satisfy the predicate
6290 first = ranges::find_if_not(first, last, etl::ref(pred), etl::ref(proj));
6291
6292 if (first == last)
6293 {
6294 return {first, first};
6295 }
6296
6297 I last_it = ranges::next(first, last);
6298
6299 I pp = stable_partition_impl(first, last_it, etl::ref(pred), etl::ref(proj), etl::distance(first, last_it));
6300
6301 return {pp, last_it};
6302 }
6303
6304 template <class R, class Pred, class Proj = etl::identity, typename = etl::enable_if_t<etl::is_range_v<R>>>
6305 constexpr ranges::borrowed_subrange_t<R> operator()(R&& r, Pred pred, Proj proj = {}) const
6306 {
6307 return (*this)(ranges::begin(r), ranges::end(r), etl::ref(pred), etl::ref(proj));
6308 }
6309
6310 private:
6311
6312 template <class I, class Pred, class Proj>
6313 static constexpr I stable_partition_impl(I first, I last, Pred pred, Proj proj, typename etl::iterator_traits<I>::difference_type len)
6314 {
6315 if (len == 0)
6316 {
6317 return first;
6318 }
6319
6320 if (len == 1)
6321 {
6322 return etl::invoke(pred, etl::invoke(proj, *first)) ? ranges::next(first) : first;
6323 }
6324
6325 I middle = ranges::next(first, len / 2);
6326
6327 I left_partition = stable_partition_impl(first, middle, etl::ref(pred), etl::ref(proj), len / 2);
6328 I right_partition = stable_partition_impl(middle, last, etl::ref(pred), etl::ref(proj), len - len / 2);
6329
6330 if (left_partition == middle)
6331 {
6332 return right_partition;
6333 }
6334
6335 if (middle == right_partition)
6336 {
6337 return left_partition;
6338 }
6339
6340 return etl::rotate(left_partition, middle, right_partition);
6341 }
6342 };
6343
6344 inline constexpr stable_partition_fn stable_partition{};
6345
6346 struct is_sorted_until_fn
6347 {
6348 template <class I, class S, class Comp = ranges::less, class Proj = etl::identity, typename = etl::enable_if_t<!etl::is_range_v<I>>>
6349 constexpr I operator()(I first, S last, Comp comp = {}, Proj proj = {}) const
6350 {
6351 if (first != last)
6352 {
6353 I next_it = ranges::next(first);
6354
6355 while (next_it != last)
6356 {
6357 if (etl::invoke(comp, etl::invoke(proj, *next_it), etl::invoke(proj, *first)))
6358 {
6359 return next_it;
6360 }
6361
6362 first = next_it;
6363 ++next_it;
6364 }
6365 }
6366
6367 return ranges::next(first, last);
6368 }
6369
6370 template <class R, class Comp = ranges::less, class Proj = etl::identity, typename = etl::enable_if_t<etl::is_range_v<R>>>
6371 constexpr ranges::borrowed_iterator_t<R> operator()(R&& r, Comp comp = {}, Proj proj = {}) const
6372 {
6373 return (*this)(ranges::begin(r), ranges::end(r), etl::move(comp), etl::move(proj));
6374 }
6375 };
6376
6377 inline constexpr is_sorted_until_fn is_sorted_until{};
6378
6379 struct is_sorted_fn
6380 {
6381 template <class I, class S, class Comp = ranges::less, class Proj = etl::identity, typename = etl::enable_if_t<!etl::is_range_v<I>>>
6382 constexpr bool operator()(I first, S last, Comp comp = {}, Proj proj = {}) const
6383 {
6384 return ranges::is_sorted_until(first, last, etl::ref(comp), etl::ref(proj)) == last;
6385 }
6386
6387 template <class R, class Comp = ranges::less, class Proj = etl::identity, typename = etl::enable_if_t<etl::is_range_v<R>>>
6388 constexpr bool operator()(R&& r, Comp comp = {}, Proj proj = {}) const
6389 {
6390 return (*this)(ranges::begin(r), ranges::end(r), etl::move(comp), etl::move(proj));
6391 }
6392 };
6393
6394 inline constexpr is_sorted_fn is_sorted{};
6395
6396 struct lower_bound_fn
6397 {
6398 template <class I, class S, class T, class Comp = ranges::less, class Proj = etl::identity, typename = etl::enable_if_t<!etl::is_range_v<I>>>
6399 constexpr I operator()(I first, S last, const T& value, Comp comp = {}, Proj proj = {}) const
6400 {
6401 auto len = etl::distance(first, last);
6402
6403 while (len > 0)
6404 {
6405 auto half = len / 2;
6406 I middle = ranges::next(first, half);
6407
6408 if (etl::invoke(comp, etl::invoke(proj, *middle), value))
6409 {
6410 first = ranges::next(middle);
6411 len -= half + 1;
6412 }
6413 else
6414 {
6415 len = half;
6416 }
6417 }
6418
6419 return first;
6420 }
6421
6422 template <class R, class T, class Comp = ranges::less, class Proj = etl::identity, typename = etl::enable_if_t<etl::is_range_v<R>>>
6423 constexpr ranges::borrowed_iterator_t<R> operator()(R&& r, const T& value, Comp comp = {}, Proj proj = {}) const
6424 {
6425 return (*this)(ranges::begin(r), ranges::end(r), value, etl::move(comp), etl::move(proj));
6426 }
6427 };
6428
6429 inline constexpr lower_bound_fn lower_bound{};
6430
6431 struct upper_bound_fn
6432 {
6433 template <class I, class S, class T, class Comp = ranges::less, class Proj = etl::identity, typename = etl::enable_if_t<!etl::is_range_v<I>>>
6434 constexpr I operator()(I first, S last, const T& value, Comp comp = {}, Proj proj = {}) const
6435 {
6436 auto len = etl::distance(first, last);
6437
6438 while (len > 0)
6439 {
6440 auto half = len / 2;
6441 I middle = ranges::next(first, half);
6442
6443 if (!etl::invoke(comp, value, etl::invoke(proj, *middle)))
6444 {
6445 first = ranges::next(middle);
6446 len -= half + 1;
6447 }
6448 else
6449 {
6450 len = half;
6451 }
6452 }
6453
6454 return first;
6455 }
6456
6457 template <class R, class T, class Comp = ranges::less, class Proj = etl::identity, typename = etl::enable_if_t<etl::is_range_v<R>>>
6458 constexpr ranges::borrowed_iterator_t<R> operator()(R&& r, const T& value, Comp comp = {}, Proj proj = {}) const
6459 {
6460 return (*this)(ranges::begin(r), ranges::end(r), value, etl::move(comp), etl::move(proj));
6461 }
6462 };
6463
6464 inline constexpr upper_bound_fn upper_bound{};
6465
6466 struct equal_range_fn
6467 {
6468 template <class I, class S, class T, class Comp = ranges::less, class Proj = etl::identity, typename = etl::enable_if_t<!etl::is_range_v<I>>>
6469 constexpr ranges::subrange<I> operator()(I first, S last, const T& value, Comp comp = {}, Proj proj = {}) const
6470 {
6471 return {ranges::lower_bound(first, last, value, etl::ref(comp), etl::ref(proj)),
6472 ranges::upper_bound(first, last, value, etl::ref(comp), etl::ref(proj))};
6473 }
6474
6475 template <class R, class T, class Comp = ranges::less, class Proj = etl::identity, typename = etl::enable_if_t<etl::is_range_v<R>>>
6476 constexpr ranges::borrowed_subrange_t<R> operator()(R&& r, const T& value, Comp comp = {}, Proj proj = {}) const
6477 {
6478 return (*this)(ranges::begin(r), ranges::end(r), value, etl::move(comp), etl::move(proj));
6479 }
6480 };
6481
6482 inline constexpr equal_range_fn equal_range{};
6483
6484 struct binary_search_fn
6485 {
6486 template <class I, class S, class T, class Comp = ranges::less, class Proj = etl::identity, typename = etl::enable_if_t<!etl::is_range_v<I>>>
6487 ETL_NODISCARD
6488 constexpr bool operator()(I first, S last, const T& value, Comp comp = {}, Proj proj = {}) const
6489 {
6490 first = ranges::lower_bound(first, last, value, etl::ref(comp), etl::ref(proj));
6491
6492 return (!(first == last) && !(etl::invoke(comp, value, etl::invoke(proj, *first))));
6493 }
6494
6495 template <class R, class T, class Comp = ranges::less, class Proj = etl::identity, typename = etl::enable_if_t<etl::is_range_v<R>>>
6496 ETL_NODISCARD
6497 constexpr bool operator()(R&& r, const T& value, Comp comp = {}, Proj proj = {}) const
6498 {
6499 return (*this)(ranges::begin(r), ranges::end(r), value, etl::move(comp), etl::move(proj));
6500 }
6501 };
6502
6503 inline constexpr binary_search_fn binary_search{};
6504
6505 struct includes_fn
6506 {
6507 template <class I1, class S1, class I2, class S2, class Comp = ranges::less, class Proj1 = etl::identity, class Proj2 = etl::identity,
6508 typename = etl::enable_if_t<!etl::is_range_v<I1>>>
6509 ETL_NODISCARD
6510 constexpr bool operator()(I1 first1, S1 last1, I2 first2, S2 last2, Comp comp = {}, Proj1 proj1 = {}, Proj2 proj2 = {}) const
6511 {
6512 for (; first2 != last2; ++first1)
6513 {
6514 if (first1 == last1)
6515 {
6516 return false;
6517 }
6518
6519 if (etl::invoke(comp, etl::invoke(proj2, *first2), etl::invoke(proj1, *first1)))
6520 {
6521 return false;
6522 }
6523
6524 if (!etl::invoke(comp, etl::invoke(proj1, *first1), etl::invoke(proj2, *first2)))
6525 {
6526 ++first2;
6527 }
6528 }
6529
6530 return true;
6531 }
6532
6533 template <class R1, class R2, class Comp = ranges::less, class Proj1 = etl::identity, class Proj2 = etl::identity,
6534 typename = etl::enable_if_t<etl::is_range_v<R1>>>
6535 ETL_NODISCARD
6536 constexpr bool operator()(R1&& r1, R2&& r2, Comp comp = {}, Proj1 proj1 = {}, Proj2 proj2 = {}) const
6537 {
6538 return (*this)(ranges::begin(r1), ranges::end(r1), ranges::begin(r2), ranges::end(r2), etl::move(comp), etl::move(proj1), etl::move(proj2));
6539 }
6540 };
6541
6542 inline constexpr includes_fn includes{};
6543
6544 struct merge_fn
6545 {
6546 template <class I1, class S1, class I2, class S2, class O, class Comp = ranges::less, class Proj1 = etl::identity, class Proj2 = etl::identity,
6547 typename = etl::enable_if_t<!etl::is_range_v<I1>>>
6548 constexpr ranges::merge_result<I1, I2, O> operator()(I1 first1, S1 last1, I2 first2, S2 last2, O result, Comp comp = {}, Proj1 proj1 = {},
6549 Proj2 proj2 = {}) const
6550 {
6551 while (first1 != last1 && first2 != last2)
6552 {
6553 if (etl::invoke(comp, etl::invoke(proj2, *first2), etl::invoke(proj1, *first1)))
6554 {
6555 *result = *first2;
6556 ++first2;
6557 }
6558 else
6559 {
6560 *result = *first1;
6561 ++first1;
6562 }
6563 ++result;
6564 }
6565
6566 while (first1 != last1)
6567 {
6568 *result = *first1;
6569 ++first1;
6570 ++result;
6571 }
6572
6573 while (first2 != last2)
6574 {
6575 *result = *first2;
6576 ++first2;
6577 ++result;
6578 }
6579
6580 return {etl::move(first1), etl::move(first2), etl::move(result)};
6581 }
6582
6583 template <class R1, class R2, class O, class Comp = ranges::less, class Proj1 = etl::identity, class Proj2 = etl::identity,
6584 typename = etl::enable_if_t<etl::is_range_v<R1>>>
6585 constexpr ranges::merge_result<ranges::borrowed_iterator_t<R1>, ranges::borrowed_iterator_t<R2>, O>
6586 operator()(R1&& r1, R2&& r2, O result, Comp comp = {}, Proj1 proj1 = {}, Proj2 proj2 = {}) const
6587 {
6588 return (*this)(ranges::begin(r1), ranges::end(r1), ranges::begin(r2), ranges::end(r2), etl::move(result), etl::move(comp), etl::move(proj1),
6589 etl::move(proj2));
6590 }
6591 };
6592
6593 inline constexpr merge_fn merge{};
6594
6595 struct inplace_merge_fn
6596 {
6597 template <class I, class S, class Comp = ranges::less, class Proj = etl::identity, typename = etl::enable_if_t<!etl::is_range_v<I>>>
6598 constexpr I operator()(I first, I middle, S last, Comp comp = {}, Proj proj = {}) const
6599 {
6600 I last_it = ranges::next(first, last);
6601
6602 if (first == middle || middle == last_it)
6603 {
6604 return last_it;
6605 }
6606
6607 inplace_merge_impl(first, middle, last_it, comp, proj, etl::distance(first, middle), etl::distance(middle, last_it));
6608
6609 return last_it;
6610 }
6611
6612 template <class R, class Comp = ranges::less, class Proj = etl::identity, typename = etl::enable_if_t<etl::is_range_v<R>>>
6613 constexpr ranges::borrowed_iterator_t<R> operator()(R&& r, ranges::iterator_t<R> middle, Comp comp = {}, Proj proj = {}) const
6614 {
6615 return (*this)(ranges::begin(r), etl::move(middle), ranges::end(r), etl::move(comp), etl::move(proj));
6616 }
6617
6618 private:
6619
6620 template <class I, class Comp, class Proj>
6621 static constexpr void inplace_merge_impl(I first, I middle, I last, Comp& comp, Proj& proj,
6622 typename etl::iterator_traits<I>::difference_type len1,
6623 typename etl::iterator_traits<I>::difference_type len2)
6624 {
6625 if (len1 == 0 || len2 == 0)
6626 {
6627 return;
6628 }
6629
6630 if (len1 + len2 == 2)
6631 {
6632 if (etl::invoke(comp, etl::invoke(proj, *middle), etl::invoke(proj, *first)))
6633 {
6634 etl::iter_swap(first, middle);
6635 }
6636 return;
6637 }
6638
6639 I first_cut;
6640 I second_cut;
6641 typename etl::iterator_traits<I>::difference_type new_len1;
6642 typename etl::iterator_traits<I>::difference_type new_len2;
6643
6644 if (len1 > len2)
6645 {
6646 new_len1 = len1 / 2;
6647 first_cut = ranges::next(first, new_len1);
6648 second_cut = ranges::lower_bound(middle, last, etl::invoke(proj, *first_cut), etl::ref(comp), etl::ref(proj));
6649 new_len2 = etl::distance(middle, second_cut);
6650 }
6651 else
6652 {
6653 new_len2 = len2 / 2;
6654 second_cut = ranges::next(middle, new_len2);
6655 first_cut = ranges::upper_bound(first, middle, etl::invoke(proj, *second_cut), etl::ref(comp), etl::ref(proj));
6656 new_len1 = etl::distance(first, first_cut);
6657 }
6658
6659 I new_middle;
6660 // Due to a non-standard etl::rotate implementation, we need to handle
6661 // the case where one of the cuts is the middle separately to avoid
6662 // returning an iterator outside of [first, last)
6663 // As soon as etl::rotate is fixed to return an iterator in the middle
6664 // of the rotated range, this can be simplified to just calling
6665 // etl::rotate
6666 if (first_cut == middle)
6667 {
6668 new_middle = second_cut;
6669 }
6670 else if (second_cut == middle)
6671 {
6672 new_middle = first_cut;
6673 }
6674 else
6675 {
6676 new_middle = etl::rotate(first_cut, middle, second_cut);
6677 }
6678
6679 inplace_merge_impl(first, first_cut, new_middle, comp, proj, new_len1, new_len2);
6680 inplace_merge_impl(new_middle, second_cut, last, comp, proj, len1 - new_len1, len2 - new_len2);
6681 }
6682 };
6683
6684 inline constexpr inplace_merge_fn inplace_merge{};
6685
6686 struct set_union_fn
6687 {
6688 template <class I1, class S1, class I2, class S2, class O, class Comp = ranges::less, class Proj1 = etl::identity, class Proj2 = etl::identity,
6689 typename = etl::enable_if_t<!etl::is_range_v<I1>>>
6690 constexpr ranges::set_union_result<I1, I2, O> operator()(I1 first1, S1 last1, I2 first2, S2 last2, O result, Comp comp = {}, Proj1 proj1 = {},
6691 Proj2 proj2 = {}) const
6692 {
6693 while (first1 != last1 && first2 != last2)
6694 {
6695 if (etl::invoke(comp, etl::invoke(proj1, *first1), etl::invoke(proj2, *first2)))
6696 {
6697 *result = *first1;
6698 ++first1;
6699 }
6700 else if (etl::invoke(comp, etl::invoke(proj2, *first2), etl::invoke(proj1, *first1)))
6701 {
6702 *result = *first2;
6703 ++first2;
6704 }
6705 else
6706 {
6707 *result = *first1;
6708 ++first1;
6709 ++first2;
6710 }
6711 ++result;
6712 }
6713
6714 while (first1 != last1)
6715 {
6716 *result = *first1;
6717 ++first1;
6718 ++result;
6719 }
6720
6721 while (first2 != last2)
6722 {
6723 *result = *first2;
6724 ++first2;
6725 ++result;
6726 }
6727
6728 return {etl::move(first1), etl::move(first2), etl::move(result)};
6729 }
6730
6731 template <class R1, class R2, class O, class Comp = ranges::less, class Proj1 = etl::identity, class Proj2 = etl::identity,
6732 typename = etl::enable_if_t<etl::is_range_v<R1>>>
6733 constexpr ranges::set_union_result<ranges::borrowed_iterator_t<R1>, ranges::borrowed_iterator_t<R2>, O>
6734 operator()(R1&& r1, R2&& r2, O result, Comp comp = {}, Proj1 proj1 = {}, Proj2 proj2 = {}) const
6735 {
6736 return (*this)(ranges::begin(r1), ranges::end(r1), ranges::begin(r2), ranges::end(r2), etl::move(result), etl::move(comp), etl::move(proj1),
6737 etl::move(proj2));
6738 }
6739 };
6740
6741 inline constexpr set_union_fn set_union{};
6742
6743 struct set_intersection_fn
6744 {
6745 template <class I1, class S1, class I2, class S2, class O, class Comp = ranges::less, class Proj1 = etl::identity, class Proj2 = etl::identity,
6746 typename = etl::enable_if_t<!etl::is_range_v<I1>>>
6747 constexpr ranges::set_intersection_result<I1, I2, O> operator()(I1 first1, S1 last1, I2 first2, S2 last2, O result, Comp comp = {},
6748 Proj1 proj1 = {}, Proj2 proj2 = {}) const
6749 {
6750 while (first1 != last1 && first2 != last2)
6751 {
6752 if (etl::invoke(comp, etl::invoke(proj1, *first1), etl::invoke(proj2, *first2)))
6753 {
6754 ++first1;
6755 }
6756 else if (etl::invoke(comp, etl::invoke(proj2, *first2), etl::invoke(proj1, *first1)))
6757 {
6758 ++first2;
6759 }
6760 else
6761 {
6762 *result = *first1;
6763 ++first1;
6764 ++first2;
6765 ++result;
6766 }
6767 }
6768
6769 return {etl::move(first1), etl::move(first2), etl::move(result)};
6770 }
6771
6772 template <class R1, class R2, class O, class Comp = ranges::less, class Proj1 = etl::identity, class Proj2 = etl::identity,
6773 typename = etl::enable_if_t<etl::is_range_v<R1>>>
6774 constexpr ranges::set_intersection_result< ranges::borrowed_iterator_t<R1>, ranges::borrowed_iterator_t<R2>, O>
6775 operator()(R1&& r1, R2&& r2, O result, Comp comp = {}, Proj1 proj1 = {}, Proj2 proj2 = {}) const
6776 {
6777 return (*this)(ranges::begin(r1), ranges::end(r1), ranges::begin(r2), ranges::end(r2), etl::move(result), etl::move(comp), etl::move(proj1),
6778 etl::move(proj2));
6779 }
6780 };
6781
6782 inline constexpr set_intersection_fn set_intersection{};
6783
6784 struct set_difference_fn
6785 {
6786 template <class I1, class S1, class I2, class S2, class O, class Comp = ranges::less, class Proj1 = etl::identity, class Proj2 = etl::identity,
6787 typename = etl::enable_if_t<!etl::is_range_v<I1>>>
6788 constexpr ranges::set_difference_result<I1, O> operator()(I1 first1, S1 last1, I2 first2, S2 last2, O result, Comp comp = {}, Proj1 proj1 = {},
6789 Proj2 proj2 = {}) const
6790 {
6791 while (first1 != last1 && first2 != last2)
6792 {
6793 if (etl::invoke(comp, etl::invoke(proj1, *first1), etl::invoke(proj2, *first2)))
6794 {
6795 *result = *first1;
6796 ++first1;
6797 ++result;
6798 }
6799 else if (etl::invoke(comp, etl::invoke(proj2, *first2), etl::invoke(proj1, *first1)))
6800 {
6801 ++first2;
6802 }
6803 else
6804 {
6805 ++first1;
6806 ++first2;
6807 }
6808 }
6809
6810 while (first1 != last1)
6811 {
6812 *result = *first1;
6813 ++first1;
6814 ++result;
6815 }
6816
6817 return {etl::move(first1), etl::move(result)};
6818 }
6819
6820 template <class R1, class R2, class O, class Comp = ranges::less, class Proj1 = etl::identity, class Proj2 = etl::identity,
6821 typename = etl::enable_if_t<etl::is_range_v<R1>>>
6822 constexpr ranges::set_difference_result<ranges::borrowed_iterator_t<R1>, O> operator()(R1&& r1, R2&& r2, O result, Comp comp = {},
6823 Proj1 proj1 = {}, Proj2 proj2 = {}) const
6824 {
6825 return (*this)(ranges::begin(r1), ranges::end(r1), ranges::begin(r2), ranges::end(r2), etl::move(result), etl::move(comp), etl::move(proj1),
6826 etl::move(proj2));
6827 }
6828 };
6829
6830 inline constexpr set_difference_fn set_difference{};
6831
6832 struct set_symmetric_difference_fn
6833 {
6834 template <class I1, class S1, class I2, class S2, class O, class Comp = ranges::less, class Proj1 = etl::identity, class Proj2 = etl::identity,
6835 typename = etl::enable_if_t<!etl::is_range_v<I1>>>
6836 constexpr ranges::set_symmetric_difference_result<I1, I2, O> operator()(I1 first1, S1 last1, I2 first2, S2 last2, O result, Comp comp = {},
6837 Proj1 proj1 = {}, Proj2 proj2 = {}) const
6838 {
6839 while (first1 != last1 && first2 != last2)
6840 {
6841 if (etl::invoke(comp, etl::invoke(proj1, *first1), etl::invoke(proj2, *first2)))
6842 {
6843 *result = *first1;
6844 ++first1;
6845 ++result;
6846 }
6847 else if (etl::invoke(comp, etl::invoke(proj2, *first2), etl::invoke(proj1, *first1)))
6848 {
6849 *result = *first2;
6850 ++first2;
6851 ++result;
6852 }
6853 else
6854 {
6855 ++first1;
6856 ++first2;
6857 }
6858 }
6859
6860 while (first1 != last1)
6861 {
6862 *result = *first1;
6863 ++first1;
6864 ++result;
6865 }
6866
6867 while (first2 != last2)
6868 {
6869 *result = *first2;
6870 ++first2;
6871 ++result;
6872 }
6873
6874 return {etl::move(first1), etl::move(first2), etl::move(result)};
6875 }
6876
6877 template <class R1, class R2, class O, class Comp = ranges::less, class Proj1 = etl::identity, class Proj2 = etl::identity,
6878 typename = etl::enable_if_t<etl::is_range_v<R1>>>
6879 constexpr ranges::set_symmetric_difference_result< ranges::borrowed_iterator_t<R1>, ranges::borrowed_iterator_t<R2>, O>
6880 operator()(R1&& r1, R2&& r2, O result, Comp comp = {}, Proj1 proj1 = {}, Proj2 proj2 = {}) const
6881 {
6882 return (*this)(ranges::begin(r1), ranges::end(r1), ranges::begin(r2), ranges::end(r2), etl::move(result), etl::move(comp), etl::move(proj1),
6883 etl::move(proj2));
6884 }
6885 };
6886
6887 inline constexpr set_symmetric_difference_fn set_symmetric_difference{};
6888
6889 struct make_heap_fn
6890 {
6891 private:
6892
6893 template <class I, class Comp, class Proj>
6894 static constexpr void sift_down(I first, typename etl::iterator_traits<I>::difference_type index,
6895 typename etl::iterator_traits<I>::difference_type length, Comp& comp, Proj& proj)
6896 {
6897 while (true)
6898 {
6899 auto child = 2 * index + 1;
6900
6901 if (child >= length)
6902 {
6903 break;
6904 }
6905
6906 if ((child + 1 < length) && etl::invoke(comp, etl::invoke(proj, *(first + child)), etl::invoke(proj, *(first + (child + 1)))))
6907 {
6908 ++child;
6909 }
6910
6911 if (!etl::invoke(comp, etl::invoke(proj, *(first + index)), etl::invoke(proj, *(first + child))))
6912 {
6913 break;
6914 }
6915
6916 etl::iter_swap(first + index, first + child);
6917 index = child;
6918 }
6919 }
6920
6921 public:
6922
6923 template <class I, class S, class Comp = ranges::less, class Proj = etl::identity, typename = etl::enable_if_t<!etl::is_range_v<I>>>
6924 constexpr I operator()(I first, S last, Comp comp = {}, Proj proj = {}) const
6925 {
6926 I last_it = ranges::next(first, last);
6927
6928 auto length = etl::distance(first, last_it);
6929
6930 if (length < 2)
6931 {
6932 return last_it;
6933 }
6934
6935 auto parent = (length - 2) / 2;
6936
6937 while (true)
6938 {
6939 sift_down(first, parent, length, comp, proj);
6940
6941 if (parent == 0)
6942 {
6943 break;
6944 }
6945
6946 --parent;
6947 }
6948
6949 return last_it;
6950 }
6951
6952 template <class R, class Comp = ranges::less, class Proj = etl::identity, typename = etl::enable_if_t<etl::is_range_v<R>>>
6953 constexpr ranges::borrowed_iterator_t<R> operator()(R&& r, Comp comp = {}, Proj proj = {}) const
6954 {
6955 return (*this)(ranges::begin(r), ranges::end(r), etl::move(comp), etl::move(proj));
6956 }
6957 };
6958
6959 inline constexpr make_heap_fn make_heap{};
6960
6961 struct push_heap_fn
6962 {
6963 template <class I, class S, class Comp = ranges::less, class Proj = etl::identity, typename = etl::enable_if_t<!etl::is_range_v<I>>>
6964 constexpr I operator()(I first, S last, Comp comp = {}, Proj proj = {}) const
6965 {
6966 ETL_STATIC_ASSERT(etl::is_random_access_iterator<I>::value, "push_heap requires random access iterators");
6967
6968 I last_it = ranges::next(first, last);
6969
6970 auto length = etl::distance(first, last_it);
6971
6972 if (length < 2)
6973 {
6974 return last_it;
6975 }
6976
6977 auto value_index = length - 1;
6978 auto parent = (value_index - 1) / 2;
6979 auto value = etl::move(*(first + value_index));
6980
6981 while ((value_index > 0) && etl::invoke(comp, etl::invoke(proj, *(first + parent)), etl::invoke(proj, value)))
6982 {
6983 *(first + value_index) = etl::move(*(first + parent));
6984 value_index = parent;
6985 parent = (value_index - 1) / 2;
6986 }
6987
6988 *(first + value_index) = etl::move(value);
6989
6990 return last_it;
6991 }
6992
6993 template <class R, class Comp = ranges::less, class Proj = etl::identity, typename = etl::enable_if_t<etl::is_range_v<R>>>
6994 constexpr ranges::borrowed_iterator_t<R> operator()(R&& r, Comp comp = {}, Proj proj = {}) const
6995 {
6996 return (*this)(ranges::begin(r), ranges::end(r), etl::move(comp), etl::move(proj));
6997 }
6998 };
6999
7000 inline constexpr push_heap_fn push_heap{};
7001
7002 struct pop_heap_fn
7003 {
7004 private:
7005
7006 template <class I, class Comp, class Proj>
7007 static constexpr void sift_down(I first, typename etl::iterator_traits<I>::difference_type index,
7008 typename etl::iterator_traits<I>::difference_type length, Comp& comp, Proj& proj)
7009 {
7010 while (true)
7011 {
7012 auto child = 2 * index + 1;
7013
7014 if (child >= length)
7015 {
7016 break;
7017 }
7018
7019 if ((child + 1 < length) && etl::invoke(comp, etl::invoke(proj, *(first + child)), etl::invoke(proj, *(first + (child + 1)))))
7020 {
7021 ++child;
7022 }
7023
7024 if (!etl::invoke(comp, etl::invoke(proj, *(first + index)), etl::invoke(proj, *(first + child))))
7025 {
7026 break;
7027 }
7028
7029 etl::iter_swap(first + index, first + child);
7030 index = child;
7031 }
7032 }
7033
7034 public:
7035
7036 template <class I, class S, class Comp = ranges::less, class Proj = etl::identity, typename = etl::enable_if_t<!etl::is_range_v<I>>>
7037 constexpr I operator()(I first, S last, Comp comp = {}, Proj proj = {}) const
7038 {
7039 ETL_STATIC_ASSERT(etl::is_random_access_iterator<I>::value, "pop_heap requires random access iterators");
7040
7042
7043 I last_it = ranges::next(first, last);
7044
7045 auto length = etl::distance(first, last_it);
7046
7047 if (length < 2)
7048 {
7049 return last_it;
7050 }
7051
7052 --last_it;
7053
7054 etl::iter_swap(first, last_it);
7055
7056 sift_down(first, decltype(length)(0), etl::distance(first, last_it), comp, proj);
7057
7058 return ranges::next(first, last);
7059
7061 }
7062
7063 template <class R, class Comp = ranges::less, class Proj = etl::identity, typename = etl::enable_if_t<etl::is_range_v<R>>>
7064 constexpr ranges::borrowed_iterator_t<R> operator()(R&& r, Comp comp = {}, Proj proj = {}) const
7065 {
7066 return (*this)(ranges::begin(r), ranges::end(r), etl::move(comp), etl::move(proj));
7067 }
7068 };
7069
7070 inline constexpr pop_heap_fn pop_heap{};
7071
7072 struct is_heap_until_fn
7073 {
7074 template <class I, class S, class Comp = ranges::less, class Proj = etl::identity, typename = etl::enable_if_t<!etl::is_range_v<I>>>
7075 constexpr I operator()(I first, S last, Comp comp = {}, Proj proj = {}) const
7076 {
7077 ETL_STATIC_ASSERT(etl::is_random_access_iterator<I>::value, "is_heap_until requires random access iterators");
7078
7079 I last_it = ranges::next(first, last);
7080
7081 auto length = etl::distance(first, last_it);
7082
7083 decltype(length) parent = 0;
7084
7085 for (decltype(length) child = 1; child < length; ++child)
7086 {
7087 if (etl::invoke(comp, etl::invoke(proj, *(first + parent)), etl::invoke(proj, *(first + child))))
7088 {
7089 return first + child;
7090 }
7091
7092 if ((child & 1) == 0)
7093 {
7094 ++parent;
7095 }
7096 }
7097
7098 return last_it;
7099 }
7100
7101 template <class R, class Comp = ranges::less, class Proj = etl::identity, typename = etl::enable_if_t<etl::is_range_v<R>>>
7102 constexpr ranges::borrowed_iterator_t<R> operator()(R&& r, Comp comp = {}, Proj proj = {}) const
7103 {
7104 return (*this)(ranges::begin(r), ranges::end(r), etl::move(comp), etl::move(proj));
7105 }
7106 };
7107
7108 inline constexpr is_heap_until_fn is_heap_until{};
7109
7110 struct is_heap_fn
7111 {
7112 template <class I, class S, class Comp = ranges::less, class Proj = etl::identity, typename = etl::enable_if_t<!etl::is_range_v<I>>>
7113 constexpr bool operator()(I first, S last, Comp comp = {}, Proj proj = {}) const
7114 {
7115 return ranges::is_heap_until(first, last, etl::ref(comp), etl::ref(proj)) == last;
7116 }
7117
7118 template <class R, class Comp = ranges::less, class Proj = etl::identity, typename = etl::enable_if_t<etl::is_range_v<R>>>
7119 constexpr bool operator()(R&& r, Comp comp = {}, Proj proj = {}) const
7120 {
7121 return (*this)(ranges::begin(r), ranges::end(r), etl::move(comp), etl::move(proj));
7122 }
7123 };
7124
7125 inline constexpr is_heap_fn is_heap{};
7126
7127 struct sort_heap_fn
7128 {
7129 template <class I, class S, class Comp = ranges::less, class Proj = etl::identity, typename = etl::enable_if_t<!etl::is_range_v<I>>>
7130 constexpr I operator()(I first, S last, Comp comp = {}, Proj proj = {}) const
7131 {
7132 ETL_STATIC_ASSERT(etl::is_random_access_iterator<I>::value, "sort_heap requires random access iterators");
7133
7134 I last_it = ranges::next(first, last);
7135 I current_last = last_it;
7136
7137 while (first != current_last)
7138 {
7139 ranges::pop_heap(first, current_last, comp, proj);
7140 --current_last;
7141 }
7142
7143 return last_it;
7144 }
7145
7146 template <class R, class Comp = ranges::less, class Proj = etl::identity, typename = etl::enable_if_t<etl::is_range_v<R>>>
7147 constexpr ranges::borrowed_iterator_t<R> operator()(R&& r, Comp comp = {}, Proj proj = {}) const
7148 {
7149 return (*this)(ranges::begin(r), ranges::end(r), etl::move(comp), etl::move(proj));
7150 }
7151 };
7152
7153 inline constexpr sort_heap_fn sort_heap{};
7154
7155 struct min_fn
7156 {
7157 template <class T, class Comp = ranges::less, class Proj = etl::identity>
7158 constexpr const T& operator()(const T& a, const T& b, Comp comp = {}, Proj proj = {}) const
7159 {
7160 return etl::invoke(comp, etl::invoke(proj, b), etl::invoke(proj, a)) ? b : a;
7161 }
7162
7163 #if ETL_HAS_INITIALIZER_LIST
7164 template <class T, class Comp = ranges::less, class Proj = etl::identity>
7165 constexpr T operator()(std::initializer_list<T> r, Comp comp = {}, Proj proj = {}) const
7166 {
7167 auto first = r.begin();
7168 auto last = r.end();
7169
7170 auto smallest = first;
7171 while (++first != last)
7172 {
7173 if (etl::invoke(comp, etl::invoke(proj, *first), etl::invoke(proj, *smallest)))
7174 {
7175 smallest = first;
7176 }
7177 }
7178 return *smallest;
7179 }
7180 #endif
7181
7182 template <class R, class Comp = ranges::less, class Proj = etl::identity, typename = etl::enable_if_t<etl::is_range_v<R>>>
7183 constexpr ranges::range_value_t<R> operator()(R&& r, Comp comp = {}, Proj proj = {}) const
7184 {
7185 auto first = ranges::begin(r);
7186 auto last = ranges::end(r);
7187
7188 auto smallest = first;
7189 while (++first != last)
7190 {
7191 if (etl::invoke(comp, etl::invoke(proj, *first), etl::invoke(proj, *smallest)))
7192 {
7193 smallest = first;
7194 }
7195 }
7196 return *smallest;
7197 }
7198 };
7199
7200 inline constexpr min_fn min{};
7201
7202 struct min_element_fn
7203 {
7204 template <class I, class S, class Comp = ranges::less, class Proj = etl::identity, typename = etl::enable_if_t<!etl::is_range_v<I>>>
7205 constexpr I operator()(I first, S last, Comp comp = {}, Proj proj = {}) const
7206 {
7207 if (first == last)
7208 {
7209 return first;
7210 }
7211
7212 I smallest = first;
7213 ++first;
7214
7215 for (; first != last; ++first)
7216 {
7217 if (etl::invoke(comp, etl::invoke(proj, *first), etl::invoke(proj, *smallest)))
7218 {
7219 smallest = first;
7220 }
7221 }
7222
7223 return smallest;
7224 }
7225
7226 template <class R, class Comp = ranges::less, class Proj = etl::identity, typename = etl::enable_if_t<etl::is_range_v<R>>>
7227 constexpr ranges::borrowed_iterator_t<R> operator()(R&& r, Comp comp = {}, Proj proj = {}) const
7228 {
7229 return (*this)(ranges::begin(r), ranges::end(r), etl::move(comp), etl::move(proj));
7230 }
7231 };
7232
7233 inline constexpr min_element_fn min_element{};
7234
7235 struct max_fn
7236 {
7237 template <class T, class Comp = ranges::less, class Proj = etl::identity>
7238 constexpr const T& operator()(const T& a, const T& b, Comp comp = {}, Proj proj = {}) const
7239 {
7240 return etl::invoke(comp, etl::invoke(proj, a), etl::invoke(proj, b)) ? b : a;
7241 }
7242
7243 #if ETL_HAS_INITIALIZER_LIST
7244 template <class T, class Comp = ranges::less, class Proj = etl::identity>
7245 constexpr T operator()(std::initializer_list<T> r, Comp comp = {}, Proj proj = {}) const
7246 {
7247 auto first = r.begin();
7248 auto last = r.end();
7249
7250 auto largest = first;
7251 while (++first != last)
7252 {
7253 if (etl::invoke(comp, etl::invoke(proj, *largest), etl::invoke(proj, *first)))
7254 {
7255 largest = first;
7256 }
7257 }
7258 return *largest;
7259 }
7260 #endif
7261
7262 template <class R, class Comp = ranges::less, class Proj = etl::identity, typename = etl::enable_if_t<etl::is_range_v<R>>>
7263 constexpr ranges::range_value_t<R> operator()(R&& r, Comp comp = {}, Proj proj = {}) const
7264 {
7265 auto first = ranges::begin(r);
7266 auto last = ranges::end(r);
7267
7268 auto largest = first;
7269 while (++first != last)
7270 {
7271 if (etl::invoke(comp, etl::invoke(proj, *largest), etl::invoke(proj, *first)))
7272 {
7273 largest = first;
7274 }
7275 }
7276 return *largest;
7277 }
7278 };
7279
7280 inline constexpr max_fn max{};
7281
7282 struct max_element_fn
7283 {
7284 template <class I, class S, class Comp = ranges::less, class Proj = etl::identity, typename = etl::enable_if_t<!etl::is_range_v<I>>>
7285 constexpr I operator()(I first, S last, Comp comp = {}, Proj proj = {}) const
7286 {
7287 if (first == last)
7288 {
7289 return first;
7290 }
7291
7292 I largest = first;
7293 ++first;
7294
7295 for (; first != last; ++first)
7296 {
7297 if (etl::invoke(comp, etl::invoke(proj, *largest), etl::invoke(proj, *first)))
7298 {
7299 largest = first;
7300 }
7301 }
7302
7303 return largest;
7304 }
7305
7306 template <class R, class Comp = ranges::less, class Proj = etl::identity, typename = etl::enable_if_t<etl::is_range_v<R>>>
7307 constexpr ranges::borrowed_iterator_t<R> operator()(R&& r, Comp comp = {}, Proj proj = {}) const
7308 {
7309 return (*this)(ranges::begin(r), ranges::end(r), etl::move(comp), etl::move(proj));
7310 }
7311 };
7312
7313 inline constexpr max_element_fn max_element{};
7314
7315 struct minmax_fn
7316 {
7317 template <class T, class Comp = ranges::less, class Proj = etl::identity>
7318 constexpr ranges::minmax_result<const T&> operator()(const T& a, const T& b, Comp comp = {}, Proj proj = {}) const
7319 {
7320 if (etl::invoke(comp, etl::invoke(proj, b), etl::invoke(proj, a)))
7321 {
7322 return {b, a};
7323 }
7324 return {a, b};
7325 }
7326
7327 #if ETL_HAS_INITIALIZER_LIST
7328 template <class T, class Comp = ranges::less, class Proj = etl::identity>
7329 constexpr ranges::minmax_result<T> operator()(std::initializer_list<T> r, Comp comp = {}, Proj proj = {}) const
7330 {
7331 auto first = r.begin();
7332 auto last = r.end();
7333
7334 auto smallest = first;
7335 auto largest = first;
7336
7337 while (++first != last)
7338 {
7339 if (etl::invoke(comp, etl::invoke(proj, *first), etl::invoke(proj, *smallest)))
7340 {
7341 smallest = first;
7342 }
7343 if (etl::invoke(comp, etl::invoke(proj, *largest), etl::invoke(proj, *first)))
7344 {
7345 largest = first;
7346 }
7347 }
7348 return {*smallest, *largest};
7349 }
7350 #endif
7351
7352 template <class R, class Comp = ranges::less, class Proj = etl::identity, typename = etl::enable_if_t<etl::is_range_v<R>>>
7353 constexpr ranges::minmax_result<ranges::range_value_t<R>> operator()(R&& r, Comp comp = {}, Proj proj = {}) const
7354 {
7355 auto first = ranges::begin(r);
7356 auto last = ranges::end(r);
7357
7358 auto smallest = first;
7359 auto largest = first;
7360
7361 while (++first != last)
7362 {
7363 if (etl::invoke(comp, etl::invoke(proj, *first), etl::invoke(proj, *smallest)))
7364 {
7365 smallest = first;
7366 }
7367 if (etl::invoke(comp, etl::invoke(proj, *largest), etl::invoke(proj, *first)))
7368 {
7369 largest = first;
7370 }
7371 }
7372 return {*smallest, *largest};
7373 }
7374 };
7375
7376 inline constexpr minmax_fn minmax{};
7377
7378 struct minmax_element_fn
7379 {
7380 template <class I, class S, class Comp = ranges::less, class Proj = etl::identity, typename = etl::enable_if_t<!etl::is_range_v<I>>>
7381 constexpr ranges::minmax_element_result<I> operator()(I first, S last, Comp comp = {}, Proj proj = {}) const
7382 {
7383 if (first == last)
7384 {
7385 return {first, first};
7386 }
7387
7388 I smallest = first;
7389 I largest = first;
7390 ++first;
7391
7392 for (; first != last; ++first)
7393 {
7394 if (etl::invoke(comp, etl::invoke(proj, *first), etl::invoke(proj, *smallest)))
7395 {
7396 smallest = first;
7397 }
7398 if (etl::invoke(comp, etl::invoke(proj, *largest), etl::invoke(proj, *first)))
7399 {
7400 largest = first;
7401 }
7402 }
7403
7404 return {smallest, largest};
7405 }
7406
7407 template <class R, class Comp = ranges::less, class Proj = etl::identity, typename = etl::enable_if_t<etl::is_range_v<R>>>
7408 constexpr ranges::minmax_element_result<ranges::borrowed_iterator_t<R>> operator()(R&& r, Comp comp = {}, Proj proj = {}) const
7409 {
7410 return (*this)(ranges::begin(r), ranges::end(r), etl::move(comp), etl::move(proj));
7411 }
7412 };
7413
7414 inline constexpr minmax_element_fn minmax_element{};
7415
7416 struct clamp_fn
7417 {
7418 template <class T, class Comp = ranges::less, class Proj = etl::identity>
7419 constexpr const T& operator()(const T& value, const T& low, const T& high, Comp comp = {}, Proj proj = {}) const
7420 {
7421 auto&& projected_value = etl::invoke(proj, value);
7422
7423 return etl::invoke(comp, projected_value, etl::invoke(proj, low)) ? low
7424 : etl::invoke(comp, etl::invoke(proj, high), projected_value) ? high
7425 : value;
7426 }
7427 };
7428
7429 inline constexpr clamp_fn clamp{};
7430
7431 struct next_permutation_fn
7432 {
7433 template <class I, class S, class Comp = ranges::less, class Proj = etl::identity, typename = etl::enable_if_t<!etl::is_range_v<I>>>
7434 constexpr ranges::next_permutation_result<I> operator()(I first, S last, Comp comp = {}, Proj proj = {}) const
7435 {
7436 I last_it = ranges::next(first, last);
7437
7438 // Empty or single-element range: already at last permutation
7439 if (first == last_it)
7440 {
7441 return {etl::move(last_it), false};
7442 }
7443
7444 I i = last_it;
7445 --i;
7446
7447 if (i == first)
7448 {
7449 return {etl::move(last_it), false};
7450 }
7451
7452 for (;;)
7453 {
7454 I i1 = i;
7455 --i;
7456
7457 // Find the rightmost element where projected *i < projected *i1
7458 if (etl::invoke(comp, etl::invoke(proj, *i), etl::invoke(proj, *i1)))
7459 {
7460 // Find the rightmost element j where projected *j > projected *i
7461 I j = last_it;
7462 while (!etl::invoke(comp, etl::invoke(proj, *i), etl::invoke(proj, *--j)))
7463 {
7464 }
7465
7466 etl::iter_swap(i, j);
7467
7468 // Reverse from i1 to last
7469 I left = i1;
7470 I right = last_it;
7471 while (left != right && left != --right)
7472 {
7473 etl::iter_swap(left, right);
7474 ++left;
7475 }
7476
7477 return {etl::move(last_it), true};
7478 }
7479
7480 if (i == first)
7481 {
7482 // Already at last (ascending) permutation: wrap to first
7483 // (descending)
7484 I left = first;
7485 I right = last_it;
7486 while (left != right && left != --right)
7487 {
7488 etl::iter_swap(left, right);
7489 ++left;
7490 }
7491
7492 return {etl::move(last_it), false};
7493 }
7494 }
7495 }
7496
7497 template <class R, class Comp = ranges::less, class Proj = etl::identity, typename = etl::enable_if_t<etl::is_range_v<R>>>
7498 constexpr ranges::next_permutation_result<ranges::borrowed_iterator_t<R>> operator()(R&& r, Comp comp = {}, Proj proj = {}) const
7499 {
7500 return (*this)(ranges::begin(r), ranges::end(r), etl::move(comp), etl::move(proj));
7501 }
7502 };
7503
7504 inline constexpr next_permutation_fn next_permutation{};
7505
7506 struct prev_permutation_fn
7507 {
7508 template <class I, class S, class Comp = ranges::less, class Proj = etl::identity, typename = etl::enable_if_t<!etl::is_range_v<I>>>
7509 constexpr ranges::prev_permutation_result<I> operator()(I first, S last, Comp comp = {}, Proj proj = {}) const
7510 {
7511 I last_it = ranges::next(first, last);
7512
7513 // Empty or single-element range: already at last permutation
7514 if (first == last_it)
7515 {
7516 return {etl::move(last_it), false};
7517 }
7518
7519 I i = last_it;
7520 --i;
7521
7522 if (i == first)
7523 {
7524 return {etl::move(last_it), false};
7525 }
7526
7527 for (;;)
7528 {
7529 I i1 = i;
7530 --i;
7531
7532 // Find the rightmost element where projected *i > projected *i1
7533 if (etl::invoke(comp, etl::invoke(proj, *i1), etl::invoke(proj, *i)))
7534 {
7535 // Find the rightmost element j where projected *j < projected *i
7536 I j = last_it;
7537 while (!etl::invoke(comp, etl::invoke(proj, *--j), etl::invoke(proj, *i)))
7538 {
7539 }
7540
7541 etl::iter_swap(i, j);
7542
7543 // Reverse from i1 to last
7544 I left = i1;
7545 I right = last_it;
7546 while (left != right && left != --right)
7547 {
7548 etl::iter_swap(left, right);
7549 ++left;
7550 }
7551
7552 return {etl::move(last_it), true};
7553 }
7554
7555 if (i == first)
7556 {
7557 // Already at last (descending) permutation: wrap to first
7558 // (ascending)
7559 I left = first;
7560 I right = last_it;
7561 while (left != right && left != --right)
7562 {
7563 etl::iter_swap(left, right);
7564 ++left;
7565 }
7566
7567 return {etl::move(last_it), false};
7568 }
7569 }
7570 }
7571
7572 template <class R, class Comp = ranges::less, class Proj = etl::identity, typename = etl::enable_if_t<etl::is_range_v<R>>>
7573 constexpr ranges::prev_permutation_result<ranges::borrowed_iterator_t<R>> operator()(R&& r, Comp comp = {}, Proj proj = {}) const
7574 {
7575 return (*this)(ranges::begin(r), ranges::end(r), etl::move(comp), etl::move(proj));
7576 }
7577 };
7578
7579 inline constexpr prev_permutation_fn prev_permutation{};
7580 } // namespace ranges
7581#endif
7582
7583} // namespace etl
7584
7585#include "private/minmax_pop.h"
7586
7587#endif
Definition functional.h:358
Definition iterator.h:310
ETL_CONSTEXPR T clamp(const T &value, const T &low, const T &high, TCompare compare)
Definition algorithm.h:2353
ETL_CONSTEXPR20 void shell_sort(TIterator first, TIterator last)
Definition algorithm.h:3228
ETL_CONSTEXPR14 TOutputIterator copy_if(TIterator begin, TIterator end, TOutputIterator out, TUnaryPredicate predicate)
Definition algorithm.h:2177
void inplace_merge(TBidirectionalIterator first, TBidirectionalIterator middle, TBidirectionalIterator last, TCompare compare)
Definition algorithm.h:2595
ETL_CONSTEXPR14 ETL_OR_STD::pair< TDestinationTrue, TDestinationFalse > partition_transform(TSource begin, TSource end, TDestinationTrue destination_true, TDestinationFalse destination_false, TUnaryFunctionTrue function_true, TUnaryFunctionFalse function_false, TUnaryPredicate predicate)
Definition algorithm.h:3120
ETL_NODISCARD ETL_CONSTEXPR14 bool any_of(TIterator begin, TIterator end, TUnaryPredicate predicate)
Definition algorithm.h:2210
ETL_NODISCARD ETL_CONSTEXPR14 TIterator min_element(TIterator begin, TIterator end, TCompare compare)
Definition algorithm.h:1479
ETL_CONSTEXPR14 TOutputIterator transform_n_if(TInputIterator i_begin, TSize n, TOutputIterator o_begin, TUnaryFunction function, TUnaryPredicate predicate)
Definition algorithm.h:3072
ETL_CONSTEXPR14 T accumulate(TIterator first, TIterator last, T sum)
Definition algorithm.h:2321
ETL_CONSTEXPR14 bool next_permutation(TIterator first, TIterator last, TCompare compare)
Definition algorithm.h:1938
ETL_NODISCARD ETL_CONSTEXPR14 bool all_of(TIterator begin, TIterator end, TUnaryPredicate predicate)
Definition algorithm.h:2199
ETL_NODISCARD ETL_CONSTEXPR14 ETL_OR_STD::pair< TIterator, TIterator > minmax_element(TIterator begin, TIterator end, TCompare compare)
Definition algorithm.h:1561
ETL_CONSTEXPR14 TOutputIterator transform_if(TInputIterator i_begin, const TInputIterator i_end, TOutputIterator o_begin, TUnaryFunction function, TUnaryPredicate predicate)
Definition algorithm.h:3027
ETL_CONSTEXPR14 TUnaryFunction for_each_if(TIterator begin, const TIterator end, TUnaryFunction function, TUnaryPredicate predicate)
Definition algorithm.h:2920
ETL_NODISCARD ETL_CONSTEXPR14 TIterator find_if_not(TIterator begin, TIterator end, TUnaryPredicate predicate)
Definition algorithm.h:1748
ETL_NODISCARD ETL_CONSTEXPR14 bool is_sorted(TIterator begin, TIterator end)
Definition algorithm.h:1669
ETL_CONSTEXPR14 TOutputIterator transform_s(TInputIterator i_begin, TInputIterator i_end, TOutputIterator o_begin, TOutputIterator o_end, TUnaryFunction function)
Definition algorithm.h:2979
ETL_CONSTEXPR14 TIterator remove(TIterator first, TIterator last, const T &value)
Definition algorithm.h:2381
ETL_CONSTEXPR14 TRandomAccessIterator partial_sort_copy(TInputIterator first, TInputIterator last, TRandomAccessIterator d_first, TRandomAccessIterator d_last, TCompare compare)
Definition algorithm.h:1136
ETL_CONSTEXPR14 TOutputIterator merge(TInputIterator1 first1, TInputIterator1 last1, TInputIterator2 first2, TInputIterator2 last2, TOutputIterator d_first, TCompare compare)
Definition algorithm.h:2543
ETL_CONSTEXPR14 void transform_n(TInputIterator i_begin, TSize n, TOutputIterator o_begin, TUnaryFunction function)
Definition algorithm.h:2999
ETL_CONSTEXPR14 TOutputIterator unique_copy(TInputIterator first, TInputIterator last, TOutputIterator d_first)
Definition algorithm.h:2485
ETL_CONSTEXPR14 ETL_OR_STD::pair< TDestinationTrue, TDestinationFalse > partition_move(TSource begin, TSource end, TDestinationTrue destination_true, TDestinationFalse destination_false, TUnaryPredicate predicate)
Definition algorithm.h:2149
ETL_CONSTEXPR14 TOutputIterator copy_n_if(TInputIterator i_begin, TSize n, TOutputIterator o_begin, TUnaryPredicate predicate)
Definition algorithm.h:2785
ETL_CONSTEXPR14 void insertion_sort(TIterator first, TIterator last)
Definition algorithm.h:3252
void sort(TIterator first, TIterator last, TCompare compare)
Definition algorithm.h:2277
ETL_NODISCARD ETL_CONSTEXPR14 bool is_unique_sorted(TIterator begin, TIterator end)
Definition algorithm.h:1727
ETL_CONSTEXPR14 TIterator unique(TIterator first, TIterator last)
Definition algorithm.h:2432
ETL_NODISCARD ETL_CONSTEXPR14 ETL_OR_STD::pair< const T &, const T & > minmax(const T &a, const T &b)
Definition algorithm.h:1608
ETL_NODISCARD ETL_CONSTEXPR14 TIterator is_sorted_until(TIterator begin, TIterator end, TCompare compare)
Definition algorithm.h:1630
ETL_CONSTEXPR14 etl::enable_if< etl::is_random_iterator< TInputIterator >::value &&etl::is_random_iterator< TOutputIterator >::value, TOutputIterator >::type copy_s(TInputIterator i_begin, TInputIterator i_end, TOutputIterator o_begin, TOutputIterator o_end)
Definition algorithm.h:2675
ETL_CONSTEXPR14 TIterator remove_if(TIterator first, TIterator last, TUnaryPredicate predicate)
Definition algorithm.h:2406
ETL_CONSTEXPR14 ETL_OR_STD::pair< TDestinationTrue, TDestinationFalse > partition_copy(TSource begin, TSource end, TDestinationTrue destination_true, TDestinationFalse destination_false, TUnaryPredicate predicate)
Definition algorithm.h:2121
ETL_CONSTEXPR14 TIterator for_each_n(TIterator begin, TSize n, TUnaryFunction function)
Definition algorithm.h:2940
ETL_NODISCARD ETL_CONSTEXPR14 TIterator binary_find(TIterator begin, TIterator end, const TValue &value)
Definition algorithm.h:2884
ETL_CONSTEXPR14 void heap_sort(TIterator first, TIterator last, TCompare compare)
Definition algorithm.h:3350
ETL_NODISCARD ETL_CONSTEXPR14 bool none_of(TIterator begin, TIterator end, TUnaryPredicate predicate)
Definition algorithm.h:2221
ETL_CONSTEXPR20 void selection_sort(TIterator first, TIterator last, TCompare compare)
Definition algorithm.h:3300
ETL_CONSTEXPR14 TOutputIterator copy_n_s(TInputIterator i_begin, TSize n, TOutputIterator o_begin, TOutputIterator o_end)
Definition algorithm.h:2725
ETL_NODISCARD ETL_CONSTEXPR14 TIterator is_unique_sorted_until(TIterator begin, TIterator end, TCompare compare)
Definition algorithm.h:1690
TOutputIterator move_s(TInputIterator i_begin, TInputIterator i_end, TOutputIterator o_begin, TOutputIterator o_end)
Definition algorithm.h:2870
ETL_CONSTEXPR14 TOutputIterator copy_if_s(TInputIterator i_begin, TInputIterator i_end, TOutputIterator o_begin, TOutputIterator o_end, TUnaryPredicate predicate)
Definition algorithm.h:2762
ETL_CONSTEXPR14 TIterator for_each_n_if(TIterator begin, TSize n, TUnaryFunction function, TUnaryPredicate predicate)
Definition algorithm.h:2957
void stable_sort(TIterator first, TIterator last, TCompare compare)
Definition algorithm.h:2299
ETL_NODISCARD ETL_CONSTEXPR14 bool is_partitioned(TIterator begin, TIterator end, TUnaryPredicate predicate)
Definition algorithm.h:2060
ETL_NODISCARD ETL_CONSTEXPR14 TIterator adjacent_find(TIterator first, TIterator last, TBinaryPredicate predicate)
Definition algorithm.h:1769
ETL_NODISCARD ETL_CONSTEXPR14 TIterator max_element(TIterator begin, TIterator end, TCompare compare)
Definition algorithm.h:1520
ETL_NODISCARD ETL_CONSTEXPR14 TIterator partition_point(TIterator begin, TIterator end, TUnaryPredicate predicate)
Definition algorithm.h:2091
ETL_NODISCARD ETL_CONSTEXPR14 bool is_permutation(TIterator1 begin1, TIterator1 end1, TIterator2 begin2)
Definition algorithm.h:1810
ETL_CONSTEXPR14 bool prev_permutation(TIterator first, TIterator last, TCompare compare)
Definition algorithm.h:1999
ETL_CONSTEXPR14 void partial_sort(TIterator first, TIterator middle, TIterator last, TCompare compare)
Definition algorithm.h:1090
#define ETL_ASSERT(b, e)
Definition error_handler.h:511
Definition exception.h:59
Definition function.h:94
ETL_CONSTEXPR14 void iota(TIterator first, TIterator last, T value)
Definition numeric.h:58
Definition absolute.h:40
ETL_CONSTEXPR14 void swap(etl::typed_storage_ext< T > &lhs, etl::typed_storage_ext< T > &rhs) ETL_NOEXCEPT
Swap two etl::typed_storage_ext.
Definition alignment.h:856
TIterator find_first_of(TIterator first, TIterator last, TPointer delimiters)
Find first of any of delimiters within the string.
Definition string_utilities.h:500
etl::enable_if< etl::is_random_access_iterator_concept< TIterator >::value, void >::type nth_element(TIterator first, TIterator nth, TIterator last, TCompare compare)
Definition algorithm.h:3742
ETL_CONSTEXPR14 TIterator stable_partition(TIterator first, TIterator last, TPredicate predicate)
Definition algorithm.h:3592
TContainer::iterator end(TContainer &container)
Definition iterator.h:1166
ETL_CONSTEXPR14 etl::enable_if< etl::is_forward_iterator< TIterator >::value, TIterator >::type partition(TIterator first, TIterator last, TPredicate predicate)
Returns the maximum value.
Definition algorithm.h:3529
TContainer::iterator begin(TContainer &container)
Definition iterator.h:1136
Definition compare.h:51
Definition functional.h:305
Definition iterator.h:130
Definition functional.h:201
Definition algorithm.h:120
Definition algorithm.h:110