diff --git a/sprout/algorithm/minmax_element.hpp b/sprout/algorithm/minmax_element.hpp index 0f345f17..a76c44fb 100644 --- a/sprout/algorithm/minmax_element.hpp +++ b/sprout/algorithm/minmax_element.hpp @@ -35,28 +35,37 @@ namespace sprout { comp(*b, *sprout::second(a)) ? sprout::second(a) : b ); } + template + inline SPROUT_CONSTEXPR sprout::pair + iter_minmax(ForwardIterator a, ForwardIterator b, Compare comp) { + typedef sprout::pair type; + return comp(*b, *a) + ? type(b, a) + : type(a, b) + ; + } template inline SPROUT_CONSTEXPR sprout::pair minmax_element_impl_ra( - RandomAccessIterator first, RandomAccessIterator last, Compare comp, - typename std::iterator_traits::difference_type pivot + RandomAccessIterator first, Compare comp, + typename std::iterator_traits::difference_type half ) { - return pivot == 0 ? sprout::pair(first, first) + return half == 1 + ? iter_minmax(first, sprout::next(first), comp) : sprout::detail::iter_minmax_pair( sprout::detail::minmax_element_impl_ra( - first, sprout::next(first, pivot), comp, - pivot / 2 + first, comp, half / 2 ), sprout::detail::minmax_element_impl_ra( - sprout::next(first, pivot), last, comp, - (sprout::distance(first, last) - pivot) / 2 + sprout::next(first, half - (half & 1)), comp, (half + 1) / 2 ), comp ) ; } + template inline SPROUT_CONSTEXPR typename std::enable_if< sprout::is_constant_distance_iterator::value, @@ -67,10 +76,43 @@ namespace sprout { std::random_access_iterator_tag* ) { - return first == last ? sprout::pair(last, last) - : sprout::detail::minmax_element_impl_ra( - first, last, comp, - sprout::distance(first, last) / 2 + return first == last || sprout::next(first) == last + ? sprout::pair(first, first) + : sprout::distance(first, last) % 2 == 0 + ? sprout::detail::minmax_element_impl_ra( + first, comp, + sprout::distance(first, last) / 2 + ) + : sprout::detail::iter_minmax( + sprout::detail::minmax_element_impl_ra( + first, comp, + sprout::distance(first, last) / 2 + ), + sprout::prev(last), + comp + ) + ; + } + + template + inline SPROUT_CONSTEXPR sprout::pair > + minmax_element_impl_3( + sprout::pair minmax, + ForwardIterator first, ForwardIterator next, + ForwardIterator last, Compare comp) { + typedef sprout::pair > type; + return next == last + ? type( + next, + sprout::detail::iter_minmax(minmax, first, comp) + ) + : type( + sprout::next(next), + sprout::detail::iter_minmax_pair( + minmax, + sprout::detail::iter_minmax(first, next, comp), + comp + ) ) ; } @@ -82,9 +124,10 @@ namespace sprout { ForwardIterator last, Compare comp, typename std::iterator_traits::difference_type n ) { - typedef sprout::pair > type; return current.first == last ? current - : n == 1 ? type(sprout::next(current.first), sprout::detail::iter_minmax(current.second, current.first, comp)) + : n == 1 ? sprout::detail::minmax_element_impl_3( + current.second, current.first, sprout::next(current.first), + last, comp) : sprout::detail::minmax_element_impl_1( sprout::detail::minmax_element_impl_1( current, @@ -94,6 +137,7 @@ namespace sprout { ) ; } + template inline SPROUT_CONSTEXPR sprout::pair > minmax_element_impl( @@ -111,6 +155,19 @@ namespace sprout { ) ; } + + template + inline SPROUT_CONSTEXPR sprout::pair > + minmax_element_impl_2( + ForwardIterator first, ForwardIterator next, ForwardIterator last, Compare comp + ) + { + typedef sprout::pair type; + return next == last ? sprout::pair(next, type(first, first)) + : sprout::pair(sprout::next(next), iter_minmax(first, next, comp)) + ; + } + template inline SPROUT_CONSTEXPR sprout::pair minmax_element( @@ -118,9 +175,10 @@ namespace sprout { std::forward_iterator_tag* ) { - typedef sprout::pair > type; return first == last ? sprout::pair(first, first) - : sprout::detail::minmax_element_impl(type(sprout::next(first), sprout::pair(first, first)), last, comp, 1).second + : sprout::detail::minmax_element_impl( + sprout::detail::minmax_element_impl_2(first, sprout::next(first), last, comp), + last, comp, 1).second ; } } // namespace detail