/*****************************************************************************
 * $Id: returnValueOptimizationPosition.cc,v 1.1 2006/10/21 00:19:08 devel Exp $
 * @file
 * @author	Jim E. Brooks  http://www.jimbrooks.org
 * @brief	This test proves that the C++ "return value optimization"
 *          is faster than returning a reference to a Position class.
 *          The return value optimization applies if the return value
 *          has the form of a constructor call.
 *//*
 * LEGAL:	COPYRIGHT (C) 2006 JIM E. BROOKS
 *          THIS SOURCE CODE IS RELEASED UNDER THE TERMS
 *          OF THE GNU GENERAL PUBLIC LICENSE (GPL).
 *****************************************************************************/

////////////////////////////////////////////////////////////////////////////////
//
// The return value optimization is both faster and better
// than the hacky fill-static-and-return-its reference.
// A contributing factor is that, although writing x/y/z
// is slower at first than returning a pointer, the caller
// then has direct access to them (rather than dereferencing each one).
//
// Fedora 5 x86-64 using g++-4.1 -O3
//
//------------------------------------
//test: test1
//secs (user) = 6.94
//------------------------------------
//------------------------------------
//test: test2
//secs (user) = 4.63
//------------------------------------
//
////////////////////////////////////////////////////////////////////////////////

const int loops = 500*1000*1000;

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

float sx = 1.0;
float sy = 2.0;
float sz = 3.0;
float dist2 = 0.0;

class Position
{
public:
    Position( void ) { }
    Position( float X, float Y, float Z ) : x(X), y(Y), z(Z) { }
    float x, y, z;
};

Position sPos(2.0,2.0,2.0);
bool flag;

/*****************************************************************************
 * Returns a reference.  May seem faster but it isn't.
 *****************************************************************************/
const Position& Test1a( void )
{
    static Position pos;
    pos.x = sx;
    pos.y = sy;
    pos.z = sz;
    return pos;
}
void
Test1( void )
{
    const Position& pos = Test1a();
	dist2 = pos.x * pos.x 
          + pos.y * pos.y 
          + pos.z * pos.z;		// .x,.y,.z need deferencing
    if ( pos.x ) flag = true;
}

/*****************************************************************************
 * Uses the "return value optimization" where a constructor call is returned.
 *****************************************************************************/
Position Test2a( void )
{
    return Position( sx, sy, sz );
}
void
Test2( void )
{
    const Position pos = Test2a();
	dist2 = pos.x * pos.x 
          + pos.y * pos.y 
          + pos.z * pos.z;		// direct access to x,y,z
    if ( pos.x ) flag = true;
}

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();
	return;
}

int
main( int argc, char** argv )
{
	cout << "First test should take more time if return value optimization was applied..." << endl;
	Measure( Test1, "test1" );
	Measure( Test2, "test2" );
}
