/*****************************************************************************
 * $Id: minmax.cc,v 1.4 2006/07/23 02:09:11 devel Exp $
 * @file
 * @author	Jim E. Brooks  http://www.jimbrooks.org
 * @brief	Test to confirm that C++ template variant Min()/Max() will result
 *          in a speedup, compared to the macro variant MIN()/MAX(),
 *          when the args are computations.  MIN()/MAX() cause redudant computations.
 *          Also proves that explicitly writing "inline" in template functions will be faster.
 *//*
 * LEGAL:	COPYRIGHT (C) 2005 JIM E. BROOKS
 *          THIS SOURCE CODE IS RELEASED UNDER THE TERMS
 *          OF THE GNU GENERAL PUBLIC LICENSE (GPL).
 *****************************************************************************/

#define TESTING 1
const int loops = 5*1000*1000;

#include <stdio.h>
#include <stdlib.h>
#include <iostream>
#include <sstream>
#include <string>
#include <math.h>
using namespace std;

// Simple but inefficient if A or B is a computation.
#define MIN(A,B) ( ((A) < (B)) ? (A) : (B) )
#define MAX(A,B) ( ((A) > (B)) ? (A) : (B) )

// Faster if A or B is a computation.
template<typename T> inline T Min( T a, T b ) { return (a < b) ? a : b; }
template<typename T> inline T Max( T a, T b ) { return (a > b) ? a : b; }

static int a = 1, b = 2, c;

#define COMPUTATION 1

// Function that does a slow computation.
int Foo( int x, int y )
{
	float a = x;
	float b = y;
	return (int) (a*b + b*(a+b) + a*(a+100) + sqrtf(a) + sqrtf(b));
}

// Test macro MIN()/MAX().
void
Test1( void )
{
#if COMPUTATION
	if ( MIN(Foo(a,b),Foo(b,a)) ) c = 1;
	if ( MAX(Foo(a,a),Foo(b,b)) ) c = 2;
#else
	if ( MIN(a,b) ) c = 1;
	if ( MAX(a,b) ) c = 2;
#endif
}

// Test C++ template Min()/Max().
void
Test2( void )
{
#if COMPUTATION
	if ( Min(Foo(a,b),Foo(b,a)) ) c = 1;
	if ( Max(Foo(a,a),Foo(b,b)) ) c = 2;
#else
	if ( Min(a,b) ) c = 1;
	if ( Max(a,b) ) c = 2;
#endif
}

void
Measure( void(*TestFunc)(void), const char* testName )
{
	std::ostringstream oss;

	// ANSI C code that measures the time the process consumed in user-mode.
	// Excludes kernel-mode (doesn't count time spent in video driver).
	int clocks1 = clock();

	for ( int i = 0; i < loops; ++i ) TestFunc();

	int clocks2			= clock();
	int clocksPerSec	= CLOCKS_PER_SEC;
	float secUser		= float(clocks2 - clocks1) / float(clocksPerSec);
	oss << "------------------------------------\n"
        << "test: " << testName << "\n"
	    << "secs (user) = " << secUser << "\n"
        << "------------------------------------\n";

	string result = oss.str();
	cout << result.c_str();
}

int
main( int argc, char** argv )
{
	Measure( Test1, "test1" );
	Measure( Test2, "test2" );
}
