// (C) Copyright Herve Bronnimann 2004. // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) /* Revision history: 1 July 2004 Split the code into two headers to lessen dependence on Boost.tuple. (Herve) 26 June 2004 Added the code for the boost minmax library. (Herve) */ #ifndef BOOST_ALGORITHM_MINMAX_ELEMENT_HPP #define BOOST_ALGORITHM_MINMAX_ELEMENT_HPP /* PROPOSED STANDARD EXTENSIONS: * * minmax_element(first, last) * Effect: std::make_pair( std::min_element(first, last), * std::max_element(first, last) ); * * minmax_element(first, last, comp) * Effect: std::make_pair( std::min_element(first, last, comp), * std::max_element(first, last, comp) ); */ #include // for std::pair and std::make_pair namespace boost { namespace detail { // for obtaining a uniform version of minmax_element // that compiles with VC++ 6.0 -- avoid the iterator_traits by // having comparison object over iterator, not over dereferenced value template struct less_over_iter { bool operator()(Iterator const& it1, Iterator const& it2) const { return *it1 < *it2; } }; template struct binary_pred_over_iter { explicit binary_pred_over_iter(BinaryPredicate const& p ) : m_p( p ) {} bool operator()(Iterator const& it1, Iterator const& it2) const { return m_p(*it1, *it2); } private: BinaryPredicate m_p; }; // common base for the two minmax_element overloads template std::pair basic_minmax_element(ForwardIter first, ForwardIter last, Compare comp) { if (first == last) return std::make_pair(last,last); ForwardIter min_result = first; ForwardIter max_result = first; // if only one element ForwardIter second = first; ++second; if (second == last) return std::make_pair(min_result, max_result); // treat first pair separately (only one comparison for first two elements) ForwardIter potential_min_result = last; if (comp(first, second)) max_result = second; else { min_result = second; potential_min_result = first; } // then each element by pairs, with at most 3 comparisons per pair first = ++second; if (first != last) ++second; while (second != last) { if (comp(first, second)) { if (comp(first, min_result)) { min_result = first; potential_min_result = last; } if (comp(max_result, second)) max_result = second; } else { if (comp(second, min_result)) { min_result = second; potential_min_result = first; } if (comp(max_result, first)) max_result = first; } first = ++second; if (first != last) ++second; } // if odd number of elements, treat last element if (first != last) { // odd number of elements if (comp(first, min_result)) min_result = first, potential_min_result = last; else if (comp(max_result, first)) max_result = first; } // resolve min_result being incorrect with one extra comparison // (in which case potential_min_result is necessarily the correct result) if (potential_min_result != last && !comp(min_result, potential_min_result)) min_result = potential_min_result; return std::make_pair(min_result,max_result); } } // namespace detail template std::pair minmax_element(ForwardIter first, ForwardIter last) { return detail::basic_minmax_element(first, last, detail::less_over_iter() ); } template std::pair minmax_element(ForwardIter first, ForwardIter last, BinaryPredicate comp) { return detail::basic_minmax_element(first, last, detail::binary_pred_over_iter(comp) ); } } /* PROPOSED BOOST EXTENSIONS * In the description below, [rfirst,rlast) denotes the reversed range * of [first,last). Even though the iterator type of first and last may * be only a Forward Iterator, it is possible to explain the semantics * by assuming that it is a Bidirectional Iterator. In the sequel, * reverse(ForwardIterator&) returns the reverse_iterator adaptor. * This is not how the functions would be implemented! * * first_min_element(first, last) * Effect: std::min_element(first, last); * * first_min_element(first, last, comp) * Effect: std::min_element(first, last, comp); * * last_min_element(first, last) * Effect: reverse( std::min_element(reverse(last), reverse(first)) ); * * last_min_element(first, last, comp) * Effect: reverse( std::min_element(reverse(last), reverse(first), comp) ); * * first_max_element(first, last) * Effect: std::max_element(first, last); * * first_max_element(first, last, comp) * Effect: max_element(first, last); * * last_max_element(first, last) * Effect: reverse( std::max_element(reverse(last), reverse(first)) ); * * last_max_element(first, last, comp) * Effect: reverse( std::max_element(reverse(last), reverse(first), comp) ); * * first_min_first_max_element(first, last) * Effect: std::make_pair( first_min_element(first, last), * first_max_element(first, last) ); * * first_min_first_max_element(first, last, comp) * Effect: std::make_pair( first_min_element(first, last, comp), * first_max_element(first, last, comp) ); * * first_min_last_max_element(first, last) * Effect: std::make_pair( first_min_element(first, last), * last_max_element(first, last) ); * * first_min_last_max_element(first, last, comp) * Effect: std::make_pair( first_min_element(first, last, comp), * last_max_element(first, last, comp) ); * * last_min_first_max_element(first, last) * Effect: std::make_pair( last_min_element(first, last), * first_max_element(first, last) ); * * last_min_first_max_element(first, last, comp) * Effect: std::make_pair( last_min_element(first, last, comp), * first_max_element(first, last, comp) ); * * last_min_last_max_element(first, last) * Effect: std::make_pair( last_min_element(first, last), * last_max_element(first, last) ); * * last_min_last_max_element(first, last, comp) * Effect: std::make_pair( last_min_element(first, last, comp), * last_max_element(first, last, comp) ); */ namespace boost { // Min_element and max_element variants namespace detail { // common base for the overloads template ForwardIter basic_first_min_element(ForwardIter first, ForwardIter last, BinaryPredicate comp) { if (first == last) return last; ForwardIter min_result = first; while (++first != last) if (comp(first, min_result)) min_result = first; return min_result; } template ForwardIter basic_last_min_element(ForwardIter first, ForwardIter last, BinaryPredicate comp) { if (first == last) return last; ForwardIter min_result = first; while (++first != last) if (!comp(min_result, first)) min_result = first; return min_result; } template ForwardIter basic_first_max_element(ForwardIter first, ForwardIter last, BinaryPredicate comp) { if (first == last) return last; ForwardIter max_result = first; while (++first != last) if (comp(max_result, first)) max_result = first; return max_result; } template ForwardIter basic_last_max_element(ForwardIter first, ForwardIter last, BinaryPredicate comp) { if (first == last) return last; ForwardIter max_result = first; while (++first != last) if (!comp(first, max_result)) max_result = first; return max_result; } } // namespace detail template ForwardIter first_min_element(ForwardIter first, ForwardIter last) { return detail::basic_first_min_element(first, last, detail::less_over_iter() ); } template ForwardIter first_min_element(ForwardIter first, ForwardIter last, BinaryPredicate comp) { return detail::basic_first_min_element(first, last, detail::binary_pred_over_iter(comp) ); } template ForwardIter last_min_element(ForwardIter first, ForwardIter last) { return detail::basic_last_min_element(first, last, detail::less_over_iter() ); } template ForwardIter last_min_element(ForwardIter first, ForwardIter last, BinaryPredicate comp) { return detail::basic_last_min_element(first, last, detail::binary_pred_over_iter(comp) ); } template ForwardIter first_max_element(ForwardIter first, ForwardIter last) { return detail::basic_first_max_element(first, last, detail::less_over_iter() ); } template ForwardIter first_max_element(ForwardIter first, ForwardIter last, BinaryPredicate comp) { return detail::basic_first_max_element(first, last, detail::binary_pred_over_iter(comp) ); } template ForwardIter last_max_element(ForwardIter first, ForwardIter last) { return detail::basic_last_max_element(first, last, detail::less_over_iter() ); } template ForwardIter last_max_element(ForwardIter first, ForwardIter last, BinaryPredicate comp) { return detail::basic_last_max_element(first, last, detail::binary_pred_over_iter(comp) ); } // Minmax_element variants -- comments removed namespace detail { template std::pair basic_first_min_last_max_element(ForwardIter first, ForwardIter last, BinaryPredicate comp) { if (first == last) return std::make_pair(last,last); ForwardIter min_result = first; ForwardIter max_result = first; ForwardIter second = ++first; if (second == last) return std::make_pair(min_result, max_result); if (comp(second, min_result)) min_result = second; else max_result = second; first = ++second; if (first != last) ++second; while (second != last) { if (!comp(second, first)) { if (comp(first, min_result)) min_result = first; if (!comp(second, max_result)) max_result = second; } else { if (comp(second, min_result)) min_result = second; if (!comp(first, max_result)) max_result = first; } first = ++second; if (first != last) ++second; } if (first != last) { if (comp(first, min_result)) min_result = first; else if (!comp(first, max_result)) max_result = first; } return std::make_pair(min_result, max_result); } template std::pair basic_last_min_first_max_element(ForwardIter first, ForwardIter last, BinaryPredicate comp) { if (first == last) return std::make_pair(last,last); ForwardIter min_result = first; ForwardIter max_result = first; ForwardIter second = ++first; if (second == last) return std::make_pair(min_result, max_result); if (comp(max_result, second)) max_result = second; else min_result = second; first = ++second; if (first != last) ++second; while (second != last) { if (comp(first, second)) { if (!comp(min_result, first)) min_result = first; if (comp(max_result, second)) max_result = second; } else { if (!comp(min_result, second)) min_result = second; if (comp(max_result, first)) max_result = first; } first = ++second; if (first != last) ++second; } if (first != last) { if (!comp(min_result, first)) min_result = first; else if (comp(max_result, first)) max_result = first; } return std::make_pair(min_result, max_result); } template std::pair basic_last_min_last_max_element(ForwardIter first, ForwardIter last, BinaryPredicate comp) { if (first == last) return std::make_pair(last,last); ForwardIter min_result = first; ForwardIter max_result = first; ForwardIter second = first; ++second; if (second == last) return std::make_pair(min_result,max_result); ForwardIter potential_max_result = last; if (comp(first, second)) max_result = second; else { min_result = second; potential_max_result = second; } first = ++second; if (first != last) ++second; while (second != last) { if (comp(first, second)) { if (!comp(min_result, first)) min_result = first; if (!comp(second, max_result)) { max_result = second; potential_max_result = last; } } else { if (!comp(min_result, second)) min_result = second; if (!comp(first, max_result)) { max_result = first; potential_max_result = second; } } first = ++second; if (first != last) ++second; } if (first != last) { if (!comp(min_result, first)) min_result = first; if (!comp(first, max_result)) { max_result = first; potential_max_result = last; } } if (potential_max_result != last && !comp(potential_max_result, max_result)) max_result = potential_max_result; return std::make_pair(min_result,max_result); } } // namespace detail template inline std::pair first_min_first_max_element(ForwardIter first, ForwardIter last) { return minmax_element(first, last); } template inline std::pair first_min_first_max_element(ForwardIter first, ForwardIter last, BinaryPredicate comp) { return minmax_element(first, last, comp); } template std::pair first_min_last_max_element(ForwardIter first, ForwardIter last) { return detail::basic_first_min_last_max_element(first, last, detail::less_over_iter() ); } template inline std::pair first_min_last_max_element(ForwardIter first, ForwardIter last, BinaryPredicate comp) { return detail::basic_first_min_last_max_element(first, last, detail::binary_pred_over_iter(comp) ); } template std::pair last_min_first_max_element(ForwardIter first, ForwardIter last) { return detail::basic_last_min_first_max_element(first, last, detail::less_over_iter() ); } template inline std::pair last_min_first_max_element(ForwardIter first, ForwardIter last, BinaryPredicate comp) { return detail::basic_last_min_first_max_element(first, last, detail::binary_pred_over_iter(comp) ); } template std::pair last_min_last_max_element(ForwardIter first, ForwardIter last) { return detail::basic_last_min_last_max_element(first, last, detail::less_over_iter() ); } template inline std::pair last_min_last_max_element(ForwardIter first, ForwardIter last, BinaryPredicate comp) { return detail::basic_last_min_last_max_element(first, last, detail::binary_pred_over_iter(comp) ); } } // namespace boost #endif // BOOST_ALGORITHM_MINMAX_ELEMENT_HPP