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

#include <QtCore/QCoreApplication>
#include <QtCore/QString>
#include <list>
#include <memory>
#include <string>

#if defined( _MSC_VER )
#pragma intrinsic (memcpy,memcmp,memset,strcat,strcmp,strcpy,strlen)
#endif

namespace constructor
{
	void * operator new(	size_t count, 
					void * object )
	{
		return object;
	}
}

//#define ALLOC_AT_ONCE
//#define USE_MALLOC
// TEMPLATE CLASS allocator
template<class T, int N>
class fast_allocator 
#ifndef USE_MALLOC
	: public std::allocator<T>
#endif
{
	char memory[N];
#ifndef ALLOC_AT_ONCE
	char* marker;
#endif

public:
	typedef std::allocator<T> MyBase;
	typedef T value_type;
	typedef value_type *pointer;
	typedef value_type & reference;
	typedef const value_type *const_pointer;
	typedef const value_type & const_reference;

	typedef size_t size_type;
	typedef ptrdiff_t difference_type;

	template<class _Other>
	struct rebind
	{	// convert an allocator<_Ty> to an allocator <_Other>
		typedef fast_allocator<_Other,N> other;
	};

	// return address of mutable _Val
	pointer address(reference _Val) const
	{
		return (&_Val);
	}

	const_pointer address(const_reference _Val) const
	{	// return address of nonmutable _Val
		return (&_Val);
	}

	fast_allocator() throw()
#ifndef ALLOC_AT_ONCE
		: marker( memory )
#endif
	{}

	// construct by copying (do nothing)
	fast_allocator( const fast_allocator<T,N>& ) throw()
#ifndef ALLOC_AT_ONCE
		: marker( memory )
#endif
	{}

	// construct from a related allocator (do nothing)
//	template<class _Other>
//	allocatorN(const std::allocator<_Other>&) throw()
//		: marker( memory )
//	{}

	// deallocate object at _Ptr, ignore size
	void deallocate(pointer p, size_type n )
	{
#ifdef ALLOC_AT_ONCE
		if ( p != static_cast<pointer>(memory) )
#ifdef USE_MALLOC
			free( p );
#else
			return MyBase::deallocate( p, n );
#endif
#else/*ALLOC_AT_ONCE*/
		if ( p+n == marker )
			marker = p;
		else if ( p < static_cast<pointer>(memory) 
				|| static_cast<pointer>(&memory[N]) <= p )
#ifdef USE_MALLOC
			free( p );
#else
			return MyBase::deallocate( p, n );
#endif
#endif
	}

	// allocate array of n elements
	pointer allocate(size_type nCount)
	{
		register size_type s = sizeof(T)*nCount;
#ifdef ALLOC_AT_ONCE
		if ( sizeof(T)*nCount < N )
			return static_cast<pointer>(memory);
#else
		if ( sizeof(T)*nCount < (&memory[N] - marker) )
		{
			pointer p = static_cast<pointer>(marker);
			marker += s;
			return p;
		}
#endif
		else
#ifdef USE_MALLOC
			return static_cast<char*>(malloc( s ));
#else
			return MyBase::allocate( nCount );
#endif
	}

	// allocate array of n elements, ignore hint
	pointer allocate(size_type nCount, const void *)
	{
		return allocate(nCount);
	}

	// construct object at _Ptr with value _Val
	void construct(pointer _Ptr, const T& _Val)
	{
		::new (_Ptr) T(_Val);
	}

	// destroy object at _Ptr
	void destroy( pointer p )
	{
		p->~T();
	}

	// estimate maximum array size
	size_type max_size() const throw()
	{
#ifdef USE_MALLOC
			return (size_type)(-1) / sizeof(T);
#else
//			return MyBase::max_size();
			return (int)(-1) / sizeof(T);
#endif
	}

//	bool operator( const fast_allocator& op )
//	{
//		return &op == this;
//	}
};

template <class T, int N> 
inline 
bool operator== ( const fast_allocator<T,N>& op1,
				const fast_allocator<T,N>& op2 )
{
	return &op1 == &op2;
}

// STRUCT char_traits<char> (FROM <string>)
template<class C>
struct fast_char_traits
{	// properties of a string or stream char element
	typedef C char_type;
	typedef int int_type;
	typedef std::streampos pos_type;
	typedef std::streamoff off_type;
//	typedef _Mbstatet state_type;

	// assign an element
	static void assign( char_type& l, const char_type& r)
	{
		l = r;
	}

	// test for element equality
	static bool eq( const char_type& l, const char_type& r)
	{
		return (l == r);
	}

	// test if l precedes r
	static bool lt( const char_type& l, const char_type& r)
	{
		return (l < r);
	}

	// compare [_First1, _First1 + n) with [_First2, ...)
	static int compare(const char_type *op1, const char_type *op2, size_t n)
	{	
		return (::memcmp(op1, op2, n*sizeof(char_type)));
	}

	// find length of null-terminated string
	static size_t length(const char_type * op)
	{
		return (::strlen(op));
	}

	// assume there is enough space in the destination buffer
	static char_type * copy(char_type *dest, const char_type *src, size_t n)
	{
		return reinterpret_cast<char_type*>(::memcpy( dest, src, n*sizeof(char_type) ));
	}

	// look for _Ch in [_First, _First + n)
	static const char_type * find(const char_type * src, size_t n, const char_type& ch)
	{
		return ((const char_type *)::memchr(src, ch, n));
	}

	// move [_First1, _First1 + n) to [_First2, ...)
	// assume there is enough space in the destination buffer
	static char_type * move(char_type *dest, const char_type *src, size_t n)
	{	
		return reinterpret_cast<char_type*>(::memmove(dest, src, n*sizeof(char_type)));
	}

	// assign n * _Ch to [_First, ...)
	static char_type * assign(char_type *_First, size_t n, char_type _Ch)
	{
		return ((char_type *)::memset(_First, _Ch, n));
	}

	// convert metacharacter to character
	static char_type to_char_type(const int_type& chMeta)
	{
		return ((char_type)chMeta);
	}

	// convert character to metacharacter
	static int_type to_int_type(const char_type& ch)
	{
		return ((unsigned char)ch);
	}

	// test for metacharacter equality
	static bool eq_int_type(const int_type& l, const int_type& r)
	{
		return (l == r);
	}

	// return end-of-file metacharacter
	static int_type eof()
	{
		return (EOF);
	}

	// return anything but EOF
	static int_type not_eof(const int_type& chMeta)
	{
		return (chMeta != eof() ? chMeta : !eof());
	}
};

template <
   class CharType,
   class Traits=fast_char_traits<CharType>, 
   class Allocator=fast_allocator<CharType,64> 
>
class fast_basic_string : public std::basic_string< CharType, Traits, Allocator >
{
public:
	typedef fast_basic_string< CharType, Traits, Allocator > MySelf;
	typedef std::basic_string< CharType, Traits, Allocator > MyBase;

	fast_basic_string(
	   const typename MyBase::value_type* _Ptr, 
	   typename MyBase::size_type _Count, 
	   const typename MyBase::allocator_type& _Al = Allocator ( )
	)
	: std::basic_string< CharType, Traits, Allocator >( _Ptr, _Count, _Al )
	{}

	fast_basic_string(
	   const typename MyBase::value_type* _Ptr, 
	   const typename MyBase::allocator_type& _Al = Allocator ( )
	)
	: std::basic_string< CharType, Traits, Allocator >( _Ptr, _Al )
	{}

	fast_basic_string(
		const MyBase& _Right, 
	   typename MyBase::size_type _Roff = 0, 
	   typename MyBase::size_type _Count = npos,
	   const typename MyBase::allocator_type& _Al = Allocator ( )
	)
	: std::basic_string< CharType, Traits, Allocator >( _Right, _Roff, _Count, _Al )
	{}

	fast_basic_string(
	   typename MyBase::size_type _Count,
	   typename MyBase::value_type _Ch,
	   const typename MyBase::allocator_type& _Al = Allocator ( )
	)
	: std::basic_string< CharType, Traits, Allocator >( _Count, _Ch, _Al )
	{}

	explicit fast_basic_string(
	   const typename MyBase::allocator_type& _Al = Allocator ( )
	)
	: std::basic_string< CharType, Traits, Allocator >( _Al )
	{}

#if 0 //ndef _MSC_VER	
	bool operator == ( const MySelf& str )
	{
		return ( str.size() != size() ) ? false : MyBase::operator == ( str );
	}
#endif
};

#if 1 //def _MSC_VER
template <class Elem, class Traits, class Alloc> 
inline 
bool operator==(
		const fast_basic_string<Elem, Traits, Alloc>& l,
		const fast_basic_string<Elem, Traits, Alloc>& r )
{	// test for string equality
	return (l.size() != r.size()) ? 
				false : (l.compare(r) == 0);
}
#endif

typedef  fast_basic_string< char > fast_string;


const char* testStr[] =
{
	"1",							//1
	"12",							//2
	"123",							//3
	"1234",							//4
	"12345",						//5
	"123456",						//6
	"1234567",						//7
	"12345678",						//8
	"123456781",					//9
	"1234567812",					//10
	"12345678123",					//11
	"123456781234",					//12
	"1234567812345",				//13
	"12345678123456",				//14
	"123456781234567",				//15
	"1234567812345678",				//16
	"12345678123456781",			//17
	"123456781234567812",			//18
	"1234567812345678123",			//19
	"12345678123456781234567812345678",	//32
	"12345678123456781234567812345678123456781234567812345678123456",	//62
	"123456781234567812345678123456781234567812345678123456781234567",	//63
	"1234567812345678123456781234567812345678123456781234567812345678",	//64

	"12345678123456781234567812345678123456781234567812345678123456781",
	"123456781234567812345678123456781234567812345678123456781234567812",
	"1234567812345678123456781234567812345678123456781234567812345678123",
	"12345678123456781234567812345678123456781234567812345678123456781234",
	"123456781234567812345678123456781234567812345678123456781234567812345678",
	"12345678123456781234567812345678123456781234567812345678123456781234567812345678",
	"123456781234567812345678123456781234567812345678123456781234567812345678123456781234567812345678",
	"12345678123456781234567812345678123456781234567812345678123456781234567812345678123456781234567812345678123456781234567812345678",
	"12345678123456781234567812345678123456781234567812345678123456781234567812345678123456781234567812345678123456781234567812345678"
	"12345678123456781234567812345678123456781234567812345678123456781234567812345678123456781234567812345678123456781234567812345678",

};

template <class S, class S2>
inline
int initString( const S2& str )
{
	S a( str );
	return 0;
}

template <class S, class S2>
inline
int assignString( const S2& str )
{
	S a;
	a = str;
	return 0;
}

template <class S>
inline
int cmpEqString( const S& str1, const S& str2 )
{
	return str1 == str2;
}

template <class S>
inline
int cmpLessString( const S& str1, const S& str2 )
{
	return str1 < str2;
}

/*
std::list<QString*> listQString;
int alocQString(char const * const pStr)
{
	QString* a = new QString(pStr);
	listQString.push_back( a );
	return 0;
}

int freeQString()
{
	std::list<QString*>::iterator it = listQString.begin();
	std::list<QString*>::iterator itEnd = listQString.end();
	for ( ; it!=itEnd; ++it )
		delete *it;
	listQString.clear();
	return 0;
}

std::list<std::string*> listStdString;
int alocStdString(char const * const pStr)
{
	std::string* a = new std::string(pStr);
	listStdString.push_back( a );
	return 0;
}

int freeStdString()
{
	std::list<std::string*>::iterator it = listStdString.begin();
	std::list<std::string*>::iterator itEnd = listStdString.end();
	for ( ; it!=itEnd; ++it )
		delete *it;
	listStdString.clear();
	return 0;
}
*/

template<	class S1, 
			class S2,
			int (*func1)( const S1& ),
			int (*func2)( const S2& ),
			int nProbes >
void testStringsUnary( char const * const pStr )
{
	double dwStart, dwEnd;

	S1 s1_op( pStr );
	S2 s2_op( pStr );

	dwStart = getCurrentTime();
	for ( int i = nProbes; i; --i )
		volatile int a = func1(s1_op);
	dwEnd = getCurrentTime();
	double dblDiff1 = dwEnd - dwStart;

	dwStart = getCurrentTime();
	for ( int i = nProbes; i; --i )
		volatile int a = func2(s2_op);
	dwEnd = getCurrentTime();
	double dblDiff2 = dwEnd - dwStart;

	printf( "m1 %f   m2 %f   m1/m2 %f   probs=%d\n", dblDiff1, dblDiff2, dblDiff1/dblDiff2, nProbes );
}

template<	class S1,
			class S2,
			int (*func1)(const S1&, const S1& ),
			int (*func2)(const S2&, const S2& ),
			int nProbes >
void testStringsBinary( char const * const pStr1, char const * const pStr2 )
{
	double dwStart, dwEnd;

	S1 s1_op1( pStr1 );
	S1 s1_op2( pStr2 );

	S2 s2_op1( pStr1 );
	S2 s2_op2( pStr2 );

	dwStart = getCurrentTime();
	for ( int i = nProbes; i; --i )
		volatile int a = func1(s1_op1,s1_op2);
	dwEnd = getCurrentTime();
	double dblDiff1 = dwEnd - dwStart;

	dwStart = getCurrentTime();
	for ( int i = nProbes; i; --i )
		volatile int a = func2(s2_op1,s2_op2);
	dwEnd = getCurrentTime();
	double dblDiff2 = dwEnd - dwStart;

	printf( "m1 %f   m2 %f   m1/m2 %f   probs=%d\n", dblDiff1, dblDiff2, dblDiff1/dblDiff2, nProbes );
}

/*
void testStrings( char const * const pStr )
{
	double dwStart, dwEnd;

	int nProbes = 5000000;

	dwStart = getCurrentTime();
	for ( int i = nProbes; i; --i )
		volatile int a = alocStdString(pStr);
	dwEnd = getCurrentTime();
	printf( "alocStdString \t%f\t\t", dwEnd - dwStart );
	dwStart = getCurrentTime();
	{
		volatile int a = freeStdString();
	}
	dwEnd = getCurrentTime();
	printf( "freeStdString \t%f\n", dwEnd - dwStart );


	dwStart = getCurrentTime();
	for ( int i = nProbes; i; --i )
		volatile int a = alocQString(pStr);
	dwEnd = getCurrentTime();
	printf( "alocQString \t%f\t\t", dwEnd - dwStart );
	dwStart = getCurrentTime();
	{
		volatile int a = freeQString();
	}
	dwEnd = getCurrentTime();
	printf( "freeQString \t%f\n", dwEnd - dwStart );

	dwStart = getCurrentTime();
	for ( int i = nProbes; i; --i )
		volatile int a = alocStdString(pStr);
	dwEnd = getCurrentTime();
	printf( "alocStdString \t%f\t\t", dwEnd - dwStart );
	dwStart = getCurrentTime();
	{
		volatile int a = freeStdString();
	}
	dwEnd = getCurrentTime();
	printf( "freeStdString \t%f\n", dwEnd - dwStart );


	dwStart = getCurrentTime();
	for ( int i = nProbes; i; --i )
		volatile int a = alocQString(pStr);
	dwEnd = getCurrentTime();
	printf( "alocQString \t%f\t\t", dwEnd - dwStart );
	dwStart = getCurrentTime();
	{
		volatile int a = freeQString();
	}
	dwEnd = getCurrentTime();
	printf( "freeQString \t%f\n", dwEnd - dwStart );
}
*/

template <class S1, class S2>
void test()
{
#if 1
	/*
	*/
	puts(	"constructor(char*)		\n"
			"============================================================");
	for ( int i = 0; i < sizeof(testStr)/sizeof(testStr[0]); ++i )
	{
		printf("strlen: %3d   ", strlen(testStr[i]), testStr[i] );
		testStringsUnary<char const * const,
						char const * const,
						initString<S1, char const * const>,
						initString<S2, char const * const>,
						1000000>( testStr[i] );
	}
#endif

#if 1
	/*
	*/
	puts(	"constructor(native)	\n"
			"============================================================");
	for ( int i = 0; i < sizeof(testStr)/sizeof(testStr[0]); ++i )
	{
		printf("strlen: %3d   ", strlen(testStr[i]), testStr[i] );
		testStringsUnary<S1,
						S2,
						initString<S1, S1>,
						initString<S2, S2>,
						1000000>( testStr[i] );
	}
#endif

#if 1
	/*
	*/
	puts(	"operator = (char*)		\n"
			"============================================================");
	for ( int i = 0; i < sizeof(testStr)/sizeof(testStr[0]); ++i )
	{
		printf("strlen: %3d   ", strlen(testStr[i]), testStr[i] );
		testStringsUnary<char const * const,
						char const * const,
						assignString<S1, char const * const>,
						assignString<S2, char const * const>,
						1000000>( testStr[i] );
	}
#endif

#if 1
	/*
	*/
	puts(	"operator = (native)	\n"
			"============================================================");
	for ( int i = 0; i < sizeof(testStr)/sizeof(testStr[0]); ++i )
	{
		printf("strlen: %3d   ", strlen(testStr[i]), testStr[i] );
		testStringsUnary<S1,
						S2,
						assignString<S1, S1>,
						assignString<S2, S2>,
						1000000>( testStr[i] );
	}
#endif

#if 1
	/*
	*/
	puts(	"operator == ()		(equal strings)\n"
			"============================================================");
	for ( int i = 0; i < sizeof(testStr)/sizeof(testStr[0]) -1; ++i )
	{
		printf("strlen: %3d   ", strlen(testStr[i]), testStr[i] );
		testStringsBinary<	S1,
							S2,
							cmpEqString<S1>,
							cmpEqString<S2>,
						1000000>( testStr[i], testStr[i] );
	}
#endif

#if 1
	/*
	*/
	puts(	"operator == ()		(never equal strings)\n"
			"============================================================");
	for ( int i = 0; i < sizeof(testStr)/sizeof(testStr[0]) -1; ++i )
	{
		printf("strlen: %3d   ", strlen(testStr[i]), testStr[i] );
		testStringsBinary<	S1,
							S2,
							cmpEqString<S1>,
							cmpEqString<S2>,
						1000000>( testStr[i], testStr[i+1] );
	}
#endif

#if 1
	/*
	*/
	puts(	"operator <			(less strings)\n"
			"============================================================");
	for ( int i = 0; i < sizeof(testStr)/sizeof(testStr[0]) -1; ++i )
	{
		printf("strlen: %3d   ", strlen(testStr[i]), testStr[i] );
		testStringsBinary<	S1,
							S2,
							cmpLessString<S1>,
							cmpLessString<S2>,
						1000000>( testStr[i], testStr[i+1] );
	}
#endif

#if 1
	/*
	*/
	puts(	"operator < ()		(great strings)\n"
			"============================================================");
	for ( int i = 0; i < sizeof(testStr)/sizeof(testStr[0]) -1; ++i )
	{
		printf("strlen: %3d   ", strlen(testStr[i]), testStr[i] );
		testStringsBinary<	S1,
							S2,
							cmpLessString<S1>,
							cmpLessString<S2>,
						1000000>( testStr[i+1], testStr[i] );
	}
#endif
}

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

	QCoreApplication a(argc, argv);

#if 1
	puts(	"************************************************************\n"
			"************************************************************\n"
			"Testing                        m1=QString vs m2=std::string \n"
			"************************************************************");
	test<QString,std::string>();
#endif

#if 0
	puts(	"************************************************************\n"
			"************************************************************\n"
			"Testing                        m1=QString vs m2=fast_string \n"
			"************************************************************");
	test<QString,fast_string>();
#endif

//	return a.exec();
	return 0;
}
