Photon microGUI widgets library 0.6.0
algorithm.hpp
1#ifndef _STDEX_ALGORITHM_H
2#define _STDEX_ALGORITHM_H
3
4#if _MSC_VER > 1000
5#pragma once
6#endif // _MSC_VER > 1000
7
8// stdex includes
9#include "./iterator.hpp"
10
11// POSIX includes
12
13// std includes
14#include <algorithm>
15#include <cstddef> // std::size_t
16#include <cassert> // assert
17#include <cstdlib> // std::rand
18#include <map> // std::pair
19#include <functional> // std::less
20
21namespace stdex
22{
23 namespace algorithm_cpp11
24 {
25#ifndef STDEX_DO_NOT_ADD_CPP11_STD // define to exclude std implementations
26 using namespace std;
27#endif
28 }
29
30 namespace cstddef
31 {
32 typedef std::size_t size_t;
33 }
34
35 // Non-modifying sequence operations
36
37 namespace algorithm_cpp11
38 {
39 // all_of (C++11)
40 // checks if a predicate is true for all of the elements in a range
41 template<class _InputIt, class _UnaryPredicate>
42 inline
43 bool all_of(_InputIt _first,
44 typename detail::_if_iterator_cat_is_input<_InputIt>::type _last, _UnaryPredicate _p)
45 {
46 for (; _first != _last; ++_first) {
47 if (!_p(*_first)) {
48 return false;
49 }
50 }
51 return true;
52 }
53
54 // any_of (C++11)
55 // checks if a predicate is true for any of the elements in a range
56 template<class _InputIt, class _UnaryPredicate>
57 inline
58 bool any_of(_InputIt _first,
59 typename detail::_if_iterator_cat_is_input<_InputIt>::type _last, _UnaryPredicate _p)
60 {
61 return std::find_if(_first, _last, _p) != _last;
62 }
63
64 // none_of (C++11)
65 // checks if a predicate is true for none of the elements in a range
66 template<class _InputIt, class _UnaryPredicate>
67 inline
68 bool none_of(_InputIt _first,
69 typename detail::_if_iterator_cat_is_input<_InputIt>::type _last, _UnaryPredicate _p)
70 {
71 for (; _first != _last; ++_first) {
72 if (_p(*_first)) return false;
73 }
74 return true;
75 }
76 }
77
78 // all_of (C++11)
79 // checks if a predicate is true for all of the elements in a range
80 // (function template)
81 using algorithm_cpp11::all_of;
82
83 // any_of (C++11)
84 // checks if a predicate is true for any of the elements in a range
85 // (function template)
86 using algorithm_cpp11::any_of;
87
88 // none_of (C++11)
89 // checks if a predicate is true for none of the elements in a range
90 // (function template)
91 using algorithm_cpp11::none_of;
92
93 // applies a function to a range of elements
94 // (function template)
95 using std::for_each;
96
97 // for_each_n (C++17)
98 // applies a function object to the first n elements of a sequence
99 // (function template)
100 //<TODO>: using std::for_each_n;
101
102 // returns the number of elements
103 using std::count;
104
105 // returns the number of elements satisfying specific criteria
106 // (function template)
107 using std::count_if;
108
109 // finds the first position where two ranges differ
110 // (function template)
111 using std::mismatch;
112
113 // determines if two sets of elements are the same
114 // (function template)
115 using std::equal;
116
117
118 // finds the first element satisfying specific criteria
119 using std::find;
120
121 // finds the first element satisfying specific criteria
122 using std::find_if;
123
124 namespace algorithm_cpp11
125 {
126 // find_if_not (C++11)
127 // finds the first element satisfying specific criteria
128 // (function template)
129 template<class _InputIt, class _UnaryPredicate>
130 inline
131 _InputIt find_if_not(_InputIt _first,
132 typename detail::_if_iterator_cat_is_input<_InputIt>::type _last, _UnaryPredicate _p)
133 {
134 for (; _first != _last; ++_first) {
135 if (!_p(*_first)) {
136 return _first;
137 }
138 }
139 return _last;
140 }
141 }
142
143 // find_if_not (C++11)
144 // finds the first element satisfying specific criteria
145 // (function template)
146 using algorithm_cpp11::find_if_not;
147
148 // finds the last sequence of elements in a certain range
149 // (function template)
150 using std::find_end;
151
152 // searches for any one of a set of elements
153 // (function template)
154 using std::find_first_of;
155
156 // finds the first two adjacent items that are equal (or satisfy a given predicate)
157 // (function template)
158 using std::adjacent_find;
159
160 // searches for a range of elements
161 // (function template)
162 using std::search;
163
164 // searches a range for a number of consecutive copies of an element
165 // (function template)
166 using std::search_n;
167
168 // Modifying sequence operations
169
170 // copies a range of elements to a new location
171 using std::copy;
172
173 namespace detail
174 {
175 template<class _InputIt, class _OutputIt>
176 struct _copy_if_args_check :
177 _iterator_enable_if<
178 _iterator_cat_is<
179 typename std::iterator_traits<_InputIt>::iterator_category,
180 std::input_iterator_tag
181 >::value == bool(true) &&
182 _iterator_cat_is_valid<
183 typename std::iterator_traits<_OutputIt>::iterator_category,
184 std::output_iterator_tag
185 >::value == bool(true),
186 _InputIt
187 >
188 { };
189
190 template<class _InputIt, class _OutputIt>
191 struct _copy_if_args_check<_InputIt, const _OutputIt> :
192 _iterator_enable_if<false, void>
193 {};
194 }
195 namespace algorithm_cpp11
196 {
197 // copy_if (C++11)
198 // copies a range of elements to a new location
199 // (function template)
200 template<class _InputIt, class _OutputIt, class _UnaryPredicate>
201 inline
202 _OutputIt copy_if(
203 _InputIt _first,
204 typename detail::_copy_if_args_check<_InputIt, _OutputIt>::type _last,
205 _OutputIt _d_first,
206 _UnaryPredicate _p)
207 {
208 while (_first != _last) {
209 if (_p(*_first))
210 * _d_first++ = *_first;
211 _first++;
212 }
213 return _d_first;
214 }
215 }
216
217 // copy_if (C++11)
218 // copies a range of elements to a new location
219 // (function template)
220 using algorithm_cpp11::copy_if;
221
222 namespace detail
223 {
224 namespace algorithm_detail
225 {
226 _iterator_no_type copy_n(...); // dummy
227
228 _iterator_no_type _copy_n_check(_iterator_no_type);
229 _iterator_yes_type _copy_n_check(...);
230
231 struct _dummy_input_iterator :
232 public std::iterator<std::input_iterator_tag, int>
233 {
234 reference operator*();
235 _dummy_input_iterator& operator++ ();
236 _dummy_input_iterator operator++ (int);
237 };
238
239 struct _dummy_output_iterator :
240 public std::iterator<std::output_iterator_tag, int>
241 {
242 reference operator*();
243 _dummy_output_iterator& operator++ ();
244 _dummy_output_iterator operator++ (int);
245 };
246
247 struct _has_buggy_copy_n1
248 {
249 static const int _B[20];
250 static const bool value = sizeof(_copy_n_check(copy_n(_B, sizeof(_B) / sizeof(int), _dummy_output_iterator()))) == sizeof(_iterator_yes_type);
251 };
252
253 struct _has_buggy_copy_n2
254 {
255 static int _A[20];
256 static const bool value = sizeof(_copy_n_check(copy_n(_dummy_input_iterator(), sizeof(_A) / sizeof(int), _A))) == sizeof(_iterator_yes_type);
257 };
258
259 struct _has_buggy_copy_n3
260 {
261 static int _A[20];
262 static const int _B[20];
263 static const bool value = sizeof(_copy_n_check(copy_n(_B, sizeof(_A) / sizeof(int), _A))) == sizeof(_iterator_yes_type);
264 };
265 }
266
267 template<class _InputIt, class _OutputT>
268 struct _copy_n_input_it_check :
269 _iterator_enable_if<
270 _iterator_cat_is<
271 typename std::iterator_traits<_InputIt>::iterator_category,
272 std::input_iterator_tag
273 >::value == bool(true) &&
274 algorithm_detail::_has_buggy_copy_n2::value == bool(false),
275 cstddef::size_t
276 >
277 { };
278
279 template<class _InputIt, class _OutputT>
280 struct _copy_n_input_it_check<_InputIt, const _OutputT> :
281 _iterator_enable_if<false, void>
282 { };
283
284 template<class _InputIt, class _OutputT>
285 struct _copy_n_input_it_check1 :
286 _iterator_enable_if<
287 _iterator_cat_is<
288 typename std::iterator_traits<_InputIt>::iterator_category,
289 std::input_iterator_tag
290 >::value == bool(true) &&
291 algorithm_detail::_has_buggy_copy_n3::value == bool(false),
292 cstddef::size_t
293 >
294 { };
295
296 template<class _InputIt, class _OutputT>
297 struct _copy_n_input_it_check1<_InputIt, const _OutputT> :
298 _iterator_enable_if<false, void>
299 { };
300
301 template<class _OutputIt>
302 struct _copy_n_output_it_check :
303 _iterator_enable_if<
304 _iterator_cat_is<
305 typename std::iterator_traits<_OutputIt>::iterator_category,
306 std::output_iterator_tag
307 >::value == bool(true) &&
308 algorithm_detail::_has_buggy_copy_n1::value == bool(false),
309 cstddef::size_t
310 >
311 { };
312 }
313
314
315 namespace algorithm_cpp11
316 {
317
318 // copy_n (C++11)
319 // copies a number of elements to a new location
320 template<class _InputT, cstddef::size_t _InputSize, class _OutputIt>
321 inline
322 _OutputIt copy_n(_InputT(&_first_arr)[_InputSize],
323 typename detail::_copy_n_output_it_check<_OutputIt>::type _count, _OutputIt _result)
324 {
325 assert(_count <= _InputSize);
326
327 _InputT* _first = _first_arr;
328
329 if (_count > 0) {
330 *_result++ = *_first;
331 for (cstddef::size_t _i = 1; _i < _count; ++_i) {
332 *_result++ = *++_first;
333 }
334 }
335 return _result;
336 }
337
338 // copy_n (C++11)
339 // copies a number of elements to a new location
340 template<class _InputIt, class _OutputT, cstddef::size_t _OutputSize>
341 inline
342 _OutputT* copy_n(_InputIt _first,
343 typename detail::_copy_n_input_it_check<_InputIt, _OutputT>::type _count, _OutputT(&_result_arr)[_OutputSize])
344 {
345 assert(_count <= _OutputSize);
346
347 _OutputT* _result = _result_arr;
348
349 if (_count > 0) {
350 *_result++ = *_first;
351 for (cstddef::size_t _i = 1; _i < _count; ++_i) {
352 *_result++ = *++_first;
353 }
354 }
355 return _result;
356 }
357
358 // copy_n (C++11)
359 // copies a number of elements to a new location
360 template<
361 class _InputT, cstddef::size_t _InputSize,
362 class _OutputT, cstddef::size_t _OutputSize
363 >
364 inline
365 _OutputT* copy_n(_InputT(&_first_arr)[_InputSize],
366 cstddef::size_t _count, _OutputT(&_result_arr)[_OutputSize])
367 {
368 assert(_count <= _OutputSize);
369 assert(_count <= _InputSize);
370
371 _InputT* _first = _first_arr;
372 _OutputT* _result = _result_arr;
373
374 if (_count > 0) {
375 *_result++ = *_first;
376 for (cstddef::size_t _i = 1; _i < _count; ++_i) {
377 *_result++ = *++_first;
378 }
379 }
380 return _result;
381 }
382 }
383
384 namespace detail
385 {
386 namespace algorithm_detail
387 {
388 template<class _Tp>
389 _Tp declval();
390
391 template<class _InputIt, class _OutputIt>
392 struct _has_copy_n
393 {
394 static const bool value = sizeof(_copy_n_check(copy_n(declval<_InputIt>(), 0, declval<_OutputIt>()))) == sizeof(_iterator_yes_type);
395 };
396 }
397
398 template<class _InputIt, class _OutputIt>
399 struct _copy_n_args_check :
400 _iterator_enable_if<
401 _iterator_cat_is<
402 typename std::iterator_traits<_InputIt>::iterator_category,
403 std::input_iterator_tag
404 >::value == bool(true) &&
405 _iterator_cat_is_valid<
406 typename std::iterator_traits<_OutputIt>::iterator_category,
407 std::output_iterator_tag
408 >::value == bool(true) &&
409 algorithm_detail::_has_copy_n<_InputIt, _OutputIt>::value == bool(false),
410 cstddef::size_t
411 >
412 { };
413 }
414
415 namespace algorithm_cpp11
416 {
417 // copy_n (C++11)
418 // copies a number of elements to a new location
419 template<class _InputIt, class _OutputIt>
420 inline
421 _OutputIt copy_n(_InputIt _first,
422 typename detail::_copy_n_args_check<_InputIt, _OutputIt>::type _count, _OutputIt _result)
423 {
424 if (_count > 0) {
425 *_result++ = *_first;
426 for (cstddef::size_t _i = 1; _i < _count; ++_i) {
427 *_result++ = *++_first;
428 }
429 }
430 return _result;
431 }
432 }
433
434 // copy_n (C++11)
435 // copies a number of elements to a new location
436 using algorithm_cpp11::copy_n;
437
438 // copies a range of elements in backwards order
439 // (function template)
440 using std::copy_backward;
441
442 // (C++11)
443 // moves a range of elements to a new location
444 // (function template)
445 // <TODO>: move()
446
447 // (C++11)
448 // moves a range of elements to a new location in backwards order
449 // (function template)
450 // <TODO>: move_backward()
451
452 // copy-assigns the given value to every element in a range
453 // (function template)
454 using std::fill;
455
456 // copy-assigns the given value to N elements in a range
457 // (function template)
458 using std::fill_n;
459
460 // applies a function to a range of elements
461 // (function template)
462 using std::transform;
463
464 // assigns the results of successive function calls to every element in a range
465 // (function template)
466 using std::generate;
467
468 // assigns the results of successive function calls to N elements in a range
469 // (function template)
470 using std::generate_n;
471
472 // removes elements satisfying specific criteria
473 // (function template)
474 using std::remove;
475
476 // removes elements satisfying specific criteria
477 // (function template)
478 using std::remove_if;
479
480 // copies a range of elements omitting those that satisfy specific criteria
481 // (function template)
482 using std::remove_copy;
483
484 // copies a range of elements omitting those that satisfy specific criteria
485 // (function template)
486 using std::remove_copy_if;
487
488 // replaces all values satisfying specific criteria with another value
489 // (function template)
490 using std::replace;
491
492 // replaces all values satisfying specific criteria with another value
493 // (function template)
494 using std::replace_if;
495
496 // copies a range, replacing elements satisfying specific criteria with another value
497 // (function template)
498 using std::replace_copy;
499
500 // copies a range, replacing elements satisfying specific criteria with another value
501 // (function template)
502 using std::replace_copy_if;
503
504 // swaps the values of two objects
505 // (function template)
506 using std::swap;
507
508 // swaps two ranges of elements
509 // (function template)
510 using std::swap_ranges;
511
512 // swaps the elements pointed to by two iterators
513 // (function template)
514 using std::iter_swap;
515
516 // reverses the order of elements in a range
517 // (function template)
518 using std::reverse;
519
520 // creates a copy of a range that is reversed
521 // (function template)
522 using std::reverse_copy;
523
524 // rotates the order of elements in a range
525 // (function template)
526 using std::rotate;
527
528 // copies and rotate a range of elements
529 // (function template)
530 using std::rotate_copy;
531
532 namespace algorithm_cpp11
533 {
534 template<class _RandomIt>
535 inline
536 void random_shuffle(_RandomIt _first,
537 typename detail::_if_iterator_cat_is_rand_access<_RandomIt>::type _last)
538 {
539 using std::swap;
540 typename std::iterator_traits<_RandomIt>::difference_type _i, _n;
541 _n = _last - _first;
542 for (_i = _n - 1; _i > 0; --_i) {
543 swap(_first[_i], _first[std::rand() % (_i + 1)]);
544 // rand() % (i+1) isn't actually correct, because the generated number
545 // is not uniformly distributed for most values of i. A correct implementation
546 // will need to essentially reimplement C++11 std::uniform_int_distribution,
547 // which is not implemented (yet).
548 }
549 }
550
551 // randomly re-orders elements in a range with user random number generator func
552 // (function template)
553 template<class _RandomIt, class _RandomFunc>
554 inline
555 void random_shuffle(_RandomIt _first,
556 typename detail::_if_iterator_cat_is_rand_access<_RandomIt>::type _last, _RandomFunc& _r)
557 {
558 typename std::iterator_traits<_RandomIt>::difference_type _i, _n;
559 _n = _last - _first;
560 for (_i = _n - 1; _i > 0; --_i) {
561 swap(_first[_i], _first[_r(_i + 1)]);
562 }
563 }
564 }
565
566 // randomly re-orders elements in a range
567 // (function template)
568 using algorithm_cpp11::random_shuffle;
569
570 // (C++11)
571 // randomly re-orders elements in a range
572 // (function template)
573 // <TODO>: shuffle()
574
575 // removes consecutive duplicate elements in a range
576 // (function template)
577 using std::unique;
578
579 // creates a copy of some range of elements that contains no consecutive duplicates
580 // (function template)
581 using std::unique_copy;
582
583 // Partitioning operations
584
585 namespace algorithm_cpp11
586 {
587 template<class _InputIt, class _UnaryPredicate>
588 inline
589 bool is_partitioned(_InputIt _first,
590 typename detail::_if_iterator_cat_is_input<_InputIt>::type _last, _UnaryPredicate _pred)
591 {
592 _first = stdex::find_if_not(_first, _last, _pred);
593 if (_first == _last)
594 return true;
595 ++_first;
596 return stdex::none_of(_first, _last, _pred);
597 }
598 }
599 // (C++11)
600 // determines if the range is partitioned by the given predicate
601 // (function template)
602 using algorithm_cpp11::is_partitioned;
603
604 // divides a range of elements into two groups
605 // (function template)
606 using std::partition;
607
608 namespace detail
609 {
610 template<class _InputIt, class _OutputIt1, class _OutputIt2>
611 struct _partition_copy_args_check :
612 _iterator_enable_if<
613 _iterator_cat_is<
614 typename std::iterator_traits<_InputIt>::iterator_category,
615 std::input_iterator_tag
616 >::value == bool(true) &&
617 _iterator_cat_is_valid<
618 typename std::iterator_traits<_OutputIt1>::iterator_category,
619 std::output_iterator_tag
620 >::value == bool(true) &&
621 _iterator_cat_is_valid<
622 typename std::iterator_traits<_OutputIt2>::iterator_category,
623 std::output_iterator_tag
624 >::value == bool(true),
625 _InputIt
626 >
627 {};
628
629 template<class _InputIt, class _OutputIt1, class _OutputIt2>
630 struct _partition_copy_args_check<_InputIt, const _OutputIt1, _OutputIt2> :
631 _iterator_traits_enable_if<false, void>
632 {};
633
634 template<class _InputIt, class _OutputIt1, class _OutputIt2>
635 struct _partition_copy_args_check<_InputIt, _OutputIt1, const _OutputIt2> :
636 _iterator_traits_enable_if<false, void>
637 {};
638
639 template<class _InputIt, class _OutputIt1, class _OutputIt2>
640 struct _partition_copy_args_check<_InputIt, const _OutputIt1, const _OutputIt2> :
641 _iterator_traits_enable_if<false, void>
642 {};
643 }
644
645 namespace algorithm_cpp11
646 {
647 template<class _InputIt, class _OutputIt1, class _OutputIt2, class _UnaryPredicate>
648 inline
649 std::pair<_OutputIt1, _OutputIt2>
650 partition_copy(
651 _InputIt _first,
652 typename detail::_partition_copy_args_check<_InputIt, _OutputIt1, _OutputIt2>::type _last,
653 _OutputIt1 _d_first_true,
654 _OutputIt2 _d_first_false,
655 _UnaryPredicate _p)
656 {
657 while (_first != _last) {
658 if (_p(*_first)) {
659 *_d_first_true = *_first;
660 ++_d_first_true;
661 }
662 else {
663 *_d_first_false = *_first;
664 ++_d_first_false;
665 }
666 ++_first;
667 }
668 return std::pair<_OutputIt1, _OutputIt2>(_d_first_true, _d_first_false);
669 }
670 }
671
672 // (C++11)
673 // copies a range dividing the elements into two groups
674 // (function template)
675 using algorithm_cpp11::partition_copy;
676
677 // divides elements into two groups while preserving their relative order
678 // (function template)
679 using std::stable_partition;
680
681 // locates the partition point of a partitioned range
682 // (function template)
683 // <TODO>: partition_point()
684
685
686 // Sorting operations
687
688 namespace algorithm_cpp11
689 {
690 // (C++11)
691 // finds the largest sorted subrange
692 // (function template)
693 template<class _ForwardIt>
694 inline
695 _ForwardIt is_sorted_until(_ForwardIt _first,
696 typename detail::_if_iterator_cat_is_forward<_ForwardIt>::type _last)
697 {
698 if (_first != _last) {
699 _ForwardIt _next = _first;
700 while (++_next != _last) {
701 if (*_next < *_first)
702 return _next;
703 _first = _next;
704 }
705 }
706 return _last;
707 }
708
709 // (C++11)
710 // finds the largest sorted subrange given binary comparison function comp
711 // (function template)
712 template <class _ForwardIt, class _Compare>
713 inline
714 _ForwardIt is_sorted_until(_ForwardIt _first,
715 typename detail::_if_iterator_cat_is_forward<_ForwardIt>::type _last, _Compare _comp)
716 {
717 if (_first != _last) {
718 _ForwardIt _next = _first;
719 while (++_next != _last) {
720 if (true == comp(*_next, *_first))
721 return _next;
722 _first = _next;
723 }
724 }
725 return _last;
726 }
727
728 // (C++11)
729 // checks whether a range is sorted into ascending order
730 // (function template)
731 template<class _ForwardIt>
732 inline
733 bool is_sorted(_ForwardIt _first,
734 typename detail::_if_iterator_cat_is_forward<_ForwardIt>::type _last)
735 {
736 return algorithm_cpp11::is_sorted_until(_first, _last) == _last;
737 }
738
739 // (C++11)
740 // checks with given binary comparison function comp whether a range is sorted into ascending order
741 // (function template)
742 template<class _ForwardIt, class _Compare>
743 inline
744 bool is_sorted(_ForwardIt _first,
745 typename detail::_if_iterator_cat_is_forward<_ForwardIt>::type _last, _Compare _comp)
746 {
747 return algorithm_cpp11::is_sorted_until(_first, _last, _comp) == _last;
748 }
749 }
750
751 // (C++11)
752 // finds the largest sorted subrange
753 // (function template)
754 using algorithm_cpp11::is_sorted_until;
755
756 // (C++11)
757 // checks whether a range is sorted into ascending order
758 // (function template)
759 using algorithm_cpp11::is_sorted;
760
761 // sorts a range into ascending order
762 // (function template)
763 using std::sort;
764
765 // sorts the first N elements of a range
766 // (function template)
767 using std::partial_sort;
768
769 // copies and partially sorts a range of elements
770 // (function template)
771 using std::partial_sort_copy;
772
773 // sorts a range of elements while preserving order between equal elements
774 // (function template)
775 using std::stable_sort;
776
777 // partially sorts the given range making sure that it is partitioned by the given element
778 // (function template)
779 using std::nth_element;
780
781 // Binary search operations (on sorted ranges)
782
783 // returns an iterator to the first element not less than the given value
784 // (function template)
785 using std::lower_bound;
786
787 // returns an iterator to the first element greater than a certain value
788 // (function template)
789 using std::upper_bound;
790
791 // determines if an element exists in a certain range
792 // (function template)
793 using std::binary_search;
794
795 // returns range of elements matching a specific key
796 // (function template)
797 using std::equal_range;
798
799 // Set operations (on sorted ranges)
800
801 // merges two sorted ranges
802 // (function template)
803 using std::merge;
804
805 // merges two ordered ranges in-place
806 // (function template)
807 using std::inplace_merge;
808
809 // returns true if one set is a subset of another
810 // (function template)
811 using std::includes;
812
813 // computes the difference between two sets
814 // (function template)
815 using std::set_difference;
816
817 // computes the intersection of two sets
818 // (function template)
819 using std::set_intersection;
820
821 // computes the symmetric difference between two sets
822 // (function template)
823 using std::set_symmetric_difference;
824
825 // computes the union of two sets
826 // (function template)
827 using std::set_union;
828
829 // Heap operations
830
831 // (C++11)
832 // checks if the given range is a max heap
833 // (function template)
834 // <TODO>: is_heap()
835
836 // (C++11)
837 // finds the largest subrange that is a max heap
838 // (function template)
839 // <TODO>: is_heap_until()
840
841 // creates a max heap out of a range of elements
842 // (function template)
843 using std::make_heap;
844
845 // adds an element to a max heap
846 // (function template)
847 using std::push_heap;
848
849 // removes the largest element from a max heap
850 // (function template)
851 using std::pop_heap;
852
853 // turns a max heap into a range of elements sorted in ascending order
854 // (function template)
855 using std::sort_heap;
856
857 // Minimum/maximum operations
858
859 // (C++17)
860 // clamps a value between a pair of boundary values
861 // (function template)
862 // <TODO>: clamp()
863
864 // returns the greater of the given values
865 // (function template)
866 using std::max;
867
868 // returns the largest element in a range
869 // (function template)
870 using std::max_element;
871
872 // returns the smaller of the given values
873 // (function template)
874 using std::min;
875
876 // returns the smallest element in a range
877 // (function template)
878 using std::min_element;
879
880 namespace algorithm_cpp11
881 {
882 // (C++11)
883 // returns the smaller and larger of two elements
884 // (function template)
885 template<class _Tp>
886 inline
887 std::pair<const _Tp&, const _Tp&> minmax(const _Tp& _a, const _Tp& _b)
888 {
889 return (_b < _a) ? std::pair<const _Tp&, const _Tp&>(_b, _a)
890 : std::pair<const _Tp&, const _Tp&>(_a, _b);
891 }
892
893 // (C++11)
894 // returns the smaller and larger of two elements using the given comparison function comp
895 // (function template)
896 template<class _Tp, class _Compare>
897 inline
898 std::pair<const _Tp&, const _Tp&> minmax(const _Tp& _a, const _Tp& _b, _Compare _comp)
899 {
900 return comp(_b, _a) ? std::pair<const _Tp&, const _Tp&>(_b, _a)
901 : std::pair<const _Tp&, const _Tp&>(_a, _b);
902 }
903
904 // (C++11)
905 // returns the smallest and the largest elements in a range
906 // using the given binary comparison function comp
907 template<class _ForwardIt, class _Compare>
908 inline
909 std::pair<_ForwardIt, _ForwardIt>
910 minmax_element(_ForwardIt _first,
911 typename detail::_if_iterator_cat_is_forward<_ForwardIt>::type _last, _Compare _comp)
912 {
913 std::pair<_ForwardIt, _ForwardIt> _result(_first, _first);
914
915 if (_first == _last) return _result;
916 if (++_first == _last) return _result;
917
918 if (_comp(*_first, *_result.first)) {
919 _result.first = _first;
920 }
921 else {
922 _result.second = _first;
923 }
924 while (++_first != _last) {
925 _ForwardIt _i = _first;
926 if (++_first == _last) {
927 if (_comp(*_i, *_result.first)) _result.first = _i;
928 else if (!(_comp(*_i, *_result.second))) _result.second = _i;
929 break;
930 }
931 else {
932 if (_comp(*_first, *_i)) {
933 if (_comp(*_first, *_result.first)) _result.first = _first;
934 if (!(_comp(*_i, *_result.second))) _result.second = _i;
935 }
936 else {
937 if (_comp(*_i, *_result.first)) _result.first = _i;
938 if (!(_comp(*_first, *_result.second))) _result.second = _first;
939 }
940 }
941 }
942 return _result;
943 }
944
945 // (C++11)
946 // returns the smallest and the largest elements in a range
947 // (function template)
948 template<class _ForwardIt>
949 inline
950 std::pair<_ForwardIt, _ForwardIt>
951 minmax_element(_ForwardIt _first,
952 typename detail::_if_iterator_cat_is_forward<_ForwardIt>::type _last)
953 {
954 typedef typename std::iterator_traits<_ForwardIt>::value_type _value_type;
955 return algorithm_cpp11::minmax_element(_first, _last, std::less<_value_type>());
956 }
957 }
958
959 // (C++11)
960 // returns the smaller and larger of two elements
961 // (function template)
962 using algorithm_cpp11::minmax;
963
964 // (C++11)
965 // returns the smallest and the largest elements in a range
966 using algorithm_cpp11::minmax_element;
967
968 // returns true if one range is lexicographically less than another
969 // (function template)
970 using std::lexicographical_compare;
971
972 namespace detail
973 {
974 template<class _ForwardIt1, class _ForwardIt2>
975 struct _if_iterators_cat_are_forward :
976 _iterator_traits_enable_if<
977 _iterator_cat_is<
978 typename std::iterator_traits<_ForwardIt1>::iterator_category,
979 std::forward_iterator_tag
980 >::value == bool(true) &&
981 _iterator_cat_is<
982 typename std::iterator_traits<_ForwardIt2>::iterator_category,
983 std::forward_iterator_tag
984 >::value == bool(true),
985 _ForwardIt1
986 >
987 {};
988
989 template<class _Tp, class _BinaryPredicate>
990 struct _BinaryToUnaryPredicate {
991 _BinaryToUnaryPredicate(const _Tp& value_, _BinaryPredicate& pred_) :
992 value(value_),
993 pred(pred_)
994 {}
995 const _Tp& value;
996 _BinaryPredicate& pred;
997
998 bool operator()(const _Tp& input) const
999 {
1000 return pred(value, input);
1001 }
1002
1003 private:
1004 // removes MSVS 2013 warning of "assignment operator could not be generated"
1005 // we do not use it anyway but whatever works for glorious Microsoft compiler...
1006 _BinaryToUnaryPredicate &operator=(const _BinaryToUnaryPredicate &other)
1007 {
1008 return *this;
1009 }
1010 };
1011
1012 template<class _Tp, class _BinaryPredicate>
1013 _BinaryToUnaryPredicate<_Tp, _BinaryPredicate>
1014 _make_b2u_predicate(const _Tp& value_, _BinaryPredicate& pred_)
1015 {
1016 return _BinaryToUnaryPredicate<_Tp, _BinaryPredicate>(value_, pred_);
1017 }
1018 }
1019
1020 namespace algorithm_cpp11
1021 {
1022 // (C++11)
1023 // determines if a sequence is a permutation of another sequence
1024 // (function template)
1025 template<class _ForwardIt1, class _ForwardIt2>
1026 inline
1027 bool is_permutation(_ForwardIt1 _first,
1028 typename detail::_if_iterators_cat_are_forward<_ForwardIt1, _ForwardIt2>::type _last, _ForwardIt2 _d_first)
1029 {
1030 // skip common prefix
1031 std::pair<_ForwardIt1, _ForwardIt2> _tie = std::mismatch(_first, _last, _d_first);
1032 _first = _tie.first;
1033 _d_first = _tie.second;
1034 // iterate over the rest, counting how many times each element
1035 // from [first, last) appears in [d_first, d_last)
1036 if (_first != _last) {
1037 _ForwardIt2 _d_last = _d_first;
1038 std::advance(_d_last, std::distance(_first, _last));
1039 for (_ForwardIt1 _i = _first; _i != _last; ++_i) {
1040 if (_i != std::find(_first, _i, *_i)) continue; // already counted this *i
1041 typename iterator_traits<_ForwardIt2>::difference_type _m = std::count(_d_first, _d_last, *_i);
1042 if (_m == 0 || std::count(_i, _last, *_i) != _m) {
1043 return false;
1044 }
1045 }
1046 }
1047 return true;
1048 }
1049
1050 template<class _ForwardIt1, class _ForwardIt2, class _BinaryPredicate>
1051 inline
1052 bool is_permutation(_ForwardIt1 _first,
1053 typename detail::_if_iterators_cat_are_forward<_ForwardIt1, _ForwardIt2>::type _last,
1054 _ForwardIt2 _d_first, _BinaryPredicate _pred)
1055 {
1056 // skip common prefix
1057 std::pair<_ForwardIt1, _ForwardIt2> _tie = std::mismatch(_first, _last, _d_first, _pred);
1058 _first = _tie.first;
1059 _d_first = _tie.second;
1060 // iterate over the rest, counting how many times each element
1061 // from [first, last) appears in [d_first, d_last)
1062 if (_first != _last) {
1063 _ForwardIt2 _d_last = _d_first;
1064 std::advance(_d_last, std::distance(_first, _last));
1065 for (_ForwardIt1 _i = _first; _i != _last; ++_i) {
1066 if (_i != std::find_if(_first, _i, detail::_make_b2u_predicate(*_i, _pred))) continue; // already counted this *i
1067 typename iterator_traits<_ForwardIt2>::difference_type _m = std::count_if(_d_first, _d_last, detail::_make_b2u_predicate(*_i, _pred));
1068 if (_m == 0 || std::count_if(_i, _last, detail::_make_b2u_predicate(*_i, _pred)) != _m) {
1069 return false;
1070 }
1071 }
1072 }
1073 return true;
1074 }
1075 }
1076
1077 // (C++11)
1078 // determines if a sequence is a permutation of another sequence
1079 // (function template)
1080 using algorithm_cpp11::is_permutation;
1081
1082 // generates the next greater lexicographic permutation of a range of elements
1083 // (function template)
1084 using std::next_permutation;
1085
1086 // generates the next smaller lexicographic permutation of a range of elements
1087 // (function template)
1088 using std::prev_permutation;
1089}
1090
1091#endif // _STDEX_ALGORITHM_H