#include <stdio.h>
#include <string.h>
#include <time.h>
#include "ut_string_class.h"


// simple helper class to help us time the operations
class Timer
{
public:
	void	start()			{ m_start = clock(); }
	void	stop()			{ m_stop  = clock(); }
	clock_t	elapsed() const	{ return m_stop - m_start; };
private:
	clock_t	m_start;
	clock_t	m_stop;
};


//
// change this to a higher value if you have a faster CPU
//
const size_t nLoops = 16;


void append_raw(char* p, size_t nSize, const char* sz)
{
	for (size_t iOuter = 0; iOuter < nLoops; ++iOuter) {
		*p = 0;
		for (size_t i=0; i < nSize; ++i) {
			strcat(p, sz);
		}
	}
}

void append_UT_String(UT_String& s, size_t nSize, const char* sz)
{
	for (size_t iOuter = 0; iOuter < nLoops; ++iOuter) {
		s = "";
		for (size_t i = 0; i < nSize; ++i) {
			s += sz;
		}
	}
}

void print_speeds(	const Timer&		tRaw,
					const Timer&		tStr,
					const UT_String&	sOp)
{
	if (!tStr.elapsed() || !tRaw.elapsed()) {
		printf(	"Measurement time too short, display not possible.\n"
				"Please increase 'nLoops' in UT_String_speed_test and try again.\n");
		return;
	}

	const float fRatio = float(tStr.elapsed()) / float(tRaw.elapsed());
	printf("\n");
	printf("Op       : %s\n", sOp.c_str());
	printf("char[]   : %d clocks\n",  static_cast<int>(tRaw.elapsed()));
	printf("UT_String: %d clocks\n",  static_cast<int>(tStr.elapsed()));
	if (fRatio < 1.0f) {
		printf("UT_String was about %.2f times FASTER!\n", 1.0f/fRatio);
	} else {
		printf("UT_String was about %.2f times slower than %s\n",
			fRatio, sOp.c_str());
	}
}

void verify_contents_is_x(const char* sz, const UT_String& s, size_t n)
{
	for (size_t i = 0; i < n; ++i) {
		if (sz[i] != 'x') {
			printf("sz error!\n");
			break;
		}
		if (s[i] != 'x') {
			printf("UT_String error!\n");
			break;
		}
	}
}

void verify_contents_is_xy(const char* sz, const UT_String& s, size_t nPairs)
{
	for (size_t i = 0; i < nPairs; ++i) {
		const size_t iBase = i * 2;
		if (sz[iBase] != 'x' || sz[iBase+1] != 'y') {
			printf("sz error!\n");
			break;
		}
		if (s[iBase] != 'x' || s[iBase+1] != 'y') {
			printf("UT_String error!\n");
			break;
		}
	}
}

int main()
{
	Timer		tRaw;
	Timer		tStr;
	UT_String	s1;

	const size_t nChars = 4096;	// bufsize to test
	const size_t nPairs = nChars / 2;

	char szTmp[nChars + 1];

	tRaw.start();	// just warm it
	tRaw.stop();	// just warm it

	tRaw.start();
	append_raw(szTmp, nChars, "x");
	tRaw.stop();

	tStr.start();
	append_UT_String(s1, nChars, "x");
	tStr.stop();

	verify_contents_is_x(szTmp, s1, nChars);

	// Note the auto-creation of the temporary UT_String (3rd arg)
	print_speeds(tRaw, tStr, "single char strcat");


	tRaw.start();
	append_raw(szTmp, nPairs, "xy");
	tRaw.stop();

	tStr.start();
	append_UT_String(s1, nPairs, "xy");
	tStr.stop();

	verify_contents_is_xy(szTmp, s1, nPairs);

	print_speeds(tRaw, tStr, "double char strcat");

	return 0;
}