// toIntTest.cpp : Defines the entry point for the console application.
//

#include <stdio.h>
#include "getCurrentTime.h"

#include "../fw/2007.12/src/base/point.h"

#if defined(__AIX) || defined(__sparc)
#define BUSERR_PROTECTION
#else
#define LOW_ENDIAN_ARCH
#endif

#if defined(__AIX) || defined(__sparc)
#define TEST_AMOUNT 100000000
#else
#define TEST_AMOUNT 1000000000
#endif


#ifdef _MSC_VER
#define MY_INLINE __forceinline
#else
#define MY_INLINE inline
#endif

#ifndef _MSC_VER
#define __int64 long
#endif


	MY_INLINE bool isShortAligned( const unsigned char * p )
	{
		return !((int)(p) % 2);
	}

	MY_INLINE bool isIntAligned( const unsigned char * p )
	{
		return !((int)(p) % 4);
	}

	//
	/// Convert a gdsII short to a standard short.
	//
	/*!
	 * The supplied pointer is to the buffer containing the entire gdsII short.
	 */
	MY_INLINE short toShort1( const unsigned char * p )
	{
		//
		// convert the byte stream to a machine short
		//
		register short val = *p << 8;
		val += *(p+1);
		//
		// check for negative
		//
		if ( val & 0x8000 )
		{
			val &= 0x7ffff;
			val ^= 0x7ffff;
			val = ++val * -1;
		}
		return val;
	}

	//
	/// Convert a gdsII short to a standard short.
	//
	/*!
	 * The supplied pointer is to the buffer containing the entire gdsII short.
	 */
	/* slow on sparc */
	MY_INLINE short toShort2( const unsigned char * p )
	{
#ifdef BUSERR_PROTECTION
		if ( isShortAligned(p) )
		{
#endif
#ifdef LOW_ENDIAN_ARCH
		//
		// convert the byte stream to a machine short
		//
		register unsigned short val = *reinterpret_cast<const short*>(p);
		const short mask = 0x00ff;
		val = (val & mask) << 8 | (val & ~mask) >> 8;
		return (unsigned short)(val);
#else
		//
		// convert the byte stream to a machine short
		//
		return *reinterpret_cast<const short*>(p);
#endif
#ifdef BUSERR_PROTECTION
		}
		else
			return *p << 8 | *(p+1);
#endif
	}

	//
	/// Convert a gdsII short to a standard short.
	//
	/*!
	 * The supplied pointer is to the buffer containing the entire gdsII short.
	 */
	/* slow on amd64 */
	MY_INLINE short toShort2_( const unsigned char * p )
	{
#ifdef BUSERR_PROTECTION
		if ( isShortAligned(p) )
		{
#endif
#ifdef LOW_ENDIAN_ARCH
		//
		// convert the byte stream to a machine short
		//
//		register short val = *p << 8;
//		return val | *(p+1);
		register unsigned int val = *reinterpret_cast<const short*>(p);
		const int mask = 0x000000ff;
		val = (val & mask) << 8 | (val & ~mask) >> 8;
		return (unsigned short)(val);
#else
		//
		// convert the byte stream to a machine short
		//
		return *reinterpret_cast<const short*>(p);
#endif
#ifdef BUSERR_PROTECTION
		}
		else
			return *p << 8 | *(p+1);
#endif
	}

	//
	/// Convert a gdsII short to a standard short.
	//
	/*!
	 * The supplied pointer is to the buffer containing the entire gdsII short.
	 */
	MY_INLINE short toShort3( const unsigned char * p )
	{
#ifdef BUSERR_PROTECTION
		if ( isShortAligned(p) )
		{
#endif
#ifdef LOW_ENDIAN_ARCH
		//
		// convert the byte stream to a machine short
		//
		register unsigned short val = *reinterpret_cast<const unsigned short*>(p);
		return val >> 8 | val << 8;
#else
		//
		// convert the byte stream to a machine short
		//
		return *reinterpret_cast<const short*>(p);
#endif
#ifdef BUSERR_PROTECTION
		}
		else
			return *p << 8 | *(p+1);
#endif
	}

	//
	/// Convert a gdsII short to a standard short.
	//
	/*!
	 * The supplied pointer is to the buffer containing the entire gdsII short.
	 */
	MY_INLINE short toShort3_( const unsigned char * p )
	{
#ifdef BUSERR_PROTECTION
		if ( isShortAligned(p) )
		{
#endif
#ifdef LOW_ENDIAN_ARCH
		//
		// convert the byte stream to a machine short
		//
		register unsigned int val = 0;
		val = *reinterpret_cast<const unsigned short*>(p);
		return val >> 8 | val << 8;
#else
		//
		// convert the byte stream to a machine short
		//
		return *reinterpret_cast<const short*>(p);
#endif
#ifdef BUSERR_PROTECTION
		}
		else
			return *p << 8 | *(p+1);
#endif
	}

	MY_INLINE int toInt1 ( const unsigned char * p )
	{
		//
		// convert the byte stream to a machine int
		//
		register int val = *p++ << 24;
		val += *p++ << 16;
		val += *p++ << 8;
		val += *p;

		//
		// check for negative
		//
		if ( val & 0x80000000 )
		{
			val &= 0x7fffffff;
			val ^= 0x7fffffff;
			val = ++val * -1;
		}
		return val;
	}

	//
	//	THE BEST
	//
	MY_INLINE int toInt2 ( const unsigned char * p )
	{
#ifdef BUSERR_PROTECTION
		if ( isIntAligned(p) )
		{
#endif
#ifdef LOW_ENDIAN_ARCH
		//
		// convert the byte stream to a machine int
		//
		register unsigned int val = *reinterpret_cast<const int*>(p);
		const int mask = 0x00ff00ff;
		val = (val & mask) << 8 | (val & ~mask) >> 8;
		return val >> 16 | val << 16;
#else
		//
		// convert the byte stream to a machine int
		//
		return *reinterpret_cast<const int*>(p);
#endif
#ifdef BUSERR_PROTECTION
		}
		else
			return *p << 24 | *(p+1) << 16 | *(p+2) << 8 | *(p+3);
#endif
	}

/* 	This is SLOW
	MY_INLINE int toInt3 ( const unsigned char * p )
	{
#ifdef BUSERR_PROTECTION
		if ( isIntAligned(p) )
		{
#endif
#ifdef LOW_ENDIAN_ARCH
		//
		// convert the byte stream to a machine int
		//
		union
		{
			unsigned char val[4];
			int iVal;
		} o;
		o.val[0] = p[3];
		o.val[1] = p[2];
		o.val[2] = p[1];
		o.val[3] = p[0];

		return o.iVal;
#else
		//
		// convert the byte stream to a machine int
		//
		return *reinterpret_cast<const int*>(p);
#endif
#ifdef BUSERR_PROTECTION
		}
		else
			return *p << 24 | *(p+1) << 16 | *(p+2) << 8 | *(p+3);
#endif
	}
*/


#ifdef __GCC__
typedef long __int64;
#endif

	typedef pod::point<int> point_int;

	MY_INLINE point_int toIntPoint1 ( const unsigned char * p )
	{
		int x = toInt2(p);
		int y = toInt2(p+sizeof(int));
		return point_int(x,y);
	}

	MY_INLINE point_int toIntPoint2 ( const unsigned char * p )
	{
#if defined(LOW_ENDIAN_ARCH) && defined(_LP64)

#ifdef BUSERR_PROTECTION
		if ( isIntAligned(p) )
		{
#endif
		//
		// convert the byte stream to a machine int
		//
		register unsigned __int64 val 
				= *reinterpret_cast<const __int64*>(p);
		const unsigned __int64 mask8 = 0x00ff00ff00ff00ffL;
		const unsigned __int64 mask16 = 0x0000ffff0000ffffL;
		val = (val & mask8) << 8 | (val & ~mask8) >> 8;
		val = (val & mask16) << 16 | (val & ~mask16) >> 16;
		return point_int( int((val << 32) >> 32), int(val >> 32) );
#ifdef BUSERR_PROTECTION
		}
#endif
#endif

#if !defined(LOW_ENDIAN_ARCH) || !defined(_LP64) || defined( BUSERR_PROTECTION )
		//
		// 32b code
		//
		int x = toInt2(p);
		int y = toInt2(p+sizeof(int));
		return point_int(x,y);
#endif
	}



int main(int argc, char* argv[])
{
//	Init
	initGetCurrentTimeLib();

	unsigned char buffer1[] = {
		   	0x01, 0x02, 0x03, 0x04,
		   	0x05, 0x06, 0x07, 0x08,
		   	0x09, 0x0A, 0x0B, 0x0C };
	unsigned char* buffer = buffer1;
	int szNum=0x01020344;
	int szNum2=0x01020304;

	double dwStart, dwEnd;

	//
	//	test toShort
	//
#if 1
	puts("Calculating speed for toShortX() aligned");
	dwStart = getCurrentTime();
	for ( int i = TEST_AMOUNT; i; --i )
		volatile short a = toShort1( buffer );
	dwEnd = getCurrentTime();
	printf( "toShort1 \t%f\n", dwEnd - dwStart );

	dwStart = getCurrentTime();
	for ( int i = TEST_AMOUNT; i; --i )
		 volatile short a = toShort2( buffer );
	dwEnd = getCurrentTime();
	printf( "toShort2 \t%f\n", dwEnd - dwStart );

	dwStart = getCurrentTime();
	for ( int i = TEST_AMOUNT; i; --i )
		 volatile short a = toShort2_( buffer );
	dwEnd = getCurrentTime();
	printf( "toShort2_ \t%f\n", dwEnd - dwStart );

	dwStart = getCurrentTime();
	for ( int i = TEST_AMOUNT; i; --i )
		 volatile short a = toShort3( buffer );
	dwEnd = getCurrentTime();
	printf( "toShort3 \t%f\n", dwEnd - dwStart );

	dwStart = getCurrentTime();
	for ( int i = TEST_AMOUNT; i; --i )
		 volatile short a = toShort3_( buffer );
	dwEnd = getCurrentTime();
	printf( "toShort3_ \t%f\n", dwEnd - dwStart );
#endif

#if 1
	puts("Calculating speed for toShortX() not aligned");

	dwStart = getCurrentTime();
	for ( int i = TEST_AMOUNT; i; --i )
		volatile short a = toShort1( buffer+1 );
	dwEnd = getCurrentTime();
	printf( "toShort1 \t%f\n", dwEnd - dwStart );

	dwStart = getCurrentTime();
	for ( int i = TEST_AMOUNT; i; --i )
		 volatile short a = toShort2( buffer+1 );
	dwEnd = getCurrentTime();
	printf( "toShort2 \t%f\n", dwEnd - dwStart );

	dwStart = getCurrentTime();
	for ( int i = TEST_AMOUNT; i; --i )
		 volatile short a = toShort2_( buffer+1 );
	dwEnd = getCurrentTime();
	printf( "toShort2_ \t%f\n", dwEnd - dwStart );

	dwStart = getCurrentTime();
	for ( int i = TEST_AMOUNT; i; --i )
		 volatile short a = toShort3( buffer+1 );
	dwEnd = getCurrentTime();
	printf( "toShort3 \t%f\n", dwEnd - dwStart );

	dwStart = getCurrentTime();
	for ( int i = TEST_AMOUNT; i; --i )
		 volatile short a = toShort3_( buffer+1 );
	dwEnd = getCurrentTime();
	printf( "toShort3_ \t%f\n", dwEnd - dwStart );
#endif

	//
	//	test toInt
	//
#if 1
	puts("Calculating speed for toIntX() aligned");

	dwStart = getCurrentTime();
	for ( int i = TEST_AMOUNT; i; --i )
		volatile int a = toInt1( buffer );
	dwEnd = getCurrentTime();
	printf( "toInt1 \t%f\n", dwEnd - dwStart );

	dwStart = getCurrentTime();
	for ( int i = TEST_AMOUNT; i; --i )
		 volatile int a = toInt2( buffer );
	dwEnd = getCurrentTime();
	printf( "toInt2 \t%f\n", dwEnd - dwStart );

//	dwStart = getCurrentTime();
//	for ( int i = TEST_AMOUNT; i; --i )
//		 volatile int a = toInt3( buffer );
//	dwEnd = getCurrentTime();
//	printf( "toInt3 \t%f\n", dwEnd - dwStart );

#endif

#if 1
	puts("Calculating speed for toIntX() miss aligned");

	dwStart = getCurrentTime();
	for ( int i = TEST_AMOUNT; i; --i )
		volatile int a = toInt1( buffer+1 );
	dwEnd = getCurrentTime();
	printf( "toInt1 \t%f\n", dwEnd - dwStart );

	dwStart = getCurrentTime();
	for ( int i = TEST_AMOUNT; i; --i )
		 volatile int a = toInt2( buffer+1 );
	dwEnd = getCurrentTime();
	printf( "toInt2 \t%f\n", dwEnd - dwStart );

//	dwStart = getCurrentTime();
//	for ( int i = TEST_AMOUNT; i; --i )
//		 volatile int a = toInt3( buffer+1 );
//	dwEnd = getCurrentTime();
//	printf( "toInt3 \t%f\n", dwEnd - dwStart );
#endif

	//
	//	test toIntPoint
	//
#if 1
	puts("Calculating speed for toIntPointX()");
	volatile int nTest[2];
	point_int a;

	dwStart = getCurrentTime();
	for ( int i = TEST_AMOUNT; i; --i )
	{
		nTest[0] = nTest[1] = i;
		a += toIntPoint1( (const unsigned char *)&nTest );
	}
	dwEnd = getCurrentTime();
	printf( "toIntPoint1 \t%f\n", dwEnd - dwStart );

	dwStart = getCurrentTime();
	for ( int i = TEST_AMOUNT; i; --i )
	{
		nTest[0] = nTest[1] = i;
		a += toIntPoint2( (const unsigned char *)&nTest );
	}
	dwEnd = getCurrentTime();
	printf( "toIntPoint2 \t%f\n", dwEnd - dwStart );

	volatile int x = a.getX();
#endif

#if 1
	puts("Checking all results for toShort1()==toShort2()");
	for ( unsigned i = 0x10000; i; --i )
	if ( toShort1( (const unsigned char *)&i ) 
		!= toShort3_( (const unsigned char *)&i ) )
		printf( "Error 1-3 %x o:%x m:%x\n", i, 
				(unsigned int)toShort1( (const unsigned char *)&i ),
				(unsigned int)toShort3_( (const unsigned char *)&i ) );

	puts("Checking all results for toInt1()==toInt2()");
	for ( unsigned i = 0xffffffff; i; --i )
		if ( toInt1( (const unsigned char *)&i ) 
			!= toInt2( (const unsigned char *)&i ) )
			printf( "Error %x o:%x m:%x\n", i, 
						toInt1( (const unsigned char *)&i ),
					   	toInt2( (const unsigned char *)&i ) );
	

	puts("Checking all results for toIntPoint1()==toIntPoint2()");
	int n8Byte[2];
	n8Byte[1] = 0;
	for ( unsigned i = 0xffffffff; i; --i )
	{
		n8Byte[0] = i;
		if ( toIntPoint1( (const unsigned char *)&n8Byte ) 
			!= toIntPoint2( (const unsigned char *)&n8Byte ) )
			printf( "Error %x,%x o:%x,%x m:%x,%x\n",  
						n8Byte[0],
						n8Byte[1],
						toIntPoint1( (const unsigned char *)&n8Byte ).getX(),
					   	toIntPoint1( (const unsigned char *)&n8Byte ).getY(), 
						toIntPoint2( (const unsigned char *)&n8Byte ).getX(),
					   	toIntPoint2( (const unsigned char *)&n8Byte ).getY() );
	}

	n8Byte[0] = 0;
	for ( unsigned i = 0xffffffff; i; --i )
	{
		n8Byte[1] = i;
		if ( toIntPoint1( (const unsigned char *)&n8Byte ) 
			!= toIntPoint2( (const unsigned char *)&n8Byte ) )
			printf( "Error %x,%x o:%x,%x m:%x,%x\n",
						n8Byte[0],
						n8Byte[1],
						toIntPoint1( (const unsigned char *)&n8Byte ).getX(),
					   	toIntPoint1( (const unsigned char *)&n8Byte ).getY(), 
						toIntPoint2( (const unsigned char *)&n8Byte ).getX(),
					   	toIntPoint2( (const unsigned char *)&n8Byte ).getY() );
	}
#endif

	return 0;
}
