//////////////////////////////////////////////////////////////////////////////
//
// Asura_SpeedTest.h
//
// Copyright (c) 2005 Rebellion. All rights reserved.
//
// Description:
//
//     Speed testing code, based on Asura_UnitTest.h
//
//////////////////////////////////////////////////////////////////////////////

// B E G I N   F I L E   W R A P P E R ///////////////////////////////////////

#ifdef ASURA_USE_PRAGMA_ONCE
    #pragma once
#endif

#ifndef ___ASURA_SPEEDTEST_H___
#define ___ASURA_SPEEDTEST_H___ 1

// I N C L U D E S ///////////////////////////////////////////////////////////
#include "Core/Asura_String.h"

// M A C R O S ///////////////////////////////////////////////////////////////

// ASURA_SPEEDTEST - declares a class derived from Asura_SpeedTest_Test with a 
// name based on the testName and testGroup macro parameters which overrides 
// the Run() method. It then creates an instance of the class. Finally it 
// begins the definition of the Run() method for you. You must complete this
// definition (i.e. write the bit in curly braces) by writing some code that
// you want to have run by the speed test registry. The test is automatically 
// added to the test registry by the Asura_SpeedTest_Test constructor. 
// Example usage (must be in file scope with constants & globals already defined):
// 		ASURA_SPEEDTEST(MatrixMultiply, Asura_Matrix_3x3)
// 		{
//			for( u_int u = 0; u < uNUM_TESTS - 1; ++u )
//			{
//				g_ax3MatrixOutput[u & uDATA_MASK] = g_ax3MatrixInput[u & uDATA_MASK] * g_ax3MatrixInput[(u + 1) & uDATA_MASK];
//			}
// 		}
#define ASURA_SPEEDTEST(testGroup, testName)\
	static void testGroup##testName##SpeedTestMarker(); \
	class testGroup##testName##SpeedTest : public Asura_SpeedTest_Test \
	{ \
		public: \
		testGroup##testName##SpeedTest () : Asura_SpeedTest_Test (#testGroup": "#testName) {} \
		void Run () { testGroup##testName##SpeedTestMarker(); } \
		u_int GetMarker() const  { return reinterpret_cast<u_int>(&testGroup##testName##SpeedTestMarker); } \
	} \
    testGroup##testName##SpeedTestInstance; \
	static void testGroup##testName##SpeedTestMarker() 

// ASURA_SPEEDTEST_INITIALISER allows global data to be initialised before 
// any speed tests are done.
#define ASURA_SPEEDTEST_INITIALISER(testGroup)\
	class speedTestInitialiser##testGroup \
	{ \
		public: \
			speedTestInitialiser##testGroup();\
	} \
	speedTestInitialiser##testGroup##Instance; \
	speedTestInitialiser##testGroup::speedTestInitialiser##testGroup() 

#define ASURA_SPEEDTEST_ENDOFFILE(testGroup)\
	static void testGroup##SpeedTestMarker(); \
	class testGroup##SpeedTestDummy : public Asura_SpeedTest_Test \
	{ \
		public: \
		testGroup##SpeedTestDummy () : Asura_SpeedTest_Test ("dummy") {} \
		void Run () {} \
		bool IsDummy() const { return true; } \
		u_int GetMarker() const { return reinterpret_cast<u_int>(&testGroup##SpeedTestMarker); } \
	} \
    testGroup##SpeedTestDummyInstance; \
	static void testGroup##SpeedTestMarker() {} 

// F U N C T I O N   D E C L A R A T I O N S /////////////////////////////////
extern void Asura_SpeedTest_RunAllTests();


// C L A S S E S /////////////////////////////////////////////////////////////
class Asura_SpeedTest_Test
{
public:
	Asura_SpeedTest_Test(const Asura_String& xTestName);
	virtual ~Asura_SpeedTest_Test() {}

	virtual void	Run () = 0;
	virtual bool	IsDummy() const { return false; }
	virtual u_int	GetMarker() const = 0;

	void					SetNext(Asura_SpeedTest_Test* pxTest);
	Asura_SpeedTest_Test*	GetNext() const;

	const char*				GetName() const { return m_xName.GetString(); }

protected:

	Asura_String			m_xName;
	Asura_SpeedTest_Test*	m_pxNext;

};


// E N D   F I L E   W R A P P E R ///////////////////////////////////////////

#endif // #ifndef ___ASURA_SPEEDTEST_H___
