Finally adding the minmax library. Still allowing overlap with header

minmax.hpp from Eric Niebler, which should be resolved soon. --Herve'


[SVN r23225]
This commit is contained in:
Hervé Brönnimann
2004-06-28 08:36:43 +00:00
parent 752c65be35
commit 1e7aec2dee
10 changed files with 2214 additions and 3 deletions

View File

@ -1,17 +1,25 @@
// (C) Copyright Eric Niebler 2004. // (C) Copyright Eric Niebler 2004.
// (C) Copyright Herve Bronnimann 2004.
// Use, modification and distribution are subject to the // Use, modification and distribution are subject to the
// Boost Software License, Version 1.0. (See accompanying file // Boost Software License, Version 1.0. (See accompanying file
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
/* /*
Revision history: Revision history:
26 June 2004
Added the code for the boost minmax library. (Herve)
25 February 2004 25 February 2004
Initial version. Initial version. (Eric)
*/ */
#ifndef BOOST_MINMAX_HPP #ifndef BOOST_MINMAX_HPP
#define BOOST_MINMAX_HPP #define BOOST_MINMAX_HPP
/*
* These macros by Eric Niebler should move into a config file.
* I'll leave them for now, until Eric sees fit to remove them.
*/
#include <algorithm> // for std::min and std::max #include <algorithm> // for std::min and std::max
#include <boost/config.hpp> #include <boost/config.hpp>
@ -21,4 +29,563 @@
#define BOOST_USING_STD_MAX()\ #define BOOST_USING_STD_MAX()\
using std::max using std::max
/* PROPOSED STANDARD EXTENSIONS:
*
* minmax(a, b)
* Effect: (b<a) ? std::make_pair(b,a) : std::make_pair(a,b);
*
* minmax(a, b, comp)
* Effect: comp(b,a) ? std::make_pair(b,a) : std::make_pair(a,b);
*
* 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 <utility> // for std::pair and std::make_pair
#include <boost/iterator/iterator_traits.hpp> // for boost::iterator_value<Iter>
namespace boost {
template <typename T>
std::pair<T&,T&>
minmax(T& a, T& b) {
return (b<a) ? std::make_pair(b,a) : std::make_pair(a,b);
}
template <typename T, class BinaryPredicate>
std::pair<T&,T&>
minmax(T& a, T& b, BinaryPredicate comp) {
return comp(b,a) ? std::make_pair(b,a) : std::make_pair(a,b);
}
template <typename T>
std::pair<const T&,const T&>
minmax(const T& a, const T& b) {
return (b<a) ? std::make_pair(b,a) : std::make_pair(a,b);
}
template <typename T, class BinaryPredicate>
std::pair<const T&,const T&>
minmax(const T& a, const T& b, BinaryPredicate comp) {
return comp(b,a) ? std::make_pair(b,a) : std::make_pair(a,b);
}
namespace detail { // for compilation with VC++ 6.0
template <typename ForwardIter, class Compare >
std::pair<ForwardIter,ForwardIter>
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);
}
template <typename Iterator>
struct less_over_iter {
bool operator()(Iterator const& it1,
Iterator const& it2) const { return *it1 < *it2; }
};
template <typename Iterator, class BinaryPredicate>
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;
};
} // namespace detail
template <typename ForwardIter>
std::pair<ForwardIter,ForwardIter>
minmax_element(ForwardIter first, ForwardIter last)
{
return detail::basic_minmax_element(first, last,
detail::less_over_iter<ForwardIter>() );
}
template <typename ForwardIter, class BinaryPredicate>
std::pair<ForwardIter,ForwardIter>
minmax_element(ForwardIter first, ForwardIter last, BinaryPredicate comp)
{
return detail::basic_minmax_element(first, last,
detail::binary_pred_over_iter<ForwardIter,BinaryPredicate>(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 {
namespace detail {
template <typename ForwardIter, class BinaryPredicate>
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 <typename ForwardIter, class BinaryPredicate>
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 <typename ForwardIter, class BinaryPredicate>
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 <typename ForwardIter, class BinaryPredicate>
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 <typename ForwardIter>
ForwardIter
first_min_element(ForwardIter first, ForwardIter last)
{
return detail::basic_first_min_element(first, last,
detail::less_over_iter<ForwardIter>() );
}
template <typename ForwardIter, class BinaryPredicate>
ForwardIter
first_min_element(ForwardIter first, ForwardIter last, BinaryPredicate comp)
{
return detail::basic_first_min_element(first, last,
detail::binary_pred_over_iter<ForwardIter,BinaryPredicate>(comp) );
}
template <typename ForwardIter>
ForwardIter
last_min_element(ForwardIter first, ForwardIter last)
{
return detail::basic_last_min_element(first, last,
detail::less_over_iter<ForwardIter>() );
}
template <typename ForwardIter, class BinaryPredicate>
ForwardIter
last_min_element(ForwardIter first, ForwardIter last, BinaryPredicate comp)
{
return detail::basic_last_min_element(first, last,
detail::binary_pred_over_iter<ForwardIter,BinaryPredicate>(comp) );
}
template <typename ForwardIter>
ForwardIter
first_max_element(ForwardIter first, ForwardIter last)
{
return detail::basic_first_max_element(first, last,
detail::less_over_iter<ForwardIter>() );
}
template <typename ForwardIter, class BinaryPredicate>
ForwardIter
first_max_element(ForwardIter first, ForwardIter last, BinaryPredicate comp)
{
return detail::basic_first_max_element(first, last,
detail::binary_pred_over_iter<ForwardIter,BinaryPredicate>(comp) );
}
template <typename ForwardIter>
ForwardIter
last_max_element(ForwardIter first, ForwardIter last)
{
return detail::basic_last_max_element(first, last,
detail::less_over_iter<ForwardIter>() );
}
template <typename ForwardIter, class BinaryPredicate>
ForwardIter
last_max_element(ForwardIter first, ForwardIter last, BinaryPredicate comp)
{
return detail::basic_last_max_element(first, last,
detail::binary_pred_over_iter<ForwardIter,BinaryPredicate>(comp) );
}
// Minmax variants -- comments removed
namespace detail {
template <typename ForwardIter, class BinaryPredicate>
std::pair<ForwardIter,ForwardIter>
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 <typename ForwardIter, class BinaryPredicate>
std::pair<ForwardIter,ForwardIter>
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 <typename ForwardIter, class BinaryPredicate>
std::pair<ForwardIter,ForwardIter>
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 <typename ForwardIter>
inline std::pair<ForwardIter,ForwardIter>
first_min_first_max_element(ForwardIter first, ForwardIter last)
{
return minmax_element(first, last);
}
template <typename ForwardIter, class BinaryPredicate>
inline std::pair<ForwardIter,ForwardIter>
first_min_first_max_element(ForwardIter first, ForwardIter last,
BinaryPredicate comp)
{
return minmax_element(first, last, comp);
}
template <typename ForwardIter>
std::pair<ForwardIter,ForwardIter>
first_min_last_max_element(ForwardIter first, ForwardIter last)
{
return detail::basic_first_min_last_max_element(first, last,
detail::less_over_iter<ForwardIter>() );
}
template <typename ForwardIter, class BinaryPredicate>
inline std::pair<ForwardIter,ForwardIter>
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<ForwardIter,BinaryPredicate>(comp) );
}
template <typename ForwardIter>
std::pair<ForwardIter,ForwardIter>
last_min_first_max_element(ForwardIter first, ForwardIter last)
{
return detail::basic_last_min_first_max_element(first, last,
detail::less_over_iter<ForwardIter>() );
}
template <typename ForwardIter, class BinaryPredicate>
inline std::pair<ForwardIter,ForwardIter>
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<ForwardIter,BinaryPredicate>(comp) );
}
template <typename ForwardIter>
std::pair<ForwardIter,ForwardIter>
last_min_last_max_element(ForwardIter first, ForwardIter last)
{
return detail::basic_last_min_last_max_element(first, last,
detail::less_over_iter<ForwardIter>() );
}
template <typename ForwardIter, class BinaryPredicate>
inline std::pair<ForwardIter,ForwardIter>
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<ForwardIter,BinaryPredicate>(comp) );
}
} // namespace boost
#endif // BOOST_MINMAX_HPP #endif // BOOST_MINMAX_HPP

View File

@ -0,0 +1,524 @@
<!doctype html public "-//w3c//dtd html 4.0 transitional//en">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
<meta name="GENERATOR" content="Mozilla/4.77 [en] (X11; U; Linux 2.2.19 i686) [Netscape]">
<meta name="Author" content="Herve Bronnimann">
<meta name="Description" content="Small library to propose minmax_element algorithm.">
<title>Boost minmax library</title>
</head>
<body text="#000000" bgcolor="#FFFFFF" link="#0000EE" vlink="#551A8B" alink="#FF0000">
<center>
<h1>
Minmax_element Performance</h1></center>
<h3>
<a NAME="Performance"></a><b>About performance</b></h3>
Of course, there are many factors that affect the performance of an algorithm.
The number of comparison is only one, but also branch prediction, pipelining,
locality of reference (affects cache efficiency), etc. In practice,
we observe that when the iterator type is a pointer,
<tt>boost::minmax_element</tt>
is only a tad slower than
<tt>std::min_element</tt>, and is even faster
than
<tt>boost::first_min_last_max_element</tt>! This is even more true
for slower iterators (<tt>list&lt;>::iterator</tt> or
<tt>map&lt;>iterator</tt>
for instance). The following experiments were conducted on a Pentium III
500 Mhz running Linux and compiled with g++, version 2.95.2, flags -O3.
In the tables, we use different distributions: <i>Identical</i> means that
all the elements are identical, <i>2-valued</i> means that we replace the
second half of the identical elements by a distinct element, <i>increasing</i>
means that all the elements are distinct and in increasing order, <i>decrea</i>sing
is the reverse, and <i>random</i> is produced by random_shuffle.
<br>
The program that created these tables is included in the distribution,
under <a href=""../example/minmax_timer.cpp"">minmax_timer.cpp</a>
<br>
<center><table BORDER NOSAVE >
<tr NOSAVE>
<td NOSAVE><b>vector&lt;int>::iterator</b></td>
<td>Identical</td>
<td>2-valued</td>
<td>Increasing</td>
<td>Decreasing</td>
<td>Random</td>
</tr>
<tr>
<td>std::min_element</td>
<td>23.26M/s</td>
<td>23.26M/s</td>
<td>23.15M/s</td>
<td>22.94M/s</td>
<td>22.94M/s</td>
</tr>
<tr>
<td>std::max_element</td>
<td>23.26M/s</td>
<td>23.26M/s</td>
<td>23.15M/s</td>
<td>22.94M/s</td>
<td>22.62M/s</td>
</tr>
<tr>
<td>boost::first_min_element</td>
<td>23.15M/s</td>
<td>23.04M/s</td>
<td>23.04M/s</td>
<td>22.94M/s</td>
<td>22.83M/s</td>
</tr>
<tr>
<td>boost::last_min_element</td>
<td>23.26M/s</td>
<td>23.26M/s</td>
<td>23.26M/s</td>
<td>22.83M/s</td>
<td>16.23M/s</td>
</tr>
<tr>
<td>boost::first_max_element</td>
<td>23.15M/s</td>
<td>23.26M/s</td>
<td>23.15M/s</td>
<td>23.04M/s</td>
<td>22.93M/s</td>
</tr>
<tr>
<td>boost::last_max_element</td>
<td>23.26M/s</td>
<td>23.15M/s</td>
<td>23.15M/s</td>
<td>22.94M/s</td>
<td>16.18M/s</td>
</tr>
<tr>
<td>boost::minmax_element</td>
<td>21.83M/s</td>
<td>21.83M/s</td>
<td>21.83M/s</td>
<td>21.55M/s</td>
<td>17.79M/s</td>
</tr>
<tr>
<td>boost::first_min_last_max_element</td>
<td>18.52M/s</td>
<td>18.38M/s</td>
<td>18.38M/s</td>
<td>18.94M/s</td>
<td>16.29M/s</td>
</tr>
<tr>
<td>boost::last_min_first_max_element</td>
<td>20.08M/s</td>
<td>20.83M/s</td>
<td>20.75M/s</td>
<td>19.76M/s</td>
<td>15.87M/s</td>
</tr>
<tr>
<td>boost::last_min_last_max_element</td>
<td>18.66M/s</td>
<td>19.69M/s</td>
<td>19.69M/s</td>
<td>19.23M/s</td>
<td>15.77M/s</td>
</tr>
<caption ALIGN=BOTTOM>Number of elements per second for standard vector
container iterators</caption>
</table></center>
<center><table BORDER NOSAVE >
<tr NOSAVE>
<td NOSAVE><b>list&lt;int>::iterator</b></td>
<td>Identical</td>
<td>2-valued</td>
<td>Increasing</td>
<td>Decreasing</td>
<td>Random</td>
</tr>
<tr>
<td>std::min_element</td>
<td>5.8M/s</td>
<td>5.8M/s</td>
<td>5.80M/s</td>
<td>5.73M/s</td>
<td>5.73M/s</td>
</tr>
<tr>
<td>std::max_element</td>
<td>5.81M/s</td>
<td>5.81M/s</td>
<td>5.78M/s</td>
<td>5.73M/s</td>
<td>5.75M/s</td>
</tr>
<tr>
<td>boost::first_min_element</td>
<td>5.81M/s</td>
<td>5.81M/s</td>
<td>5.79M/s</td>
<td>5.75M/s</td>
<td>5.73M/s</td>
</tr>
<tr>
<td>boost::last_min_element</td>
<td>5.81M/s</td>
<td>5.80M/s</td>
<td>5.79M/s</td>
<td>5.73M/s</td>
<td>5.03M/s</td>
</tr>
<tr>
<td>boost::first_max_element</td>
<td>5.81M/s</td>
<td>5.80M/s</td>
<td>5.78M/s</td>
<td>5.74M/s</td>
<td>5.73M/s</td>
</tr>
<tr>
<td>boost::last_max_element</td>
<td>5.81M/s</td>
<td>5.80M/s</td>
<td>5.79M/s</td>
<td>5.73M/s</td>
<td>5.07M/s</td>
</tr>
<tr>
<td>boost::minmax_element</td>
<td>5.68M/s</td>
<td>5.80M/s</td>
<td>5.66M/s</td>
<td>5.74M/s</td>
<td>5.30M/s</td>
</tr>
<tr>
<td>boost::first_min_last_max_element</td>
<td>5.79M/s</td>
<td>5.81M/s</td>
<td>5.78M/s</td>
<td>5.73M/s</td>
<td>5.04M/s</td>
</tr>
<tr>
<td>boost::last_min_first_max_element</td>
<td>5.69M/s</td>
<td>5.79M/s</td>
<td>5.69M/s</td>
<td>5.73M/s</td>
<td>4.84M/s</td>
</tr>
<tr>
<td>boost::last_min_last_max_element</td>
<td>5.61M/s</td>
<td>5.79M/s</td>
<td>5.64M/s</td>
<td>5.74M/s</td>
<td>4.75M/s</td>
</tr>
<caption ALIGN=BOTTOM>Runtimes for standard list container iterators</caption>
</table></center>
<center><table BORDER NOSAVE >
<tr NOSAVE>
<td NOSAVE><b>multiset&lt;int>::iterator</b></td>
<td>Identical</td>
<td>2-valued</td>
<td>Increasing</td>
<td>Decreasing</td>
<td>Random</td>
</tr>
<tr>
<td>std::min_element</td>
<td>4.03M/s</td>
<td>4.04M/s</td>
<td>4.02M/s</td>
<td>4.04M/s</td>
<td>2.97M/s</td>
</tr>
<tr>
<td>std::max_element3.007M</td>
<td>4.02M/s</td>
<td>4.02M/s</td>
<td>4.01M/s</td>
<td>4.02M/s</td>
<td>2.96M/s</td>
</tr>
<tr>
<td>boost::first_min_element</td>
<td>4.01M/s</td>
<td>4.04M/s</td>
<td>4.03M/s</td>
<td>4.04M/s</td>
<td>3.01M/s</td>
</tr>
<tr>
<td>boost::last_min_element</td>
<td>4.03M/s</td>
<td>4.04M/s</td>
<td>4.04M/s</td>
<td>4.04M/s</td>
<td>3.00M/s</td>
</tr>
<tr>
<td>boost::first_max_element</td>
<td>4.04M/s</td>
<td>4.04M/s</td>
<td>4.04M/s</td>
<td>4.06M/s</td>
<td>3.01M/s</td>
</tr>
<tr>
<td>boost::last_max_element</td>
<td>4.04M/s</td>
<td>4.04M/s</td>
<td>4.03M/s</td>
<td>4.04M/s</td>
<td>3.00M/s</td>
</tr>
<tr>
<td>boost::minmax_element</td>
<td>3.98M/s</td>
<td>3.99M/s</td>
<td>3.98M/s</td>
<td>3.99M/s</td>
<td>3.00M/s</td>
</tr>
<tr>
<td>boost::first_min_last_max_element</td>
<td>3.99M/s</td>
<td>3.98M/s</td>
<td>3.97M/s</td>
<td>3.99M/s</td>
<td>2.99M/s</td>
</tr>
<tr>
<td>boost::last_min_first_max_element</td>
<td>3.97M/s</td>
<td>3.98M/s</td>
<td>3.96M/s</td>
<td>3.98M/s</td>
<td>3.00M/s</td>
</tr>
<tr>
<td>boost::last_min_last_max_element</td>
<td>4.00M/s</td>
<td>4.00M/s</td>
<td>4.00M/s</td>
<td>4.02M/s</td>
<td>2.97M/s</td>
</tr>
<caption ALIGN=BOTTOM>Runtimes for standard set/multiset container iterators</caption>
</table></center>
<hr SIZE="6">
<br>Last modified 2004-06-28
<p><font face="Arial,Helvetica"><font size=-1>&copy; Copyright Herv&eacute;
Br&ouml;nnimann, Polytechnic University, 2002--2004. Permission to copy, use,
modify, sell and distribute this software and its documentation is granted
provided this copyright notice appears in all copies. This software and
its documentation is provided "as is" without express or implied warranty,
and with no claim as to its suitability for any purpose.</font></font>
</body>
</html>

View File

@ -0,0 +1,114 @@
<!doctype html public "-//w3c//dtd html 4.0 transitional//en">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
<meta name="GENERATOR" content="Mozilla/4.77 [en] (X11; U; Linux 2.2.19 i686) [Netscape]">
<meta name="Author" content="Herve Bronnimann">
<meta name="Description" content="Small library to propose minmax_element algorithm.">
<title>Boost minmax library synopsis</title>
</head>
<body text="#000000" bgcolor="#FFFFFF" link="#0000EE" vlink="#551A8B" alink="#FF0000">
<center>
<h1>
Minmax_element</h1></center>
<h3>
Synopsis</h3>
<pre>namespace boost {
template &lt;class T>
std::pair&lt;const T&amp;,const T&amp;>
minmax(const T&amp; a, const T&amp; b);
template &lt;class T, class <a href="http://www.sgi.com/tech/stl/ BinaryPredicate.html">BinaryPredicate</a>>
std::pair&lt;const T&amp;,const T&amp;>
minmax(const T&amp; a, const T&amp; b, BinaryPredicate comp);
template &lt;class <a href="http://www.sgi.com/tech/stl/ForwardIterator.html">ForwardIterator</a>>
std::pair&lt;ForwardIterator,ForwardIterator>
minmax_element(ForwardIterator first, ForwardIterator last);
template &lt;class <a href="http://www.sgi.com/tech/stl/ForwardIterator.html">ForwardIterator</a>, class <a href="http://www.sgi.com/tech/stl/BinaryPredicate.html">BinaryPredicate</a>>
std::pair&lt;ForwardIterator,ForwardIterator>
minmax_element(ForwardIterator first, ForwardIterator last,
BinaryPredicate comp);
template &lt;class <a href="http://www.sgi.com/tech/stl/ForwardIterator.html">ForwardIterator</a>>
ForwardIterator first_min_element(ForwardIterator first, ForwardIterator last);
template &lt;class <a href="http://www.sgi.com/tech/stl/ForwardIterator.html">ForwardIterator</a>, class <a href="http://www.sgi.com/tech/stl/BinaryPredicate.html">BinaryPredicate</a>>
ForwardIterator first_min_element(ForwardIterator first, ForwardIterator last,
BinaryPredicate comp);
template &lt;class <a href="http://www.sgi.com/tech/stl/ForwardIterator.html">ForwardIterator</a>>
ForwardIterator last_min_element(ForwardIterator first, ForwardIterator last);
template &lt;class <a href="http://www.sgi.com/tech/stl/ForwardIterator.html">ForwardIterator</a>, class <a href="http://www.sgi.com/tech/stl/BinaryPredicate.html">BinaryPredicate</a>>
ForwardIterator last_min_element(ForwardIterator first, ForwardIterator last,
BinaryPredicate comp);
template &lt;class <a href="http://www.sgi.com/tech/stl/ForwardIterator.html">ForwardIterator</a>>
ForwardIterator first_max_element(ForwardIterator first, ForwardIterator last);
template &lt;class <a href="http://www.sgi.com/tech/stl/ForwardIterator.html">ForwardIterator</a>, class <a href="http://www.sgi.com/tech/stl/BinaryPredicate.html">BinaryPredicate</a>>
ForwardIterator first_max_element(ForwardIterator first, ForwardIterator last,
BinaryPredicate comp);
template &lt;class <a href="http://www.sgi.com/tech/stl/ForwardIterator.html">ForwardIterator</a>>
ForwardIterator last_max_element(ForwardIterator first, ForwardIterator last);
template &lt;class <a href="http://www.sgi.com/tech/stl/ForwardIterator.html">ForwardIterator</a>, class <a href="http://www.sgi.com/tech/stl/BinaryPredicate.html">BinaryPredicate</a>>
ForwardIterator last_max_element(ForwardIterator first, ForwardIterator last,
BinaryPredicate comp);
template &lt;class <a href="http://www.sgi.com/tech/stl/ForwardIterator.html">ForwardIterator</a>>
std::pair&lt;ForwardIterator,ForwardIterator>
first_min_first_max_element(ForwardIterator first, ForwardIterator last);
template &lt;class <a href="http://www.sgi.com/tech/stl/ForwardIterator.html">ForwardIterator</a>, class <a href="http://www.sgi.com/tech/stl/BinaryPredicate.html">BinaryPredicate</a>>
std::pair&lt;ForwardIterator,ForwardIterator>
first_min_first_max_element(ForwardIterator first, ForwardIterator last,
BinaryPredicate comp);
template &lt;class <a href="http://www.sgi.com/tech/stl/ForwardIterator.html">ForwardIterator</a>>
std::pair&lt;ForwardIterator,ForwardIterator>
first_min_last_max_element(ForwardIterator first, ForwardIterator last);
template &lt;class <a href="http://www.sgi.com/tech/stl/ForwardIterator.html">ForwardIterator</a>, class <a href="http://www.sgi.com/tech/stl/BinaryPredicate.html">BinaryPredicate</a>>
std::pair&lt;ForwardIterator,ForwardIterator>
first_min_last_max_element(ForwardIterator first, ForwardIterator last,
BinaryPredicate comp);
template &lt;class <a href="http://www.sgi.com/tech/stl/ForwardIterator.html">ForwardIterator</a>>
std::pair&lt;ForwardIterator,ForwardIterator>
last_min_first_max_element(ForwardIterator first, ForwardIterator last);
template &lt;class <a href="http://www.sgi.com/tech/stl/ForwardIterator.html">ForwardIterator</a>, class <a href="http://www.sgi.com/tech/stl/BinaryPredicate.html">BinaryPredicate</a>>
std::pair&lt;ForwardIterator,ForwardIterator>
last_min_first_max_element(ForwardIterator first, ForwardIterator last,
BinaryPredicate comp);
template &lt;class <a href="http://www.sgi.com/tech/stl/ForwardIterator.html">ForwardIterator</a>>
std::pair&lt;ForwardIterator,ForwardIterator>
last_min_last_max_element(ForwardIterator first, ForwardIterator last);
template &lt;class <a href="http://www.sgi.com/tech/stl/ForwardIterator.html">ForwardIterator</a>, class <a href="http://www.sgi.com/tech/stl/BinaryPredicate.html">BinaryPredicate</a>>
std::pair&lt;ForwardIterator,ForwardIterator>
last_min_last_max_element(ForwardIterator first, ForwardIterator last,
BinaryPredicate comp);
}</pre>
<hr SIZE="6">
<br>Last modified 2002-05-09
<p><font face="Arial,Helvetica"><font size=-1>&copy; Copyright Herv&eacute;
Br&ouml;nnimann, Polytechnic University, 2002. Permission to copy, use,
modify, sell and distribute this software and its documentation is granted
provided this copyright notice appears in all copies. This software and
its documentation is provided "as is" without express or implied warranty,
and with no claim as to its suitability for any purpose.</font></font>
</body>
</html>

14
minmax/example/Jamfile Normal file
View File

@ -0,0 +1,14 @@
# Boost.Minmax Library Example Jamfile
#
# Copyright (C) 2002--2004, Herve Bronnimann
#
# Use, modification, and distribution is subject to 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)
#
subproject libs/minmax/example ;
exe minmax_ex : minmax_ex.cpp ;
exe minmax_timer : minmax_timer.cpp ;

View File

@ -0,0 +1,23 @@
#include <list>
#include <algorithm>
#include <cstdlib>
#include <cassert>
#include <iostream>
#include <boost/minmax.hpp>
int main()
{
using namespace std;
list<int> L;
generate_n(front_inserter(L), 1000, rand);
typedef list<int>::const_iterator iterator;
pair< iterator, iterator > result = boost::minmax_element(L.begin(), L.end());
cout << "The smallest element is " << *(result.first) << endl;
cout << "The largest element is " << *(result.second) << endl;
assert( result.first == std::min_element(L.begin(), L.end()) );
assert( result.second == std::max_element(L.begin(), L.end()) );
}

View File

@ -0,0 +1,207 @@
#include <utility>
#include <functional>
#include <algorithm>
#include <numeric>
#include <iterator>
#include <vector>
#include <list>
#include <set>
#include <iostream>
// What's the proper BOOST_ flag for <iomanip.h> vs <ios>
#include <iomanip>
#include <boost/timer.hpp>
#include <boost/minmax.hpp>
template <class T1, class T2>
void tie(std::pair<T1, T2> p, T1& min, T2& max)
{
min = p.first; max = p.second;
}
template <class Value>
struct less_count : std::less<Value> {
less_count(less_count<Value> const& lc) : _M_counter(lc._M_counter) {}
less_count(int& counter) : _M_counter(counter) {}
bool operator()(Value const& a, Value const& b) const {
++_M_counter;
return std::less<Value>::operator()(a,b);
}
void reset() {
_M_counter = 0;
}
private:
int& _M_counter;
};
inline int opt_min_count(int n) {
return (n==0) ? 0 : n-1;
}
inline int opt_minmax_count(int n) {
if (n < 2) return 0;
if (n == 2) return 1;
return (n%2 == 0) ? 3*(n/2)-1 : 3*(n/2)+1;
}
inline int opt_boost_minmax_count(int n) {
if (n < 2) return 0;
if (n == 2) return 1;
return (n%2 == 0) ? 3*(n/2)-2 : 3*(n/2);
}
int repeats = 10;
#define TIMER( n, cmd , cmdname ) \
t.restart(); \
for (int i=0; i<repeats; ++i) { cmd ; } \
std::cout << " " << std::setprecision(4) \
<< (double)n*repeats/t.elapsed()/1.0E6 \
<< "M items/sec " << cmdname << "\n"
#define CTIMER( n, cmd , cmdname, count, opt ) \
t.restart(); lc.reset(); \
for (int i=0; i<repeats; ++i) { cmd ; } \
std::cout << " " << std::setprecision(4) \
<< (double)n*repeats/t.elapsed()/1.0E6 \
<< "M items/sec " << cmdname \
<< " ("<< (count)/repeats << " vs " << opt << ")\n"
template <class CIterator>
void test_minmax_element(CIterator first, CIterator last, int n, char* name)
{
typedef typename std::iterator_traits<CIterator>::value_type vtype;
boost::timer t;
std::cout << " ON " << name << " WITH OPERATOR<()\n";
TIMER( n, std::min_element(first, last),
"std::min_element" << name << "");
TIMER( n, std::max_element(first, last),
"std::max_element" << name << "");
TIMER( n, boost::first_min_element(first, last),
"boost::first_min_element" << name << "");
TIMER( n, boost::last_min_element(first, last),
"boost::last_min_element" << name << " ");
TIMER( n, boost::first_max_element(first, last),
"boost::first_max_element" << name << "");
TIMER( n, boost::last_max_element(first, last),
"boost::last_max_element" << name << " ");
TIMER( n, boost::minmax_element(first, last),
"boost::minmax_element" << name << " ");
TIMER( n, boost::first_min_last_max_element(first, last),
"boost::first_min_last_max_element" << name << "");
TIMER( n, boost::last_min_first_max_element(first, last),
"boost::last_min_first_max_element" << name << "");
TIMER( n, boost::last_min_last_max_element(first, last),
"boost::last_min_last_max_element" << name << " ");
#define pred std::bind2nd( std::greater<vtype>(), vtype(10) )
TIMER( n, boost::min_element_if(first, last, pred),
"boost::min_element_if" << name << "");
TIMER( n, boost::max_element_if(first, last, pred),
"boost::max_element_if" << name << "");
TIMER( n, std::min_element(boost::make_filter_iterator(first, last, pred),
boost::make_filter_iterator(last, last, pred)),
"std::min_element_with_filter_iterator" << name << "");
TIMER( n, std::max_element(boost::make_filter_iterator(first, last, pred),
boost::make_filter_iterator(last, last, pred)),
"std::max_element_if_with_filter_iterator" << name << "");
#undef pred
int counter = 0;
less_count<vtype> lc(counter);
std::cout << " ON " << name << " WITH LESS<> AND COUNTING COMPARISONS\n";
CTIMER( n, std::min_element(first, last, lc),
"std::min_element" << name << " ",
counter, opt_min_count(n) );
CTIMER( n, std::max_element(first, last, lc),
"std::max_element" << name << " ",
counter, opt_min_count(n) );
CTIMER( n, boost::first_min_element(first, last, lc),
"boost::first_min_element" << name << "",
counter, opt_min_count(n) );
CTIMER( n, boost::last_min_element(first, last, lc),
"boost::last_max_element" << name << " ",
counter, opt_min_count(n) );
CTIMER( n, boost::first_max_element(first, last, lc),
"boost::first_min_element" << name << "",
counter, opt_min_count(n) );
CTIMER( n, boost::last_max_element(first, last, lc),
"boost::last_max_element" << name << " ",
counter, opt_min_count(n) );
CTIMER( n, boost::minmax_element(first, last, lc),
"boost::minmax_element" << name << " ",
counter, opt_minmax_count(n) );
CTIMER( n, boost::first_min_last_max_element(first, last, lc),
"boost::first_min_last_max_element" << name << "",
counter, opt_boost_minmax_count(n) );
CTIMER( n, boost::last_min_first_max_element(first, last, lc),
"boost::last_min_first_max_element" << name << "",
counter, opt_boost_minmax_count(n) );
CTIMER( n, boost::last_min_last_max_element(first, last, lc),
"boost::last_min_last_max_element" << name << " ",
counter, opt_minmax_count(n) );
}
template <class Container, class Iterator, class Value>
void test_container(Iterator first, Iterator last, int n, char* name)
{
Container c(first, last);
typename Container::iterator fit(c.begin()), lit(c.end());
test_minmax_element(fit, lit, n, name);
}
template <class Iterator>
void test_range(Iterator first, Iterator last, int n)
{
typedef typename std::iterator_traits<Iterator>::value_type Value;
// Test various containers with these values
test_container< std::vector<Value>, Iterator, Value >(first, last, n, "<vector>");
#ifndef ONLY_VECTOR
test_container< std::list<Value>, Iterator, Value >(first, last, n, "<list> ");
test_container< std::multiset<Value>, Iterator, Value >(first, last, n, "<set> ");
#endif
}
template <class Value>
void test(int n)
{
// Populate test vector with identical values
std::cout << "IDENTICAL VALUES... \n";
std::vector<Value> test_vector(n, Value(1));
typename std::vector<Value>::iterator first( test_vector.begin() );
typename std::vector<Value>::iterator last( test_vector.end() );
test_range(first, last, n);
// Populate test vector with two values
std::cout << "TWO DISTINCT VALUES...\n";
typename std::vector<Value>::iterator middle( first + n/2 );
std::fill(middle, last, Value(2));
test_range(first, last, n);
// Populate test vector with increasing values
std::cout << "INCREASING VALUES... \n";
std::fill(first, last, Value(1));
std::accumulate(first, last, Value(0));
test_range(first, last, n);
// Populate test vector with decreasing values
std::cout << "DECREASING VALUES... \n";
std::reverse(first, last);
test_range(first, last, n);
// Populate test vector with random values
std::cout << "RANDOM VALUES... \n";
std::random_shuffle(first, last);
test_range(first, last, n);
}
int
main(char argc, char** argv)
{
int n = 100;
if (argc > 1) n = atoi(argv[1]);
if (argc > 2) repeats = atoi(argv[2]);
test<int>(n);
return 0;
}

481
minmax/index.html Normal file
View File

@ -0,0 +1,481 @@
<!DOCTYPE html public "-//w3c//dtd html 4.0 transitional//en">
<HTML>
<HEAD>
<LINK REL="stylesheet" TYPE="text/css" HREF="../../../boost.css">
<META http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
<META name="GENERATOR" content="Mozilla/4.77 [en] (X11; U; Linux 2.2.19 i686) [Netscape]">
<META name="Author" content="Herve Bronnimann">
<META name="Description" content="Small library to propose minmax_element algorithm.">
<title>Boost Minmax library</title>
</HEAD>
<body text="#000000" bgcolor="#FFFFFF" link="#0000EE" vlink="#551A8B" alink="#FF0000">
<h2><img src="../../c++boost.gif" WIDTH="276" HEIGHT="86">Header &lt;<A
HREF="../../../boost/minmax.hpp">boost/minmax.hpp</A>&gt; </H2>
<quote>
<b>
<a href="#minmax_element">Motivation</a><br>
<a href="#synopsis">Synopsis</a><br>
<a href="#description">Function templates description</a><br>
<a href="#definition">Definition</a><br>
<a href="#reqs">Requirements on type</a>s<br>
<a href="#precond">Preconditions</a><br>
<a href="#postcond">Postconditions</a><br>
<a href="#complexity">Complexity</a><br>
<a href="#example">Example</a><br>
<a href="#notes">Notes</a><br>
<a href="#rationale">Rationale</a><br>
<a href="#perf">Note about performance</a><br>
<a href="#acks">Acknowledgements</a>
</b>
</quote>
<a name="minmax_element">
<h3>
Motivation</h3>
<p>The minmax library is composed of a single header <tt><a href="../../boost/minmax.hpp">&lt;boost/minmax.hpp></a></tt>.
I always thought it is a waste to have to call two functions to compute the
extent of a range, performing two passes over the input, when one should
be enough. The first part implements the function templates
<tt>minmax</tt>
and <tt>minmax_element</tt> as straightforward extensions of the C++
standard. (Please note: the intent is not to fix the known defaults of
<tt>std::min</tt>
and <tt>std::max</tt>, but to add one more algorithms that combines both; see the
<a href="#no-fix">rationale</a>.)</p>
<p>The second part proposes variants that can usually not be computed by
the minmax algorithm, and which are more flexible in case some elements are equal.
Those variants could have been also provided with policy-based design,
but I ruled against that (see <a href="#no-policy">rationale</a>).
</p>
<p>If you are interested about
<a href="minmax_benchs.html">performance</a>,
you will see that <tt>minmax_element</tt> is just slightly less efficient
than a single <tt>min_element</tt> or <tt>max_element</tt>, and thus
twice as efficient as two separate calls to <tt>min_element</tt> and
<tt>max_element</tt>. From a
theoretical standpoint,
all the <tt>minmax_element</tt> functions perform at most
<tt>3n/2+1</tt>
comparisons and exactly n increments of the
<tt>ForwardIterator</tt>.</p>
</a>
<a name="synopsis">
<h3>
Synopsis</h3>
<pre>namespace boost {
// Minmax
template &lt;class T>
std::pair&lt;const T&amp;,const T&amp;>
minmax(const T&amp; a, const T&amp; b);
template &lt;class T, class <a href="http://www.sgi.com/tech/stl/ BinaryPredicate.html">BinaryPredicate</a>>
std::pair&lt;const T&amp;,const T&amp;>
minmax(const T&amp; a, const T&amp; b, BinaryPredicate comp);
// Minmax_element
template &lt;class <a href="http://www.sgi.com/tech/stl/ForwardIterator.html">ForwardIterator</a>>
std::pair&lt;ForwardIterator,ForwardIterator>
minmax_element(ForwardIterator first, ForwardIterator last);
template &lt;class <a href="http://www.sgi.com/tech/stl/ForwardIterator.html">ForwardIterator</a>, class <a href="http://www.sgi.com/tech/stl/BinaryPredicate.html">BinaryPredicate</a>>
std::pair&lt;ForwardIterator,ForwardIterator>
minmax_element(ForwardIterator first, ForwardIterator last,
BinaryPredicate comp);
}
</pre>
In addition, there are a bunch of extensions which specify
which element(s) you want to pick in case of equal elements. They are:
<ul>
<li><tt>first_min_element</tt> and <tt>last_min_element</tt></li>
<li><tt>first_max_element</tt> and <tt>last_max_element</tt></li>
<li><tt>first_min_first_max_element</tt>,
<tt>first_min_last_max_element</tt>,
<tt>last_min_first_max_element</tt>, and
<tt>last_min_last_max_element</tt></li>
</ul>
I won't bore you with the complete synopsis, they have exactly the same
declaration as their corresponding <tt>_element</tt> function. Still,
you can find the complete synopsis <a href="minmax_synopsis.html">here</a>.
</a>
<a name="description">
<h3>
Function templates description</h3>
The <tt>minmax</tt> algorithm returns a pair <tt>p</tt> containing either
<i>(a,b)</i>
or <i>(b,a)</i>, such that <tt>p.first&lt;p.second</tt> in the first version,
or <tt>comp(p.first,p.second)</tt> in the second version. If the elements
are equivalent, the pair <i>(a,b) </i>is returned. <a href="#Note1">[1]</a>
<p>The <tt>minmax_element </tt>is semantically equivalent to <tt>first_min_first_max_element</tt>.
<p><tt>First_min_element</tt> and <tt>first_max_element</tt> find the smallest
and largest elements in the range <tt>[first, last)</tt>. If there are
several instance of these elements, the first one is returned. They are
identical to
<tt>std::min_element</tt> and <tt>std::max_element</tt>and
are only included in this library for symmetry.
<p><tt>Last_min_element</tt> and <tt>last_max_element</tt> find the smallest
and largest elements in the range <tt>[first, last)</tt>. They are almost
identical to
<tt>std::min_element</tt> and <tt>std::max_element</tt>, except
that they return the last instance of the largest element (and not the
first, as <tt>first_min_element</tt> and <tt>last_max_element</tt> would).
<p>The family of algorithms comprising <tt>first_min_first_max_element</tt>,
<tt>first_min_first_max_element</tt>,
<tt>first_min_first_max_element</tt>,
and <tt>first_min_first_max_element</tt> can be described generically as
follows (using <i><tt>which</tt></i> and
<i><tt>what</tt></i> for <tt>first</tt>
or <tt>last</tt>): <tt><i>which</i>_min_<i>what</i>_max_element</tt> finds
the (first or last, according to <i><tt>which</tt></i>) smallest element
and the (first or last, according to <i><tt>what</tt></i>) largest element
in the range
<tt>[first, last)</tt>. The first version is semantically
equivalent to:
<pre><tt> std::make_pair(boost::<i>which</i>_min_element(first,last),
boost::<i>what</i>_max_element(first,last))</tt>,</pre>
and the second version to:
<pre><tt> std::make_pair(boost::<i>which</i>_min_element(first,last,comp),
boost::<i>what</i>_max_element(first,last,comp))</tt>.</pre>
<p><br><b><i>Note</i></b>: the <tt>first_min_last_max_element</tt> can also be described
as finding the first and last elements in the range if it were stably sorted.
</a>
<a name="definition">
<h3>
Definition</h3>
Defined in <a href="../../boost/minmax.hpp">minmax.hpp</a>.
</a>
<a name="reqs">
<h3>
Requirements on types</h3>
For minmax, <tt>T</tt> must be a model of <a href="http://www.sgi.com/tech/stl/LessThanComparable.html">LessThan
Comparable</a>.
<p>For all the other function templates, versions with two template parameters:
<ul>
<li>
<tt>ForwardIterator</tt> is a model of <a href="http://www.sgi.com/tech/stl/ForwardIterator.html">Forward
Iterator</a>.</li>
<li>
<tt>ForwardIterator</tt>'s value type is <a href="http://www.sgi.com/tech/stl/LessThanComparable.html">LessThan
Comparable</a>.</li>
</ul>
For the versions with three template parameters:
<ul>
<li>
<tt>ForwardIterator</tt> is a model of <a href="http://www.sgi.com/tech/stl/ForwardIterator.html">Forward
Iterator</a>.</li>
<li>
<tt>BinaryPredicate</tt> is a model of <a href="http://www.sgi.com/tech/stl/BinaryPredicate.html">Binary
Predicate</a>.</li>
<li>
<tt>ForwardIterator</tt>'s value type is convertible to <tt>BinaryPredicate</tt>'s
first argument type and second argument type.</li>
</ul>
</a>
<a name="precond">
<h3>
Preconditions</h3>
<ul>
<li>
<tt>[first, last)</tt> is a valid range.</li>
</ul>
</a>
<a name="postcond">
<h3>
Postconditions</h3>
In addition to the semantic description above. for <tt>minmax_element</tt>
and all the <tt><i>which</i>_min_<i>what</i>_max_element</tt>
variants, the return value is
<tt>last</tt> or <tt>std::make_pair(last,last)</tt>
if and only if <tt>[first, last)</tt> is an empty range. Otherwise, the
return value or both members of the resulting pair are iterators in the
range
<tt>[first, last)</tt>.
</a>
<a name="complexity">
<h3>
<a NAME="Complexity"></a>Complexity</h3>
Minmax performs a single comparison and is otherwise of constant complexity.
<p>The complexity of all the other algorithms is linear. They all perform
exactly n increment operations, and zero comparisons if <tt>[first,last)</tt>
is empty, otherwise :
<ul>
<li>
all the <tt>min_element</tt> and <tt>max_element</tt> variants perform
exactly<tt>(n-1)</tt> comparisons,</li>
<li>
<tt>minmax_element</tt> , <tt>first_min_first_max_element</tt>, and <tt>last_min_last_max_element</tt>
perform at most <tt>3(n/2)-1</tt> comparisons if <tt>n</tt> is even and
non-zero, and at most <tt>3(n/2)+1</tt> if <tt>n</tt> is odd,
<a href="#Note2">[2]</a></li>
<li>
<tt>first_min_last_max_element</tt>, and <tt>last_min_first_max_element</tt>
perform exactly <tt>3n/2-2</tt> comparisons if n is even and non-zero,
and at most <tt>3(n/2)</tt> if <tt>n</tt> is odd,
<a href="#Note1">[3]</a></li>
</ul>
where <tt>n</tt> is the number of elements in <tt>[first,last)</tt>.
</a>
<a name="example">
<h3>
Example</h3>
This example is included in the distribution in the examples section of
the library under
<a href="example/minmax_ex.cpp">minmax_ex.cpp</a>.
<pre>int main()
{
using namespace std;
<a href="http://www.sgi.com/tech/stl/List.html">list</a>&lt;int> L;
<a href="http://www.sgi.com/tech/stl/generate_n.html">generate_n</a>(<a href="http://www.sgi.com/tech/stl/front_insert_iterator.html">front_inserter</a>(L), 1000, rand);
typedef list&lt;int>::const_iterator iterator;
pair&lt; iterator, iterator > result = boost::minmax_element(L.begin(), L.end());
cout &lt;&lt; "The smallest element is " &lt;&lt; *(result.first) &lt;&lt; endl;
cout &lt;&lt; "The largest element is " &lt;&lt; *(result.second) &lt;&lt; endl;
assert( result.first == std::min_element(L.begin(), L.end());
assert( result.second == std::max_element(L.begin(), L.end());
}</pre>
</a>
<a name="notes">
<h3>
Notes</h3>
<a NAME="Note1"></a><a href="#Note1">[1]</a> It is not recommended to use
idioms such as <tt><a href="http://www.boost.org/libs/tuple/doc/tuple_users_guide.html#tiers">tie</a>(a,b)=minmax(a,b)</tt>
to order two elements <tt>a</tt>, <tt>b</tt>, although this would have
the desired effect. The reason is that two unnecessary assignments are
performed if a and b are in order. It is better to stick to <tt>if (b&lt;a)
swap(a,b)</tt> to achieve that effect.
<p><a NAME="Note2"></a><a href="#Note2">[2]</a> These algorithms always
perform at least <tt>3n/2-2</tt> comparisons, which is a lower bound on
the number of comparisons in any case (Cormen, Leiserson, Rivest: "Introduction
to Algorithms", section 9.1, Exercise 9.1-). The algorithms essentially compare
the elements in pairs, performing 1 comparison for the first two elements,
then 3 comparisons for each remaining pair of elements (one to order the
elements and one for updating each the minimum and and the maximum). When
the number of elements is odd, the last one needs to be compared to the
current minimum and also to the current maximum. In addition, for <tt>minmax</tt>,
in cases where equality of the two members in the pair could occur, and
the update stores the second, we save the first to check at the end if
the update should have stored the first (in case of equality). It's hard
to predict if the last comparison is performed or not, hence the at most
in both cases.
<p><a NAME="Note3"></a><a href="#Note3">[3]</a> These algorithms always
perform at least <tt>3n/2-2</tt> comparisons, which is a lower bound on
the number of comparisons in any case. The method is the same as in note
<a href="#Note2">[2]</a>
above, and like above, when the number of elements is odd, the last one
needs to be compared to the current minimum and also to the current maximum.
We can avoid the latter comparison if the former is successful, hence the
<i>at
most</i> instead of <i>exactly</i> in the odd case.
</a>
<a name="rationale">
<h3>
<b>Rationale:</b></h3>
<a name="no-fix">
<h4><b>Your minmax suffers from the same problems as std::min and
std::max.</b></h4>
<p>I am aware of the problems with std::min and
std::max, and all the debate that has been going on (please consult
<a href="http://www.cuj.com/experts/1904/alexandr.htm?topic=experts&topic=experts">Alexandrescu's
paper</a> and the links therein). But I don't see the purpose of this
library as fixing something that is part of the C++ standard. I humbly
think it's beyond the scope of this library. Rather, I am
following the way of the standard in simply providing one more function
of the same family. If someone else wants to fix std::min, their fix
would probably apply to boost::minmax as well.</p>
</a>
<h4><b>Why no <tt>min/max_element_if</tt>?</b></h4>
<p>In a first version of the library, I proposed <tt>_if</tt> versions of
all the algorithms (well, not all, because that would be too much).
However, there is simply no reason to do so, and all the versions I had
were just as fast implemented using the excellent
<tt>&lt;boost/iterator_adaptors.hpp></tt> library. Namely, a call to
<tt>min_element_if(first, last, pred)</tt> would be just as well
implemented by:
<pre>
// equivalent to min_element_if(first, last, pred)
min_element(boost::make_filter_iterator(first, last, pred),
boost::make_filter_iterator(last, last, pred));
</pre>
Arguably, the <tt>min_element_if</tt> version is somewhat shorter, but
the overhead of iterator adaptors is not large, and they get rid of a
lot of code (think of all the combinations between first/last and
doubling them with _if variants!).</p>
<h4><b>Discussion: about std::max_element</b></h4>
<p>This rationale is somewhat historical, but explains why there are all
these <tt>first/last_min/max_element</tt> functions.</p>
<p>The C++ standard mandates that <tt>std::min_element</tt> and <tt>std::max_element</tt>
return the first instance of the smallest and largest elements (as opposed
to, say, the last). This arbitrary choice has some consistency: In the
case of v of type vector&lt;int>, for instance, it is true that <tt>std::min_element(v.begin(),v.end(),std::less&lt;int>())
== std::max_element(v.begin(),v.end(),std::greater&lt;int>())</tt>.
<p>There is of course nothing wrong with this: it's simply a matter of
choice. Yet another way to specify min_element and max_element is to define
them as the first and the last elements if the range was stably sorted.
(The <i>stable</i> sort is necessary to disambiguate between iterators
that have the same value.) In that case, min should return the first instance
and max should return the last. Then, both functions are related by
<tt>reverse_iterator(std::first_min_element(v.begin(),v.end(),std::less&lt;int>()))
==
std::last_max_element(v.rbegin(),v.rend(),std::greater&lt;int>())</tt>.
This definition is subtly different from the previous one.</p>
<p>The definition problem surfaces when one tries to design a minmax_element,
using the procedure proposed in (Cormen, Leiserson, Rivest: "Introduction
to Algorithms", section 9.1). It <i>should</i> be possible to derive an
algorithm using only <tt>3n/2</tt> comparisons if <tt>[first,last) </tt>has
<tt>n</tt>
elements, but if one tries to write a function called <tt>first_min_first_max_element()</tt>
which returns both <tt>std::min_element</tt> and <tt>std::max_element</tt>
in a pair, the trivial implementation does not work. The problem, rather
subtly, is about equal elements: I had to think for a while to find a
way to perform only three
comparisons per pair and return the first min and first max elements.
For a long time, it seemed any
attempts at doing so would consume four comparisons per pair in the worst
case. This implementation achieves that.</p>
<p>It is not possible (or even desirable) to change the meaning of
<tt>max_element</tt>,
but it is still beneficial to provide a function called <tt>minmax_element</tt>,
which returns a pair of <tt>min_element</tt> and <tt>max_element</tt>.
Although it is easy enough to call <tt>min_element</tt> and <tt>max_element</tt>,
this performs
<tt>2(n-1)</tt> comparisons, and necessitates <b>two</b>
passes over the input. In contrast,
<tt>minmax_element</tt> will perform
the fewer comparisons and perform a <b>single</b> pass over the input.
The savings can be significant when the iterator type is not a raw pointer,
or even is just a model of the InputIterator concept (although in that
case the interface would have to be
changed, as the return type could not be copied, so one could e.g.
return a value).</p>
<p>In order to benefit from all the variants of the algorithm, I propose
to introduce both <tt>first_min_element</tt> and <tt>last_min_element</tt>,
and their counterparts <tt>first_max_element</tt> and <tt>last_max_element</tt>.
Then I also propose all the variants algorithms: <tt>first_min_last_max_element</tt>
and <tt>last_min_first_max_element</tt>, which perform only at most <tt>3n/2</tt>
comparisons, and only a single pass on the input. In fact, it can be proven
that computing minmax requires at least <tt>3(n/2)-2</tt> comparisons in
any instance of the problem (Cormen, Leiserson, Rivest, 2nd edition, section
9.1). The implementation I give does not perform unnecessary comparisons
(whose result could have been computed by transitivity from previous
comparisons).</p>
<p>It appears that <tt>first_min_last_max_element</tt> may be just a tad
slower than
<tt>first_min_element</tt> alone, still much less than <tt>first_min_element</tt>
and
<tt>last_max_element</tt> called separately. <a href="#Performance">[2]</a>
<h4><b>Why algorithms and not accumulators?</b></h4>
<p>The minmax algorithms are useful in computing the extent of a range.
In computer graphics, we need a bounding box of a set of objects.
In that case the need for a single pass is even more stringent
as all three directions must be done at once. Food for thoughts: there
is matter for a nice generic programming library with stackable <tt>update_min</tt>
and <tt>update_max</tt> function objects which store a reference to the
<tt>min_result</tt>and
<tt>max_result</tt> variables, in conjunction with the <tt>for_each</tt>
algorithm).</p>
<p>I believe many standard sequential algorithms could be reformulated
with accumulators (and many others, such as in statistics, expectation /
variance / etc.). It seems that there is room for another library, but I
do not see it competing with minmax, rather extending several algorithms
(including minmax) to the accumulator framework. However, I felt it is
beyond the scope of this library to provide such accumulators.</p>
<a NAME="no-policy">
<h4><b>This first/last is a perfect application for a policy-based
design.</b></h4>
<p>True, and I could have gone that way, with the default policy for
<tt>min_element</tt> and <tt>max_element</tt> to pick the first
occurence of the result. This would have thinned the number of
combinations of the minmax_element variants. But it would also have
meant to change the interface of <tt>boost::minmax_element</tt>.
One of the goals of the <tt>minmax_element</tt> algorithm is its
eventual addition to the C++ standard, in connection with
<tt>std::min_element</tt> and <tt>std::max_element</tt>
(and I feel that it would be quite natural
given the shortness of the implementation, and the not quite trivial
detail which is needed to get it right). So changing the interface by
adding policies would have meant unfortunately to depart from the
standard and created an obstacle towards that goal. Besides, the code
remains rather readable and simple without policies. So I am quite happy
to keep it like this.
</p></a>
</a>
<a name="perf">
<a href="minmax_benchs.html"><h3><b>About performance</b></h3></a>
</a>
<a name="acks">
<h3>
Acknowledgements</h3>
My students in CS903 (Polytechnic Univ., <a href="http://photon.poly.edu/~hbr/cs903/">http://photon.poly.edu/~hbr/cs903/</a>)
who had <tt>minmax_element</tt> as an assignment helped clarify the issues,
and also come up with the optimum number of comparisons for <tt>first_min_last_max_element</tt>.
The identification of the issue surrounding <tt>max_element</tt> is solely
my own.
<p>One <tt>minmax_element</tt> implementation, which performs <tt>3(n/2)+O(log
n)</tt> comparisons on the average when the elements are <tt>random_shuffle</tt>d,
was suggested by my student Marc Glisse. The current one, which performs
<tt>3(n/2)+1</tt>
comparisons in the worst case, was suggested by John Iacono.<p>
<p>Finally, Matthew Wilson and Jeremy Siek contributed pre-review
comments, while Gennadiy Rozental, John Maddock, Craig Henderson, Gary
Powell participated in the review of the library, managed by Thomas
Witt. In particular, Gennadiy suggested a factorization of the code;
while I haven't followed it all the way, his suggestions do make the
code more readable and still work with older compilers.
All my thanks for the excellent advice and reviews from all.
<h3>
See also</h3>
<tt><a href="http://www.sgi.com/tech/stl/min.html">min</a></tt>, <tt><a href="http://www.sgi.com/tech/stl/max.html">max</a></tt>,
<tt><a href="http://www.sgi.com/tech/stl/min_element.html">min_element</a></tt>,
<tt><a href="http://www.sgi.com/tech/stl/max_element.html">max_element</a></tt>,
<tt><a href="http://www.sgi.com/tech/stl/LessThanComparable.html">LessThan
Comparable</a></tt>,
<tt><a href="http://www.sgi.com/tech/stl/sort.html">sort</a></tt>,
<tt><a href="http://www.sgi.com/tech/stl/nth_element.html">nth_element</a></tt>
.
<hr SIZE="6">
<br>Last modified 2002-06-28
<p><font face="Arial,Helvetica"><font size=-1>&copy; Copyright Herv&eacute;
Br&ouml;nnimann, Polytechnic University, 2002--2004.
Use, modification, and distribution is subject to the Boost Software
License, Version 1.0. (See accompanying file <a href="../../LICENSE_1_0.txt">License_1_0.txt</a> or copy at
<a href="http://www.boost.org/LICENSE_1_0.txt">http://www.boost.org/LICENSE_1_0.txt</a>)
</font></font>
</body>
</html>

23
minmax/test/Jamfile Normal file
View File

@ -0,0 +1,23 @@
# Boost.Minmax Library Test Jamfile
#
# Copyright (C) 2002--2004, Herve Bronnimann
#
# Use, modification, and distribution is subject to 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)
#
subproject libs/minmax/test ;
# bring in rules for testing
SEARCH on testing.jam = $(BOOST_BUILD_PATH) ;
include testing.jam ;
# Make tests run by default.
DEPENDS all : test ;
{
test-suite minmax:
[ run minmax_test.cpp ]
;
}

17
minmax/test/Jamfile.v2 Normal file
View File

@ -0,0 +1,17 @@
# Boost.Minmax Library test Jamfile
#
# Copyright (C) 2002--2004, Herve Bronnimann
#
# Use, modification, and distribution is subject to 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)
#
import testing ;
{
test-suite minmax:
[ run minmax_test.cpp ]
;
}

241
minmax/test/minmax_test.cpp Normal file
View File

@ -0,0 +1,241 @@
#include <utility>
#include <functional>
#include <algorithm>
#include <numeric>
#include <iterator>
#include <vector>
#include <list>
#include <set>
#include <iostream>
#include <boost/minmax.hpp>
#include <boost/test/included/test_exec_monitor.hpp>
#include <boost/iterator/reverse_iterator.hpp>
class custom {
int _M_x;
friend bool operator<(custom const& x, custom const& y);
friend std::ostream& operator<<(std::ostream& str, custom const& x);
public:
explicit custom(int x = 0) : _M_x(x) {}
custom(custom const& y) : _M_x(y._M_x) {}
custom operator+(custom const& y) const { return custom(_M_x+y._M_x); }
custom& operator+=(custom const& y) { _M_x += y._M_x; return *this; }
};
bool operator< (custom const& x, custom const& y)
{
return x._M_x < y._M_x;
}
std::ostream& operator<<(std::ostream& str, custom const& x)
{
str << x._M_x;
return str;
}
namespace std {
template <>
struct iterator_traits<int*> {
typedef random_access_iterator_tag iterator_category;
typedef int value_type;
typedef ptrdiff_t difference_type;
typedef value_type* pointer;
typedef value_type& reference;
};
template <>
struct iterator_traits<custom*> {
typedef random_access_iterator_tag iterator_category;
typedef custom value_type;
typedef ptrdiff_t difference_type;
typedef value_type* pointer;
typedef value_type& reference;
};
}
template <class T1, class T2, class T3, class T4>
void tie(std::pair<T1, T2> p, T3& first, T4& second)
{
first = T3(p.first); second = T4(p.second);
}
template <class Value>
struct less_count : std::less<Value> {
typedef std::less<Value> Base;
less_count(less_count<Value> const& lc) : _M_counter(lc._M_counter) {}
less_count(int& counter) : _M_counter(counter) {}
bool operator()(Value const& a, Value const& b) const {
++_M_counter;
return Base::operator()(a,b);
}
void reset() {
_M_counter = 0;
}
private:
int& _M_counter;
};
inline int opt_min_count(int n) {
return (n==0) ? 0 : n-1;
}
inline int opt_minmax_count(int n) {
if (n < 2) return 0;
if (n == 2) return 2;
return (n%2 == 0) ? 3*(n/2)-1 : 3*(n/2)+1;
}
inline int opt_boost_minmax_count(int n) {
if (n < 2) return 0;
if (n == 2) return 1;
return (n%2 == 0) ? 3*(n/2)-2 : 3*(n/2);
}
#define CHECK_EQUAL_ITERATORS( left, right, first ) \
BOOST_CHECK_EQUAL( std::distance( first, left ), std::distance( first, right ) )
template <class CIterator>
void test_minmax(CIterator first, CIterator last, int n)
{
using namespace boost;
typedef typename std::iterator_traits<CIterator>::value_type Value;
typedef boost::reverse_iterator<CIterator> RCIterator;
// assume that CIterator is BidirectionalIter
CIterator min, max;
RCIterator rfirst(last), rlast(first), rmin(min), rmax(max);
int counter = 0;
less_count<Value> lc(counter);
// standard extensions
// first version, operator<
tie( boost::minmax_element(first, last), min, max );
CHECK_EQUAL_ITERATORS( min, std::min_element(first, last), first );
CHECK_EQUAL_ITERATORS( max, std::max_element(first, last), first );
// second version, comp function object (keeps a counter!)
lc.reset();
tie( boost::minmax_element(first, last, lc), min, max );
BOOST_CHECK( counter <= opt_minmax_count(n) );
CHECK_EQUAL_ITERATORS( min, std::min_element(first, last, lc), first );
CHECK_EQUAL_ITERATORS( max, std::max_element(first, last, lc), first );
// boost extensions
// first version, operator<
CHECK_EQUAL_ITERATORS( boost::first_min_element(first, last), std::min_element(first, last), first );
rmin = RCIterator(boost::last_min_element(first, last));
rmin = (rmin == rfirst) ? rlast : --rmin;
CHECK_EQUAL_ITERATORS( rmin, std::min_element(rfirst, rlast), rfirst );
CHECK_EQUAL_ITERATORS( boost::first_max_element(first, last), std::max_element(first, last), first );
rmax = RCIterator(boost::last_max_element(first, last));
rmax = (rmax == rfirst) ? rlast : --rmax;
CHECK_EQUAL_ITERATORS( rmax, std::max_element(rfirst, rlast), rfirst );
tie( boost::first_min_last_max_element(first, last), min, max );
CHECK_EQUAL_ITERATORS( min, boost::first_min_element(first, last), first );
CHECK_EQUAL_ITERATORS( max, boost::last_max_element(first, last), first );
tie( boost::last_min_first_max_element(first, last), min, max );
CHECK_EQUAL_ITERATORS( min, boost::last_min_element(first, last), first );
CHECK_EQUAL_ITERATORS( max, boost::first_max_element(first, last), first );
tie( boost::last_min_last_max_element(first, last), min, max );
CHECK_EQUAL_ITERATORS( min, boost::last_min_element(first, last), first );
CHECK_EQUAL_ITERATORS( max, boost::last_max_element(first, last), first );
// second version, comp function object (keeps a counter!)
lc.reset();
min = boost::first_min_element(first, last, lc);
BOOST_CHECK( counter <= opt_min_count(n) );
CHECK_EQUAL_ITERATORS( min, std::min_element(first, last, lc), first );
lc.reset();
rmin = RCIterator(boost::last_min_element(first, last, lc));
rmin = (rmin == rfirst) ? rlast : --rmin;
BOOST_CHECK( counter <= opt_min_count(n) );
CHECK_EQUAL_ITERATORS( rmin, std::min_element(rfirst, rlast, lc), rfirst );
lc.reset();
max = boost::first_max_element(first, last, lc);
BOOST_CHECK( counter <= opt_min_count(n) );
CHECK_EQUAL_ITERATORS( max, std::max_element(first, last, lc), first );
lc.reset();
rmax = RCIterator(boost::last_max_element(first, last, lc));
rmax = (rmax == rfirst) ? rlast : --rmax;
BOOST_CHECK( counter <= opt_min_count(n) );
CHECK_EQUAL_ITERATORS( rmax, std::max_element(rfirst, rlast, lc), rfirst );
lc.reset();
tie( boost::first_min_last_max_element(first, last, lc), min, max );
BOOST_CHECK( counter <= opt_boost_minmax_count(n) );
CHECK_EQUAL_ITERATORS( min, boost::first_min_element(first, last, lc), first );
CHECK_EQUAL_ITERATORS( max, boost::last_max_element(first, last, lc), first );
lc.reset();
tie( boost::last_min_first_max_element(first, last, lc), min, max );
BOOST_CHECK( counter <= opt_boost_minmax_count(n) );
BOOST_CHECK( min == boost::last_min_element(first, last, lc) );
CHECK_EQUAL_ITERATORS( max, boost::first_max_element(first, last, lc), first );
lc.reset();
tie( boost::last_min_last_max_element(first, last, lc), min, max );
BOOST_CHECK( counter <= opt_minmax_count(n) );
CHECK_EQUAL_ITERATORS( min, boost::last_min_element(first, last, lc), first );
CHECK_EQUAL_ITERATORS( max, boost::last_max_element(first, last, lc), first );
}
template <class Container, class Iterator, class Value>
void test_container(Iterator first, Iterator last, int n, Container* dummy = 0 )
{
Container c(first, last);
test_minmax(c.begin(), c.end(), n);
}
template <class Iterator>
void test_range(Iterator first, Iterator last, int n, char* name)
{
typedef typename std::iterator_traits<Iterator>::value_type Value;
// Test various containers with these values
// std::cout << " vector<" << name << ">...";
test_container< std::vector<Value>, Iterator, Value >(first, last, n);
// std::cout << " list<" << name << ">...";
test_container< std::list<Value>, Iterator, Value >(first, last, n);
// std::cout << " set<" << name << ">...";
test_container< std::set<Value>, Iterator, Value >(first, last, n);
// std::cout << "\n";
}
template <class Value>
void test(int n, char* name)
{
// Populate test vector with identical values
// std::cout << " Identical values... ";
std::vector<Value> test_vector(n, Value(1));
typename std::vector<Value>::iterator first( test_vector.begin() );
typename std::vector<Value>::iterator last( test_vector.end() );
test_range(first, last, n, name);
// Populate test vector with two values
// std::cout << " Two distinct values...";
typename std::vector<Value>::iterator middle( first + n/2 );
std::fill(middle, last, Value(2));
test_range(first, last, n, name);
// Populate test vector with increasing values
// std::cout << " Increasing values... ";
std::accumulate(first, last, Value(0));
test_range(first, last, n, name);
// Populate test vector with decreasing values
// std::cout << " Decreasing values... ";
std::reverse(first, last);
test_range(first, last, n, name);
// Populate test vector with random values
// std::cout << " Random values... ";
std::random_shuffle(first, last);
test_range(first, last, n, name);
}
int test_main( int argc, char* argv[] )
{
int n = 100;
if (argc > 1) n = atoi(argv[1]);
test<int>(n, "builtin");
test<custom>(n, "custom ");
return 0;
}