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

typedef long int64;

static char *
pg_int64tostr(char *str, int64 value)
{
	char *start;
	char *end;

	/*
	 * Handle negative numbers in a special way. We can't just append a '-'
	 * prefix and reverse the sign as on two's complement machines negative
	 * numbers can be 1 further from 0 than positive numbers, we do it this way
	 * so we properly handle the smallest possible value.
	 */
	if (value < 0)
	{
		*str++ = '-';

		/* mark the position we must reverse the string from. */
		start = str;

		/* Compute the result string backwards. */
		do
		{
			int64		remainder;
			int64		oldval = value;

			value /= 10;
			remainder = oldval - value * 10;
			*str++ = '0' + -remainder;
		} while (value != 0);
	}
	else
	{
		/* mark the position we must reverse the string from. */
		start = str;
		do
		{
			int64		remainder;
			int64		oldval = value;

			value /= 10;
			remainder = oldval - value * 10;
			*str++ = '0' + remainder;
		} while (value != 0);
	}

	/* Add trailing NUL byte, and back up 'str' to the last character. */
	end = str;
	*str-- = '\0';

	/* Reverse string. */
	while (start < str)
	{
		char		swap = *start;
		*start++ = *str;
		*str-- = swap;
	}
	return end;
}

static char *
pg_int64tostr_memcpy(char *str, int64 value)
{
	char temp[24];
	char *end = temp + 23;
	char *p = end;

	/*
	 * Handle negative numbers in a special way. We can't just append a '-'
	 * prefix and reverse the sign as on two's complement machines negative
	 * numbers can be 1 further from 0 than positive numbers, we do it this way
	 * so we properly handle the smallest possible value.
	 */
	 
	*p-- = '\0';
	 
	if (value < 0)
	{
		do
		{
			*p-- = -(value % 10) + '0';
			value /= 10;
		} while (value != 0);

		*p-- = '-';
	}
	else
	{
		do
		{
			*p-- = value % 10 + '0';
			value /= 10;
		} while (value != 0);
	}

	memcpy(str, p + 1, end - p);

	return str + (end - p - 1);
}


static char *
pg_int64tostr_new(char *str, int64 value)
{
	char *start;
	char *end;

	/*
	 * Handle negative numbers in a special way. We can't just append a '-'
	 * prefix and reverse the sign as on two's complement machines negative
	 * numbers can be 1 further from 0 than positive numbers, we do it this way
	 * so we properly handle the smallest possible value.
	 */
	if (value < 0)
	{
		*str++ = '-';

		/* mark the position we must reverse the string from. */
		start = str;

		/* Compute the result string backwards. */
		do
		{
			*str++ = -(value % 10) + '0';
			value /= 10;
		} while (value != 0);
	}
	else
	{
		/* mark the position we must reverse the string from. */
		start = str;
		do
		{
			*str++ = value % 10 + '0';
			value /= 10;
		} while (value != 0);
	}

	/* Add trailing NUL byte, and back up 'str' to the last character. */
	end = str;
	*str-- = '\0';

	/* Reverse string. */
	while (start < str)
	{
		char		swap = *start;
		*start++ = *str;
		*str-- = swap;
	}
	return end;
}

typedef char bool;
#define true 1
#define false 0

#define PG_INT64_MIN -9223372036854775808LL

void
pg_lltoa(int64 value, char *a)
{
	char	   *start = a;
	bool		neg = false;

	/*
	 * Avoid problems with the most negative integer not being representable
	 * as a positive integer.
	 */
	if (value == PG_INT64_MIN)
	{
		memcpy(a, "-9223372036854775808", 21);
		return;
	}
	else if (value < 0)
	{
		value = -value;
		neg = true;
	}

	/* Compute the result string backwards. */
	do
	{
		int64		remainder;
		int64		oldval = value;

		value /= 10;
		remainder = oldval - value * 10;
		*a++ = '0' + remainder;
	} while (value != 0);

	if (neg)
		*a++ = '-';

	/* Add trailing NUL byte, and back up 'a' to the last character. */
	*a-- = '\0';

	/* Reverse string. */
	while (start < a)
	{
		char		swap = *start;

		*start++ = *a;
		*a-- = swap;
	}
}
#define STARTNUM -1000000000
#define ENDNUM 1000000000

#define NUM_TO_PRINT 30

int main(void)
{
	clock_t start, finish;
	int i;
	char buffer[30];
	char *p;	

	start = clock();

	for(i = STARTNUM; i <= ENDNUM; i++)
		p = pg_int64tostr_memcpy(buffer, NUM_TO_PRINT);

	finish = clock();

	printf("pg_int64tostr_memcpy in %f seconds\n", (double) (finish - start) / CLOCKS_PER_SEC);

	start = clock();

	for(i = STARTNUM; i <= ENDNUM; i++)
		p = pg_int64tostr(buffer, NUM_TO_PRINT);

	finish = clock();

	printf("pg_int64tostr in %f seconds\n", (double) (finish - start) / CLOCKS_PER_SEC);

	start = clock();

	for(i = STARTNUM; i <= ENDNUM; i++)
		p = pg_int64tostr_new(buffer, NUM_TO_PRINT);

	finish = clock();

	printf("pg_int64tostr_new in %f seconds\n", (double) (finish - start) / CLOCKS_PER_SEC);

	start = clock();

    for(i = STARTNUM; i <= ENDNUM; i++)
		pg_lltoa(NUM_TO_PRINT, buffer);

	finish = clock();

	printf("pg_lltoa in %f seconds\n", (double) (finish - start) / CLOCKS_PER_SEC);


	return 0;
}
