1 // (C) Copyright Herve Bronnimann 2004.
3 // Distributed under the Boost Software License, Version 1.0. (See accompanying
4 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
9 Split the code into two headers to lessen dependence on
12 Added the code for the boost minmax library. (Herve)
15 #ifndef BOOST_ALGORITHM_MINMAX_ELEMENT_HPP
16 #define BOOST_ALGORITHM_MINMAX_ELEMENT_HPP
18 /* PROPOSED STANDARD EXTENSIONS:
20 * minmax_element(first, last)
21 * Effect: std::make_pair( std::min_element(first, last),
22 * std::max_element(first, last) );
24 * minmax_element(first, last, comp)
25 * Effect: std::make_pair( std::min_element(first, last, comp),
26 * std::max_element(first, last, comp) );
29 #include <utility> // for std::pair and std::make_pair
33 namespace detail
{ // for obtaining a uniform version of minmax_element
34 // that compiles with VC++ 6.0 -- avoid the iterator_traits by
35 // having comparison object over iterator, not over dereferenced value
37 template <typename Iterator
>
38 struct less_over_iter
{
39 bool operator()(Iterator
const& it1
,
40 Iterator
const& it2
) const { return *it1
< *it2
; }
43 template <typename Iterator
, class BinaryPredicate
>
44 struct binary_pred_over_iter
{
45 explicit binary_pred_over_iter(BinaryPredicate
const& p
) : m_p( p
) {}
46 bool operator()(Iterator
const& it1
,
47 Iterator
const& it2
) const { return m_p(*it1
, *it2
); }
52 // common base for the two minmax_element overloads
54 template <typename ForwardIter
, class Compare
>
55 std::pair
<ForwardIter
,ForwardIter
>
56 basic_minmax_element(ForwardIter first
, ForwardIter last
, Compare comp
)
59 return std::make_pair(last
,last
);
61 ForwardIter min_result
= first
;
62 ForwardIter max_result
= first
;
64 // if only one element
65 ForwardIter second
= first
; ++second
;
67 return std::make_pair(min_result
, max_result
);
69 // treat first pair separately (only one comparison for first two elements)
70 ForwardIter potential_min_result
= last
;
71 if (comp(first
, second
))
75 potential_min_result
= first
;
78 // then each element by pairs, with at most 3 comparisons per pair
79 first
= ++second
; if (first
!= last
) ++second
;
80 while (second
!= last
) {
81 if (comp(first
, second
)) {
82 if (comp(first
, min_result
)) {
84 potential_min_result
= last
;
86 if (comp(max_result
, second
))
89 if (comp(second
, min_result
)) {
91 potential_min_result
= first
;
93 if (comp(max_result
, first
))
97 if (first
!= last
) ++second
;
100 // if odd number of elements, treat last element
101 if (first
!= last
) { // odd number of elements
102 if (comp(first
, min_result
))
103 min_result
= first
, potential_min_result
= last
;
104 else if (comp(max_result
, first
))
108 // resolve min_result being incorrect with one extra comparison
109 // (in which case potential_min_result is necessarily the correct result)
110 if (potential_min_result
!= last
111 && !comp(min_result
, potential_min_result
))
112 min_result
= potential_min_result
;
114 return std::make_pair(min_result
,max_result
);
117 } // namespace detail
119 template <typename ForwardIter
>
120 std::pair
<ForwardIter
,ForwardIter
>
121 minmax_element(ForwardIter first
, ForwardIter last
)
123 return detail::basic_minmax_element(first
, last
,
124 detail::less_over_iter
<ForwardIter
>() );
127 template <typename ForwardIter
, class BinaryPredicate
>
128 std::pair
<ForwardIter
,ForwardIter
>
129 minmax_element(ForwardIter first
, ForwardIter last
, BinaryPredicate comp
)
131 return detail::basic_minmax_element(first
, last
,
132 detail::binary_pred_over_iter
<ForwardIter
,BinaryPredicate
>(comp
) );
137 /* PROPOSED BOOST EXTENSIONS
138 * In the description below, [rfirst,rlast) denotes the reversed range
139 * of [first,last). Even though the iterator type of first and last may
140 * be only a Forward Iterator, it is possible to explain the semantics
141 * by assuming that it is a Bidirectional Iterator. In the sequel,
142 * reverse(ForwardIterator&) returns the reverse_iterator adaptor.
143 * This is not how the functions would be implemented!
145 * first_min_element(first, last)
146 * Effect: std::min_element(first, last);
148 * first_min_element(first, last, comp)
149 * Effect: std::min_element(first, last, comp);
151 * last_min_element(first, last)
152 * Effect: reverse( std::min_element(reverse(last), reverse(first)) );
154 * last_min_element(first, last, comp)
155 * Effect: reverse( std::min_element(reverse(last), reverse(first), comp) );
157 * first_max_element(first, last)
158 * Effect: std::max_element(first, last);
160 * first_max_element(first, last, comp)
161 * Effect: max_element(first, last);
163 * last_max_element(first, last)
164 * Effect: reverse( std::max_element(reverse(last), reverse(first)) );
166 * last_max_element(first, last, comp)
167 * Effect: reverse( std::max_element(reverse(last), reverse(first), comp) );
169 * first_min_first_max_element(first, last)
170 * Effect: std::make_pair( first_min_element(first, last),
171 * first_max_element(first, last) );
173 * first_min_first_max_element(first, last, comp)
174 * Effect: std::make_pair( first_min_element(first, last, comp),
175 * first_max_element(first, last, comp) );
177 * first_min_last_max_element(first, last)
178 * Effect: std::make_pair( first_min_element(first, last),
179 * last_max_element(first, last) );
181 * first_min_last_max_element(first, last, comp)
182 * Effect: std::make_pair( first_min_element(first, last, comp),
183 * last_max_element(first, last, comp) );
185 * last_min_first_max_element(first, last)
186 * Effect: std::make_pair( last_min_element(first, last),
187 * first_max_element(first, last) );
189 * last_min_first_max_element(first, last, comp)
190 * Effect: std::make_pair( last_min_element(first, last, comp),
191 * first_max_element(first, last, comp) );
193 * last_min_last_max_element(first, last)
194 * Effect: std::make_pair( last_min_element(first, last),
195 * last_max_element(first, last) );
197 * last_min_last_max_element(first, last, comp)
198 * Effect: std::make_pair( last_min_element(first, last, comp),
199 * last_max_element(first, last, comp) );
204 // Min_element and max_element variants
206 namespace detail
{ // common base for the overloads
208 template <typename ForwardIter
, class BinaryPredicate
>
210 basic_first_min_element(ForwardIter first
, ForwardIter last
,
211 BinaryPredicate comp
)
213 if (first
== last
) return last
;
214 ForwardIter min_result
= first
;
215 while (++first
!= last
)
216 if (comp(first
, min_result
))
221 template <typename ForwardIter
, class BinaryPredicate
>
223 basic_last_min_element(ForwardIter first
, ForwardIter last
,
224 BinaryPredicate comp
)
226 if (first
== last
) return last
;
227 ForwardIter min_result
= first
;
228 while (++first
!= last
)
229 if (!comp(min_result
, first
))
234 template <typename ForwardIter
, class BinaryPredicate
>
236 basic_first_max_element(ForwardIter first
, ForwardIter last
,
237 BinaryPredicate comp
)
239 if (first
== last
) return last
;
240 ForwardIter max_result
= first
;
241 while (++first
!= last
)
242 if (comp(max_result
, first
))
247 template <typename ForwardIter
, class BinaryPredicate
>
249 basic_last_max_element(ForwardIter first
, ForwardIter last
,
250 BinaryPredicate comp
)
252 if (first
== last
) return last
;
253 ForwardIter max_result
= first
;
254 while (++first
!= last
)
255 if (!comp(first
, max_result
))
260 } // namespace detail
262 template <typename ForwardIter
>
264 first_min_element(ForwardIter first
, ForwardIter last
)
266 return detail::basic_first_min_element(first
, last
,
267 detail::less_over_iter
<ForwardIter
>() );
270 template <typename ForwardIter
, class BinaryPredicate
>
272 first_min_element(ForwardIter first
, ForwardIter last
, BinaryPredicate comp
)
274 return detail::basic_first_min_element(first
, last
,
275 detail::binary_pred_over_iter
<ForwardIter
,BinaryPredicate
>(comp
) );
278 template <typename ForwardIter
>
280 last_min_element(ForwardIter first
, ForwardIter last
)
282 return detail::basic_last_min_element(first
, last
,
283 detail::less_over_iter
<ForwardIter
>() );
286 template <typename ForwardIter
, class BinaryPredicate
>
288 last_min_element(ForwardIter first
, ForwardIter last
, BinaryPredicate comp
)
290 return detail::basic_last_min_element(first
, last
,
291 detail::binary_pred_over_iter
<ForwardIter
,BinaryPredicate
>(comp
) );
294 template <typename ForwardIter
>
296 first_max_element(ForwardIter first
, ForwardIter last
)
298 return detail::basic_first_max_element(first
, last
,
299 detail::less_over_iter
<ForwardIter
>() );
302 template <typename ForwardIter
, class BinaryPredicate
>
304 first_max_element(ForwardIter first
, ForwardIter last
, BinaryPredicate comp
)
306 return detail::basic_first_max_element(first
, last
,
307 detail::binary_pred_over_iter
<ForwardIter
,BinaryPredicate
>(comp
) );
310 template <typename ForwardIter
>
312 last_max_element(ForwardIter first
, ForwardIter last
)
314 return detail::basic_last_max_element(first
, last
,
315 detail::less_over_iter
<ForwardIter
>() );
318 template <typename ForwardIter
, class BinaryPredicate
>
320 last_max_element(ForwardIter first
, ForwardIter last
, BinaryPredicate comp
)
322 return detail::basic_last_max_element(first
, last
,
323 detail::binary_pred_over_iter
<ForwardIter
,BinaryPredicate
>(comp
) );
327 // Minmax_element variants -- comments removed
331 template <typename ForwardIter
, class BinaryPredicate
>
332 std::pair
<ForwardIter
,ForwardIter
>
333 basic_first_min_last_max_element(ForwardIter first
, ForwardIter last
,
334 BinaryPredicate comp
)
337 return std::make_pair(last
,last
);
339 ForwardIter min_result
= first
;
340 ForwardIter max_result
= first
;
342 ForwardIter second
= ++first
;
344 return std::make_pair(min_result
, max_result
);
346 if (comp(second
, min_result
))
351 first
= ++second
; if (first
!= last
) ++second
;
352 while (second
!= last
) {
353 if (!comp(second
, first
)) {
354 if (comp(first
, min_result
))
356 if (!comp(second
, max_result
))
359 if (comp(second
, min_result
))
361 if (!comp(first
, max_result
))
364 first
= ++second
; if (first
!= last
) ++second
;
368 if (comp(first
, min_result
))
370 else if (!comp(first
, max_result
))
374 return std::make_pair(min_result
, max_result
);
377 template <typename ForwardIter
, class BinaryPredicate
>
378 std::pair
<ForwardIter
,ForwardIter
>
379 basic_last_min_first_max_element(ForwardIter first
, ForwardIter last
,
380 BinaryPredicate comp
)
382 if (first
== last
) return std::make_pair(last
,last
);
384 ForwardIter min_result
= first
;
385 ForwardIter max_result
= first
;
387 ForwardIter second
= ++first
;
389 return std::make_pair(min_result
, max_result
);
391 if (comp(max_result
, second
))
396 first
= ++second
; if (first
!= last
) ++second
;
397 while (second
!= last
) {
398 if (comp(first
, second
)) {
399 if (!comp(min_result
, first
))
401 if (comp(max_result
, second
))
404 if (!comp(min_result
, second
))
406 if (comp(max_result
, first
))
409 first
= ++second
; if (first
!= last
) ++second
;
413 if (!comp(min_result
, first
))
415 else if (comp(max_result
, first
))
419 return std::make_pair(min_result
, max_result
);
422 template <typename ForwardIter
, class BinaryPredicate
>
423 std::pair
<ForwardIter
,ForwardIter
>
424 basic_last_min_last_max_element(ForwardIter first
, ForwardIter last
,
425 BinaryPredicate comp
)
427 if (first
== last
) return std::make_pair(last
,last
);
429 ForwardIter min_result
= first
;
430 ForwardIter max_result
= first
;
432 ForwardIter second
= first
; ++second
;
434 return std::make_pair(min_result
,max_result
);
436 ForwardIter potential_max_result
= last
;
437 if (comp(first
, second
))
441 potential_max_result
= second
;
444 first
= ++second
; if (first
!= last
) ++second
;
445 while (second
!= last
) {
446 if (comp(first
, second
)) {
447 if (!comp(min_result
, first
))
449 if (!comp(second
, max_result
)) {
451 potential_max_result
= last
;
454 if (!comp(min_result
, second
))
456 if (!comp(first
, max_result
)) {
458 potential_max_result
= second
;
462 if (first
!= last
) ++second
;
466 if (!comp(min_result
, first
))
468 if (!comp(first
, max_result
)) {
470 potential_max_result
= last
;
474 if (potential_max_result
!= last
475 && !comp(potential_max_result
, max_result
))
476 max_result
= potential_max_result
;
478 return std::make_pair(min_result
,max_result
);
481 } // namespace detail
483 template <typename ForwardIter
>
484 inline std::pair
<ForwardIter
,ForwardIter
>
485 first_min_first_max_element(ForwardIter first
, ForwardIter last
)
487 return minmax_element(first
, last
);
490 template <typename ForwardIter
, class BinaryPredicate
>
491 inline std::pair
<ForwardIter
,ForwardIter
>
492 first_min_first_max_element(ForwardIter first
, ForwardIter last
,
493 BinaryPredicate comp
)
495 return minmax_element(first
, last
, comp
);
498 template <typename ForwardIter
>
499 std::pair
<ForwardIter
,ForwardIter
>
500 first_min_last_max_element(ForwardIter first
, ForwardIter last
)
502 return detail::basic_first_min_last_max_element(first
, last
,
503 detail::less_over_iter
<ForwardIter
>() );
506 template <typename ForwardIter
, class BinaryPredicate
>
507 inline std::pair
<ForwardIter
,ForwardIter
>
508 first_min_last_max_element(ForwardIter first
, ForwardIter last
,
509 BinaryPredicate comp
)
511 return detail::basic_first_min_last_max_element(first
, last
,
512 detail::binary_pred_over_iter
<ForwardIter
,BinaryPredicate
>(comp
) );
515 template <typename ForwardIter
>
516 std::pair
<ForwardIter
,ForwardIter
>
517 last_min_first_max_element(ForwardIter first
, ForwardIter last
)
519 return detail::basic_last_min_first_max_element(first
, last
,
520 detail::less_over_iter
<ForwardIter
>() );
523 template <typename ForwardIter
, class BinaryPredicate
>
524 inline std::pair
<ForwardIter
,ForwardIter
>
525 last_min_first_max_element(ForwardIter first
, ForwardIter last
,
526 BinaryPredicate comp
)
528 return detail::basic_last_min_first_max_element(first
, last
,
529 detail::binary_pred_over_iter
<ForwardIter
,BinaryPredicate
>(comp
) );
532 template <typename ForwardIter
>
533 std::pair
<ForwardIter
,ForwardIter
>
534 last_min_last_max_element(ForwardIter first
, ForwardIter last
)
536 return detail::basic_last_min_last_max_element(first
, last
,
537 detail::less_over_iter
<ForwardIter
>() );
540 template <typename ForwardIter
, class BinaryPredicate
>
541 inline std::pair
<ForwardIter
,ForwardIter
>
542 last_min_last_max_element(ForwardIter first
, ForwardIter last
,
543 BinaryPredicate comp
)
545 return detail::basic_last_min_last_max_element(first
, last
,
546 detail::binary_pred_over_iter
<ForwardIter
,BinaryPredicate
>(comp
) );
551 #endif // BOOST_ALGORITHM_MINMAX_ELEMENT_HPP