Adobe Source Libraries 1.49.0
A collection of C++ libraries.
Loading...
Searching...
No Matches
selection_algorithms.hpp
Go to the documentation of this file.
1/*
2 Copyright 2013 Adobe
3 Distributed under the Boost Software License, Version 1.0.
4 (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
5*/
6/**************************************************************************************************/
7
8#ifndef ADOBE_ALGORITHM_SELECTION_HPP
9#define ADOBE_ALGORITHM_SELECTION_HPP
10
11#include <adobe/config.hpp>
12
13#include <algorithm>
14#include <functional>
15#include <vector>
16
17#include <boost/range/begin.hpp>
18#include <boost/range/end.hpp>
19#include <boost/range/size.hpp>
20#include <boost/range/size_type.hpp>
21#include <boost/range/value_type.hpp>
22
26
27/**************************************************************************************************/
28
29namespace adobe {
30
31/**************************************************************************************************/
47/**************************************************************************************************/
54template <typename S, // S models ForwardIterator, value_type(S) == I
55 typename O, // O models OutputIterator
56 typename P>
57// P models BinaryPredicate
58inline O selection_operation_remainder(S first, S last, O output, bool this_inside,
59 bool other_inside, P pred) {
60 bool prev_op_result(pred(this_inside, other_inside));
61
62 while (first != last) {
63 this_inside = !this_inside;
64
65 bool cur_op_result(pred(this_inside, other_inside));
66
67 if (prev_op_result != cur_op_result)
68 *output++ = *first;
69
70 prev_op_result = cur_op_result;
71
72 ++first;
73 }
74
75 return output;
76}
77
78/**************************************************************************************************/
84template <typename C1, // C1 models ConvertibleToBool
85 typename C2 = C1> // C2 models ConvertibleToBool
88 bool operator()(const C1& x, const C2& y) const {
89 return static_cast<bool>(x) != static_cast<bool>(y);
90 }
91};
92
93/**************************************************************************************************/
99template <typename S1, // S1 models ForwardIterator, value_type(S1) == value_type(S2)
100 typename S2, // S2 models ForwardIterator, value_type(S2) == value_type(S1)
101 typename O, // O models OutputIterator
102 typename P, // P models BinaryPredicate
103 typename C>
104// C models StrictWeakOrdering
105O selection_operation(S1 s1_first, S1 s1_last, S2 s2_first, S2 s2_last, O output, bool s1_inside,
106 bool s2_inside, P pred, C comp) {
107 if (s1_first == s1_last)
108 return selection_operation_remainder(s2_first, s2_last, output, s2_inside, s1_inside, pred);
109 else if (s2_first == s2_last)
110 return selection_operation_remainder(s1_first, s1_last, output, s1_inside, s2_inside, pred);
111
112 bool prev_op_result(pred(s1_inside, s2_inside));
113
114 while (true) {
115 typename std::iterator_traits<S1>::value_type next(comp(*s1_first, *s2_first) ? *s1_first
116 : *s2_first);
117
118 if (*s1_first == next) {
119 s1_inside = !s1_inside;
120
121 ++s1_first;
122 }
123
124 if (*s2_first == next) {
125 s2_inside = !s2_inside;
126
127 ++s2_first;
128 }
129
130 bool cur_op_result(pred(s1_inside, s2_inside));
131
132 if (prev_op_result != cur_op_result)
133 *output++ = next;
134
135 prev_op_result = cur_op_result;
136
137 if (s1_first == s1_last)
138 return selection_operation_remainder(s2_first, s2_last, output, s2_inside, s1_inside,
139 pred);
140 else if (s2_first == s2_last)
141 return selection_operation_remainder(s1_first, s1_last, output, s1_inside, s2_inside,
142 pred);
143 }
144
145 return output;
146}
147
148/**************************************************************************************************/
154template <typename S1, // S1 models ForwardIterator, value_type(S1) == I
155 typename S2, // S2 models ForwardIterator, value_type(S2) == I
156 typename O, // O models OutputIterator
157 typename C>
158// C models StrictWeakOrdering
159inline O selection_union(S1 s1_first, S1 s1_last, S2 s2_first, S2 s2_last, O output, C comp,
160 bool s1_inside = false, bool s2_inside = false) {
161 return selection_operation(s1_first, s1_last, s2_first, s2_last, output, s1_inside, s2_inside,
162 std::logical_or<bool>(), comp);
163}
164
165/**************************************************************************************************/
171template <typename S1, // S1 models ForwardIterator, value_type(S1) == I
172 typename S2, // S2 models ForwardIterator, value_type(S2) == I
173 typename O, // O models OutputIterator
174 typename C>
175// C models StrictWeakOrdering
176inline O selection_intersection(S1 s1_first, S1 s1_last, S2 s2_first, S2 s2_last, O output, C comp,
177 bool s1_inside = false, bool s2_inside = false) {
178 return selection_operation(s1_first, s1_last, s2_first, s2_last, output, s1_inside, s2_inside,
179 std::logical_and<bool>(), comp);
180}
181
182/**************************************************************************************************/
188template <typename S1, // S1 models ForwardIterator, value_type(S1) == I
189 typename S2, // S2 models ForwardIterator, value_type(S2) == I
190 typename O, // O models OutputIterator
191 typename C>
192// C models StrictWeakOrdering
193inline O selection_difference(S1 s1_first, S1 s1_last, S2 s2_first, S2 s2_last, O output, C comp,
194 bool s1_inside = false, bool s2_inside = false) {
195 return selection_intersection(s1_first, s1_last, s2_first, s2_last, output, comp, s1_inside,
196 !s2_inside);
197}
198
199/**************************************************************************************************/
205template <typename S1, // S1 models ForwardIterator, value_type(S1) == I
206 typename S2, // S2 models ForwardIterator, value_type(S2) == I
207 typename O, // O models OutputIterator
208 typename C>
209// C models StrictWeakOrdering
210inline O selection_symmetric_difference(S1 s1_first, S1 s1_last, S2 s2_first, S2 s2_last, O output,
211 C comp, bool s1_inside = false, bool s2_inside = false) {
212 return selection_operation(s1_first, s1_last, s2_first, s2_last, output, s1_inside, s2_inside,
213 logical_xor<bool>(), comp);
214}
215
216/**************************************************************************************************/
222template <typename S1, // S1 models InputIterator, value_type(S1) == I
223 typename S2, // S2 models InputIterator, value_type(S2) == I
224 typename C>
225// C models StrictWeakOrdering
226inline bool selection_includes(S1 s1_first, S1 s1_last, S2 s2_first, S2 s2_last, C comp,
227 bool s1_inside = false, bool s2_inside = false) {
228 if (s1_inside == s2_inside) {
229 typedef typename std::iterator_traits<S1>::value_type value_type;
230
231 std::vector<value_type> result;
232
233 selection_intersection(s1_first, s1_last, s2_first, s2_last, std::back_inserter(result),
234 comp, s1_inside, s2_inside);
235
236 return std::equal(s2_first, s2_last, result.begin());
237 } else if (s1_inside) {
238 return selection_includes(boost::next(s1_first), s1_last, s2_first, s2_last, comp,
239 !s1_inside, s2_inside);
240 }
241
242 // s2_inside == true
243 return selection_includes(s1_first, s1_last, boost::next(s2_first), s2_last, comp, s1_inside,
244 !s2_inside);
245}
246
247/**************************************************************************************************/
253template <typename Selection1, typename Selection2>
254Selection1 selection_intersection(const Selection1& x, const Selection2& y) {
255 if (&x == &y)
256 return x;
257
258 Selection1 result(start_selected(x) && start_selected(y));
259
260 adobe::selection_intersection(x.begin(), x.end(), y.begin(), y.end(),
261 std::back_inserter(result),
262 std::less<typename boost::range_value<Selection1>::type>(),
264
265 return result;
266}
267
268/**************************************************************************************************/
274template <typename Selection1, typename Selection2>
275Selection1 selection_union(const Selection1& x, const Selection2& y) {
276 if (&x == &y)
277 return x;
278
279 Selection1 result(start_selected(x) || start_selected(y));
280
281 adobe::selection_union(x.begin(), x.end(), y.begin(), y.end(), std::back_inserter(result),
282 std::less<typename boost::range_value<Selection1>::type>(),
284
285 return result;
286}
287
288/**************************************************************************************************/
294template <typename Selection1, typename Selection2>
295Selection1 selection_difference(const Selection1& x, const Selection2& y) {
296 if (&x == &y)
297 return Selection1();
298
299 Selection1 result(start_selected(x) != start_selected(y));
300
301 adobe::selection_difference(x.begin(), x.end(), y.begin(), y.end(), std::back_inserter(result),
302 std::less<typename boost::range_value<Selection1>::type>(),
304
305 return result;
306}
307
308/**************************************************************************************************/
314template <typename Selection1, typename Selection2>
315Selection1 selection_symmetric_difference(const Selection1& x, const Selection2& y) {
316 if (&x == &y)
317 return Selection1();
318
319 Selection1 result(start_selected(x) != start_selected(y));
320
322 x.begin(), x.end(), y.begin(), y.end(), std::back_inserter(result),
323 std::less<typename boost::range_value<Selection1>::type>(), start_selected(x),
324 start_selected(y));
325
326 return result;
327}
328
329/**************************************************************************************************/
335template <typename Selection1, typename Selection2>
336bool selection_includes(const Selection1& x, const Selection2& y) {
337 if (&x == &y)
338 return true;
339
340 return adobe::selection_includes(x.begin(), x.end(), y.begin(), y.end(),
341 std::less<typename boost::range_value<Selection1>::type>(),
343}
344
345/**************************************************************************************************/
351template <typename Selection>
352inline void invert(Selection& x) {
353 x.invert();
354}
355
356/**************************************************************************************************/
362template <typename Selection>
363inline bool start_selected(const Selection& x) {
364 return x.start_selected();
365}
366
367/**************************************************************************************************/
373template <typename Selection>
374inline typename boost::range_size<Selection>::type size(const Selection& x) {
375 return x.size();
376}
377
378/**************************************************************************************************/
384template <typename Selection, typename ForwardRange>
385typename boost::range_size<Selection>::type size(const Selection& x, const ForwardRange& range) {
386 typedef typename boost::range_const_iterator<Selection>::type selection_const_iterator;
387 typedef typename boost::range_size<Selection>::type selection_size_type;
388 typedef typename boost::range_const_iterator<ForwardRange>::type range_const_iterator;
389
390 if (x.empty())
391 return 0;
392
393 // this is the case when the selection has no elements, but it starts selected
394 // (in other words, every item in the selection is toggled as selected)
395 if (x.size() == 0)
396 return boost::size(range);
397
398 selection_const_iterator s_iter(boost::begin(x));
399 selection_const_iterator s_last(boost::end(x));
400
401 range_const_iterator prev(boost::begin(range));
402 range_const_iterator iter(boost::next(prev, *s_iter));
403 range_const_iterator last(boost::end(range));
404
405 selection_size_type result(0);
406 bool inside(start_selected(x));
407
408 while (true) {
409 if (inside)
410 result += static_cast<selection_size_type>(std::distance(prev, iter));
411
412 if (iter == last)
413 break;
414
415 prev = iter;
416
417 iter = ++s_iter == s_last ? last : boost::next(boost::begin(range), *s_iter);
418
419 inside = !inside;
420 }
421
422 return result;
423}
424
425/**************************************************************************************************/
431template <typename Selection>
432bool is_selected(const Selection& x, typename Selection::value_type index) {
433 typename boost::range_const_iterator<Selection>::type found(
434 std::upper_bound(boost::begin(x), boost::end(x), index));
435 typename boost::range_size<Selection>::type count(std::distance(boost::begin(x), found));
436
437 return (count % 2 == 1) != start_selected(x);
438}
439
440/**************************************************************************************************/
447template <typename Selection, typename ForwardRange, typename OutputIterator>
448OutputIterator selection_copy(const Selection& x, const ForwardRange& range,
449 OutputIterator output) {
450 typedef typename boost::range_const_iterator<Selection>::type selection_const_iterator;
451 typedef typename boost::range_const_iterator<ForwardRange>::type range_const_iterator;
452
453 if (boost::size(range) == 0)
454 return output;
455
456 bool inside(start_selected(x));
457
458 selection_const_iterator s_iter(boost::begin(x));
459 selection_const_iterator s_last(boost::end(x));
460
461 range_const_iterator iter(boost::begin(range));
462 range_const_iterator last(boost::end(range));
463
464 while (iter != last) {
465 if (s_iter != s_last && iter == boost::next(boost::begin(range), *s_iter)) {
466 ++s_iter;
467
468 inside = !inside;
469 }
470
471 if (inside)
472 *output++ = *iter;
473
474 ++iter;
475 }
476
477 return output;
478}
479
480/**************************************************************************************************/
486template <typename Selection, typename ForwardRange, typename O1, // O1 models OutputIterator
487 typename O2>
488// O2 models OutputIterator
489std::pair<O1, O2> selection_partition_copy(const Selection& selection, ForwardRange& range,
490 O1 false_output, O2 true_output) {
491 typedef typename boost::range_const_iterator<Selection>::type selection_const_iterator;
492 typedef typename boost::range_iterator<ForwardRange>::type range_iterator;
493
494 if (boost::size(range) == 0)
495 return std::make_pair(false_output, true_output);
496
497 selection_const_iterator selection_first(boost::begin(selection));
498 selection_const_iterator selection_last(boost::end(selection));
499
500 range_iterator first(boost::begin(range));
501 range_iterator last(boost::end(range));
502
503 bool inside(start_selected(selection));
504
505 while (true) {
506 range_iterator copy_last(selection_first == selection_last
507 ? last
508 : boost::next(boost::begin(range), *selection_first));
509
510 // REVISIT (fbrereto) : It'd be nice to collapse the following into ? :
511 // notation, but some compilers require that the
512 // types returned by ? : be the same, which we cannot
513 // guarantee here.
514 if (inside)
515 std::copy(first, copy_last, true_output);
516 else
517 std::copy(first, copy_last, false_output);
518
519 if (copy_last == last)
520 break;
521
522 first = copy_last;
523 ++selection_first;
524 inside = !inside;
525 }
526
527 return std::make_pair(false_output, true_output);
528}
529
530/**************************************************************************************************/
536template <typename Selection, typename ForwardRange, typename UnaryFunction>
537UnaryFunction selection_foreach(const Selection& x, const ForwardRange& range, UnaryFunction proc) {
538 typedef typename boost::range_const_iterator<Selection>::type selection_const_iterator;
539 typedef typename boost::range_const_iterator<ForwardRange>::type range_const_iterator;
540
541 bool inside(start_selected(x));
542
543 selection_const_iterator s_iter(boost::begin(x));
544 selection_const_iterator s_last(boost::end(x));
545
546 range_const_iterator iter(boost::begin(range));
547 range_const_iterator last(boost::end(range));
548
549 while (iter != last) {
550 if (s_iter != s_last && iter == boost::next(boost::begin(range), *s_iter)) {
551 ++s_iter;
552
553 inside = !inside;
554 }
555
556 if (inside)
557 proc(*iter);
558
559 ++iter;
560 }
561
562 return proc;
563}
564
565/**************************************************************************************************/
571template <typename Selection>
572inline std::pair<typename boost::range_const_iterator<Selection>::type,
573 typename boost::range_size<Selection>::type>
574selection_find_boundary(const Selection& selection, typename Selection::size_type p,
575 std::random_access_iterator_tag) {
576 typedef typename boost::range_const_iterator<Selection>::type const_iterator;
577 typedef typename boost::range_size<Selection>::type size_type;
578 typedef std::pair<const_iterator, size_type> result_type;
579
580 const_iterator bound(std::lower_bound(boost::begin(selection), boost::end(selection), p));
581
582 return result_type(bound,
583 static_cast<size_type>(std::distance(boost::begin(selection), bound)));
584}
585
586/**************************************************************************************************/
592template <typename Selection>
593std::pair<typename boost::range_const_iterator<Selection>::type,
594 typename boost::range_size<Selection>::type>
595selection_find_boundary(const Selection& selection, typename Selection::size_type p,
596 std::forward_iterator_tag) {
597 typedef typename boost::range_const_iterator<Selection>::type const_iterator;
598 typedef typename boost::range_size<Selection>::type size_type;
599 typedef std::pair<const_iterator, size_type> result_type;
600
601 const_iterator iter(boost::begin(selection));
602 const_iterator last(boost::end(selection));
603 size_type boundary_count(0);
604
605 while (iter != last && *iter < p) {
606 ++boundary_count;
607 ++iter;
608 }
609
610 return result_type(iter, boundary_count);
611}
612
613/**************************************************************************************************/
632template <typename Selection>
633inline std::pair<typename boost::range_const_iterator<Selection>::type,
634 typename boost::range_size<Selection>::type>
635selection_find_boundary(const Selection& selection, typename Selection::size_type p) {
636 typedef typename boost::range_const_iterator<Selection>::type const_iterator;
637 typedef typename boost::range_size<Selection>::type size_type;
638 typedef std::pair<const_iterator, size_type> result_type;
639 typedef typename iterator_category<const_iterator>::type iterator_category;
640
641 if (boost::size(selection) == 0)
642 return result_type(boost::end(selection), 0);
643
644 return selection_find_boundary(selection, p, iterator_category());
645}
646
647/**************************************************************************************************/
679template <typename SelectionIterator, typename RangeIterator>
680RangeIterator selection_stable_partition(SelectionIterator selection_first,
681 SelectionIterator selection_last, RangeIterator first,
682 RangeIterator range_first, RangeIterator range_last,
683 std::size_t boundary_count = 0) {
684 std::size_t n(static_cast<std::size_t>(std::distance(selection_first, selection_last)));
685
686 if (n == 0)
687 return boundary_count % 2 ? range_first : range_last;
688
689 std::size_t half(n / 2);
690 SelectionIterator selection_middle(boost::next(selection_first, half));
691 RangeIterator range_middle(boost::next(first, *selection_middle));
692
693 RangeIterator i(selection_stable_partition(selection_first, selection_middle, first,
694 range_first, range_middle, boundary_count));
695
696 RangeIterator j(selection_stable_partition(boost::next(selection_middle), selection_last, first,
697 range_middle, range_last,
698 boundary_count + half + 1));
699
700 return other_of(adobe::rotate(i, range_middle, j), range_middle);
701}
702
703/**************************************************************************************************/
709template <typename Selection, typename ForwardRange>
710inline typename boost::range_iterator<ForwardRange>::type
711selection_stable_partition(const Selection& selection, ForwardRange& range) {
712 return selection_stable_partition(boost::begin(selection), boost::end(selection),
713 boost::begin(range), boost::begin(range), boost::end(range),
714 start_selected(selection));
715}
716
717/**************************************************************************************************/
753template <typename Selection, typename ForwardRange>
754std::pair<typename boost::range_iterator<ForwardRange>::type,
755 typename boost::range_iterator<ForwardRange>::type>
757 const Selection& selection, ForwardRange& range, std::size_t p,
758 typename boost::range_size<Selection>::type prior_boundary_count = 0) {
759 typedef typename boost::range_size<Selection>::type size_type;
760 typedef typename boost::range_const_iterator<Selection>::type selection_const_iterator;
761 typedef typename boost::range_iterator<ForwardRange>::type range_iterator;
762
763 std::pair<selection_const_iterator, size_type> selection_split =
764 adobe::selection_find_boundary(selection, p);
765
766 range_iterator first(boost::begin(range));
767 range_iterator range_p(boost::next(first, p));
768 range_iterator last(boost::end(range));
769
770 range_iterator i(selection_stable_partition(boost::begin(selection), selection_split.first,
771 first, first, range_p, prior_boundary_count));
772
773 range_iterator j(selection_stable_partition(selection_split.first, boost::end(selection), first,
774 range_p, last, selection_split.second + 1));
775
776 return std::pair<range_iterator, range_iterator>(i, j);
777}
778
779/**************************************************************************************************/
797template <typename I, typename N> // I models ForwardIterator
798std::pair<I, N> find_sequence_end(I f, I l, N n) {
799 while (f != l && n == *f) {
800 ++n;
801 ++f;
802 }
803 return {f, n};
804}
805
806
807/**************************************************************************************************/
817
818template <typename I, // I models ForwardIterator
819 typename O> // O models OutputIterator>
820void index_set_to_selection(I f, I l, O output) {
821 while (f != l) {
822 auto n = *f;
823 *output++ = n;
824 ++f;
825 ++n;
826 std::tie(f, n) = find_sequence_end(f, l, n);
827 *output++ = n;
828 }
829}
830
831/**************************************************************************************************/
863
864template <typename Selection, typename ForwardRange>
865Selection index_set_to_selection(const ForwardRange& index_set) {
866
867 Selection result;
868
869 index_set_to_selection(std::begin(index_set), std::end(index_set), std::back_inserter(result));
870
871 return result;
872}
873
874/**************************************************************************************************/
889template <typename Selection, typename OutputIterator>
890OutputIterator selection_to_index_set(const Selection& selection,
891 typename boost::range_size<Selection>::type max_index,
892 OutputIterator output) {
893 typedef typename boost::range_size<Selection>::type size_type;
894 typedef typename boost::range_const_iterator<Selection>::type selection_const_iterator;
895
896 bool selected(start_selected(selection));
897 size_type index(0);
898 selection_const_iterator iter(boost::begin(selection));
899 selection_const_iterator last(boost::end(selection));
900
901 while (iter != last) {
902 while (index != *iter && index != max_index) {
903 if (selected)
904 *output++ = index;
905
906 ++index;
907 }
908
909 selected = !selected;
910 ++iter;
911 }
912
913 if (selected)
914 while (index != max_index)
915 *output++ = index++;
916
917 return output;
918}
919
920/**************************************************************************************************/
921
922} // namespace adobe
923
924/**************************************************************************************************/
925
926#endif
927
928/**************************************************************************************************/
boost::range_difference< InputRange >::type count(InputRange &range, T &value)
count implementation
Definition count.hpp:40
const T & other_of(const P &pair, const T &x, BinaryPredicate pred)
other_of implementation
Definition other_of.hpp:37
std::pair< I, I > rotate(I f, I m, I l, std::bidirectional_iterator_tag)
Definition rotate.hpp:39
std::pair< typename boost::range_iterator< ForwardRange >::type, typename boost::range_iterator< ForwardRange >::type > selection_stable_partition_about(const Selection &selection, ForwardRange &range, std::size_t p, typename boost::range_size< Selection >::type prior_boundary_count=0)
RangeIterator selection_stable_partition(SelectionIterator selection_first, SelectionIterator selection_last, RangeIterator first, RangeIterator range_first, RangeIterator range_last, std::size_t boundary_count=0)
O selection_difference(S1 s1_first, S1 s1_last, S2 s2_first, S2 s2_last, O output, C comp, bool s1_inside=false, bool s2_inside=false)
selection_difference implementation
void index_set_to_selection(I f, I l, O output)
std::pair< O1, O2 > selection_partition_copy(const Selection &selection, ForwardRange &range, O1 false_output, O2 true_output)
selection_partition_copy implementation
O selection_operation(S1 s1_first, S1 s1_last, S2 s2_first, S2 s2_last, O output, bool s1_inside, bool s2_inside, P pred, C comp)
selection_operation implementation
O selection_union(S1 s1_first, S1 s1_last, S2 s2_first, S2 s2_last, O output, C comp, bool s1_inside=false, bool s2_inside=false)
selection_union implementation
O selection_symmetric_difference(S1 s1_first, S1 s1_last, S2 s2_first, S2 s2_last, O output, C comp, bool s1_inside=false, bool s2_inside=false)
selection_symmetric_difference implementation
std::pair< typename boost::range_const_iterator< Selection >::type, typename boost::range_size< Selection >::type > selection_find_boundary(const Selection &selection, typename Selection::size_type p, std::random_access_iterator_tag)
OutputIterator selection_copy(const Selection &x, const ForwardRange &range, OutputIterator output)
O selection_intersection(S1 s1_first, S1 s1_last, S2 s2_first, S2 s2_last, O output, C comp, bool s1_inside=false, bool s2_inside=false)
selection_intersection implementation
bool is_selected(const Selection &x, typename Selection::value_type index)
O selection_operation_remainder(S first, S last, O output, bool this_inside, bool other_inside, P pred)
void invert(Selection &x)
invert implementation
std::pair< I, N > find_sequence_end(I f, I l, N n)
UnaryFunction selection_foreach(const Selection &x, const ForwardRange &range, UnaryFunction proc)
selection_foreach implementation
bool start_selected(const Selection &x)
start_selected implementation
boost::range_size< Selection >::type size(const Selection &x)
bool selection_includes(S1 s1_first, S1 s1_last, S2 s2_first, S2 s2_last, C comp, bool s1_inside=false, bool s2_inside=false)
selection_includes implementation
OutputIterator selection_to_index_set(const Selection &selection, typename boost::range_size< Selection >::type max_index, OutputIterator output)
bool operator()(const C1 &x, const C2 &y) const