blob: 1aefd21fc6dd0e2e471a2a942ccb51dd07ff9881 [file] [log] [blame]
/*
Copyright 2007-2008 Adobe Systems Incorporated
Distributed under the MIT License (see accompanying file LICENSE_1_0_0.txt
or a copy at http://stlab.adobe.com/licenses.html )
This test file started life as
ISO/IEC TR 18015:2006(E) Appendix D.4
Goals:
Compare the performance of function pointers, functors, inline functors,
standard functors, and native comparison operators
Also compare the performance of qsort(), quicksort template, and std::sort
Assumptions:
1) inline functors, standard functors and inlined native
comparisons will perform similarly
2) using functors is faster than using function pointers
3) inline functors are as fast or faster than out of line functors
4) a template is at least as fast as a hard coded function of
the same algorithm, sometimes faster
5) std::sort is faster than qsort()
6) std::sort is faster than a naive quicksort template using the same functor
Since qsort's comparison function must return int (less than 0, 0, greater than 0)
and std::sort's must return a bool, it is not possible to test them with each
other's comparator.
*/
/******************************************************************************/
#include <functional>
#include <algorithm>
#include <cstdlib>
#include "benchmark_results.h"
#include "benchmark_timer.h"
using namespace std;
/******************************************************************************/
template <class Iterator>
void verify_sorted(Iterator first, Iterator last) {
Iterator prev = first;
first++;
while (first != last) {
if (*first++ < *prev++) {
printf("test %i failed\n", current_test);
break;
}
}
}
/******************************************************************************/
// --------- helper functions --------------------------------------------
// qsort passes void * arguments to its comparison function,
// which must return negative, 0, or positive value
int
less_than_function1( const void * lhs, const void * rhs )
{
if( *(const double *) lhs < *(const double *) rhs ) return -1;
if( *(const double *) lhs > *(const double *) rhs ) return 1;
return 0;
}
// std::sort, on the other hand, needs a comparator that returns true or false
bool
less_than_function2( const double lhs, const double rhs )
{
return( lhs < rhs? true : false );
}
// the comparison operator in the following functor is defined out of line
struct less_than_functor
{
bool operator()( const double& lhs, const double& rhs ) const;
};
bool
less_than_functor::operator()( const double& lhs, const double& rhs ) const
{
return( lhs < rhs? true : false );
}
// the comparison operator in the following functor is defined inline
struct inline_less_than_functor
{
inline bool operator()( const double& lhs, const double& rhs ) const
{
return( lhs < rhs? true : false );
}
};
/******************************************************************************/
// hard coded comparison function
template<class Iterator>
void quicksort(Iterator begin, Iterator end)
{
// this only works for pointers and STL iterators
typedef typename iterator_traits<Iterator>::value_type T;
if ( (end - begin) > 1 ) {
T middleValue = *begin;
Iterator left = begin;
Iterator right = end;
for(;;) {
while ( middleValue < *(--right) );
if ( !(left < right ) ) break;
while ( *(left) < middleValue )
++left;
if ( !(left < right ) ) break;
// swap
T temp = *right;
*right = *left;
*left = temp;
}
quicksort( begin, right + 1 );
quicksort( right + 1, end );
}
}
/******************************************************************************/
// comparison function passed in as a functor
template<class Iterator, typename Comparator>
void quicksort(Iterator begin, Iterator end, Comparator compare)
{
// this only works for pointers and STL iterators
typedef typename iterator_traits<Iterator>::value_type T;
if ( (end - begin) > 1 ) {
T middleValue = *begin;
Iterator left = begin;
Iterator right = end;
for(;;) {
while ( compare( middleValue, *(--right) ) );
if ( !(left < right ) ) break;
while ( compare( *(left), middleValue ) )
++left;
if ( !(left < right ) ) break;
// swap
T temp = *right;
*right = *left;
*left = temp;
}
quicksort( begin, right + 1, compare );
quicksort( right + 1, end, compare );
}
}
/******************************************************************************/
typedef bool comparator_function( const double x, const double y );
// use a pointer to function as a template parameter
// exact function is known at compile time, and can be inlined
template<class Iterator, comparator_function compare>
void quicksort(Iterator begin, Iterator end)
{
// this only works for pointers and STL iterators
typedef typename iterator_traits<Iterator>::value_type T;
if ( (end - begin) > 1 ) {
T middleValue = *begin;
Iterator left = begin;
Iterator right = end;
for(;;) {
while ( compare( middleValue, *(--right) ) );
if ( !(left < right ) ) break;
while ( compare( *(left), middleValue ) )
++left;
if ( !(left < right ) ) break;
// swap
T temp = *right;
*right = *left;
*left = temp;
}
quicksort( begin, right + 1, compare );
quicksort( right + 1, end, compare );
}
}
/******************************************************************************/
// use a function pointer
// most compilers will not inline the function argument
void quicksort_function(double* begin, double* end, comparator_function compare)
{
if ( (end - begin) > 1 ) {
double middleValue = *begin;
double* left = begin;
double* right = end;
for(;;) {
while ( compare( middleValue, *(--right) ) );
if ( !(left < right ) ) break;
while ( compare( *(left), middleValue ) )
++left;
if ( !(left < right ) ) break;
// swap
double temp = *right;
*right = *left;
*left = temp;
}
quicksort( begin, right + 1, compare );
quicksort( right + 1, end, compare );
}
}
/******************************************************************************/
int main(int argc, char* argv[])
{
int i;
#ifdef SMALL_PROBLEM_SIZE
int iterations = (1 < argc) ? atoi(argv[1]) : 30; // number of iterations
#else
int iterations = (1 < argc) ? atoi(argv[1]) : 300; // number of iterations
#endif
int tablesize = (2 < argc) ? atoi(argv[2]) : 10000; // size of array
// seed the random number generator, so we get repeatable results
srand( tablesize + 123 );
// initialize the table to sort
double * master_table = new double[tablesize];
for( int n = 0; n < tablesize; ++n )
{
master_table[n] = static_cast<double>( rand() );
}
double * table = new double[tablesize]; // working copy
// here is where the timing starts
for (i = 0; i < iterations; ++i)
{
copy(master_table, master_table+tablesize, table);
qsort( table, tablesize, sizeof(double), less_than_function1 );
verify_sorted( table, table + tablesize );
}
for (i = 0; i < iterations; ++i)
{
copy(master_table, master_table+tablesize, table);
quicksort_function( table, table + tablesize, less_than_function2 );
verify_sorted( table, table + tablesize );
}
for (i = 0; i < iterations; ++i)
{
copy(master_table, master_table+tablesize, table);
quicksort( table, table + tablesize, less_than_function2 );
verify_sorted( table, table + tablesize );
}
for (i = 0; i < iterations; ++i)
{
copy(master_table, master_table+tablesize, table);
quicksort<double *, less_than_function2 >( table, table + tablesize );
verify_sorted( table, table + tablesize );
}
for (i = 0; i < iterations; ++i)
{
copy(master_table, master_table+tablesize, table);
sort( table, table + tablesize, less_than_function2 );
verify_sorted( table, table + tablesize );
}
for (i = 0; i < iterations; ++i)
{
copy(master_table, master_table+tablesize, table);
quicksort( table, table + tablesize, less_than_functor() );
verify_sorted( table, table + tablesize );
}
for (i = 0; i < iterations; ++i)
{
sort( table, table + tablesize, less_than_functor() );
verify_sorted( table, table + tablesize );
copy(master_table, master_table+tablesize, table);
}
for (i = 0; i < iterations; ++i)
{
copy(master_table, master_table+tablesize, table);
quicksort( table, table + tablesize, inline_less_than_functor() );
verify_sorted( table, table + tablesize );
}
for (i = 0; i < iterations; ++i)
{
copy(master_table, master_table+tablesize, table);
sort( table, table + tablesize, inline_less_than_functor() );
verify_sorted( table, table + tablesize );
}
for (i = 0; i < iterations; ++i)
{
copy(master_table, master_table+tablesize, table);
quicksort( table, table + tablesize, less<double>() );
verify_sorted( table, table + tablesize );
}
for (i = 0; i < iterations; ++i)
{
copy(master_table, master_table+tablesize, table);
sort( table, table + tablesize, less<double>() );
verify_sorted( table, table + tablesize );
}
for (i = 0; i < iterations; ++i)
{
copy(master_table, master_table+tablesize, table);
quicksort( table, table + tablesize );
verify_sorted( table, table + tablesize );
}
for (i = 0; i < iterations; ++i)
{
copy( master_table, master_table+tablesize, table );
sort( table, table + tablesize );
verify_sorted( table, table + tablesize );
}
delete[] table;
delete[] master_table;
return 0;
}