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