//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: Variant Pearson Hash general purpose hashing algorithm described
//			by Cargill in C++ Report 1994.  Generates a 16-bit result.
//
//=============================================================================

#include <stdlib.h>
#include "tier0/basetypes.h"
#include "tier0/platform.h"
#include "generichash.h"
#include <ctype.h>
#include "tier0/dbg.h"

// NOTE: This has to be the last file included!
#include "tier0/memdbgon.h"


//-----------------------------------------------------------------------------
//
// Table of randomly shuffled values from 0-255 generated by:
//
//-----------------------------------------------------------------------------
/*
void MakeRandomValues()
{
	int i, j, r;
	unsigned  t;
	srand( 0xdeadbeef );

	for ( i = 0; i < 256; i++ )
	{
		g_nRandomValues[i] = (unsigned )i;
	}

	for (j = 0; j < 8; j++)
	{
		for (i = 0; i < 256; i++)
		{
			r = rand() & 0xff;
			t = g_nRandomValues[i];
			g_nRandomValues[i] = g_nRandomValues[r];
			g_nRandomValues[r] = t;
		}
	}

	printf("static unsigned g_nRandomValues[256] =\n{\n");

	for (i = 0; i < 256; i += 16)
	{
		printf("\t");
		for (j = 0; j < 16; j++)
			printf(" %3d,", g_nRandomValues[i+j]);
		printf("\n");
	}
	printf("};\n");
}
*/

static unsigned g_nRandomValues[256] =
{
	238,	164,	191,	168,	115,	 16,	142,	 11,	213,	214,	 57,	151,	248,	252,	 26,	198,
	 13,	105,	102,	 25,	 43,	 42,	227,	107,	210,	251,	 86,	 66,	 83,	193,	126,	108,
	131,	  3,	 64,	186,	192,	 81,	 37,	158,	 39,	244,	 14,	254,	 75,	 30,	  2,	 88,
	172,	176,	255,	 69,	  0,	 45,	116,	139,	 23,	 65,	183,	148,	 33,	 46,	203,	 20,
	143,	205,	 60,	197,	118,	  9,	171,	 51,	233,	135,	220,	 49,	 71,	184,	 82,	109,
	 36,	161,	169,	150,	 63,	 96,	173,	125,	113,	 67,	224,	 78,	232,	215,	 35,	219,
	 79,	181,	 41,	229,	149,	153,	111,	217,	 21,	 72,	120,	163,	133,	 40,	122,	140,
	208,	231,	211,	200,	160,	182,	104,	110,	178,	237,	 15,	101,	 27,	 50,	 24,	189,
	177,	130,	187,	 92,	253,	136,	100,	212,	 19,	174,	 70,	 22,	170,	206,	162,	 74,
	247,	  5,	 47,	 32,	179,	117,	132,	195,	124,	123,	245,	128,	236,	223,	 12,	 84,
	 54,	218,	146,	228,	157,	 94,	106,	 31,	 17,	 29,	194,	 34,	 56,	134,	239,	246,
	241,	216,	127,	 98,	  7,	204,	154,	152,	209,	188,	 48,	 61,	 87,	 97,	225,	 85,
	 90,	167,	155,	112,	145,	114,	141,	 93,	250,	  4,	201,	156,	 38,	 89,	226,	196,
	  1,	235,	 44,	180,	159,	121,	119,	166,	190,	144,	 10,	 91,	 76,	230,	221,	 80,
	207,	 55,	 58,	 53,	175,	  8,	  6,	 52,	 68,	242,	 18,	222,	103,	249,	147,	129,
	138,	243,	 28,	185,	 62,	 59,	240,	202,	234,	 99,	 77,	 73,	199,	137,	 95,	165,
};

//-----------------------------------------------------------------------------
// String 
//-----------------------------------------------------------------------------
unsigned FASTCALL HashString( const char *pszKey )
{
	const uint8 *k =   (const uint8 *)pszKey;
	unsigned 	even = 0,
				odd  = 0,
				n;

	while ((n = *k++) != 0)
	{
		even = g_nRandomValues[odd ^ n];
		if ((n = *k++) != 0)
			odd = g_nRandomValues[even ^ n];
		else
			break;
	}

	return (even << 8) | odd ;
}


//-----------------------------------------------------------------------------
// Case-insensitive string 
//-----------------------------------------------------------------------------
unsigned FASTCALL HashStringCaseless( const char *pszKey )
{
	const uint8 *k = (const uint8 *) pszKey;
	unsigned	even = 0,
				odd  = 0,
				n;

	while ((n = toupper(*k++)) != 0)
	{
		even = g_nRandomValues[odd ^ n];
		if ((n = toupper(*k++)) != 0)
			odd = g_nRandomValues[even ^ n];
		else
			break;
	}

	return (even << 8) | odd;
}

//-----------------------------------------------------------------------------
// 32 bit conventional case-insensitive string 
//-----------------------------------------------------------------------------
unsigned FASTCALL HashStringCaselessConventional( const char *pszKey )
{
	unsigned hash = 0xAAAAAAAA; // Alternating 1's and 0's to maximize the effect of the later multiply and add

	for( ; *pszKey ; pszKey++ )
	{
		hash = ( ( hash << 5 ) + hash ) + (uint8)tolower(*pszKey);
	}

	return hash;
}

//-----------------------------------------------------------------------------
// int hash
//-----------------------------------------------------------------------------
unsigned FASTCALL HashInt( const int n )
{
	unsigned		even, odd;
	even  = g_nRandomValues[n & 0xff];
	odd   = g_nRandomValues[((n >> 8) & 0xff)];

	even  = g_nRandomValues[odd ^ (n >> 24)];
	odd   = g_nRandomValues[even ^ ((n >> 16) & 0xff)];
	even  = g_nRandomValues[odd ^ ((n >> 8) &  0xff)];
	odd   = g_nRandomValues[even  ^ (n & 0xff)];

	return (even << 8) | odd;
}

//-----------------------------------------------------------------------------
// 4-byte hash
//-----------------------------------------------------------------------------
unsigned FASTCALL Hash4( const void *pKey )
{
	const uint32 *	p = (const uint32 *) pKey;
	unsigned		even,
					odd,
					n;
	n     = *p;
	even  = g_nRandomValues[n & 0xff];
	odd   = g_nRandomValues[((n >> 8) & 0xff)];

	even  = g_nRandomValues[odd ^ (n >> 24)];
	odd   = g_nRandomValues[even ^ ((n >> 16) & 0xff)];
	even  = g_nRandomValues[odd ^ ((n >> 8) &  0xff)];
	odd   = g_nRandomValues[even  ^ (n & 0xff)];

	return (even << 8) | odd;
}


//-----------------------------------------------------------------------------
// 8-byte hash
//-----------------------------------------------------------------------------
unsigned FASTCALL Hash8( const void *pKey )
{
	const uint32 *	p = (const uint32 *) pKey;
	unsigned		even,
					odd,
					n;
	n     = *p;
	even  = g_nRandomValues[n & 0xff];
	odd   = g_nRandomValues[((n >> 8) & 0xff)];

	even  = g_nRandomValues[odd ^ (n >> 24)];
	odd   = g_nRandomValues[even ^ ((n >> 16) & 0xff)];
	even  = g_nRandomValues[odd ^ ((n >> 8) &  0xff)];
	odd   = g_nRandomValues[even  ^ (n & 0xff)];

	n     = *(p+1);
	even  = g_nRandomValues[odd ^ (n >> 24)];
	odd   = g_nRandomValues[even  ^ ((n >> 16) & 0xff)];
	even  = g_nRandomValues[odd ^ ((n >> 8) &  0xff)];
	odd   = g_nRandomValues[even  ^ (n & 0xff)];

	return (even << 8) | odd;
}


//-----------------------------------------------------------------------------
// 12-byte hash
//-----------------------------------------------------------------------------
unsigned FASTCALL Hash12( const void *pKey )
{
	const uint32 *	p = (const uint32 *) pKey;
	unsigned		even,
					odd,
					n;
	n     = *p;
	even  = g_nRandomValues[n & 0xff];
	odd   = g_nRandomValues[((n >> 8) & 0xff)];

	even  = g_nRandomValues[odd ^ (n >> 24)];
	odd   = g_nRandomValues[even ^ ((n >> 16) & 0xff)];
	even  = g_nRandomValues[odd ^ ((n >> 8) &  0xff)];
	odd   = g_nRandomValues[even  ^ (n & 0xff)];

	n     = *(p+1);
	even  = g_nRandomValues[odd ^ (n >> 24)];
	odd   = g_nRandomValues[even  ^ ((n >> 16) & 0xff)];
	even  = g_nRandomValues[odd ^ ((n >> 8) &  0xff)];
	odd   = g_nRandomValues[even  ^ (n & 0xff)];

	n     = *(p+2);
	even  = g_nRandomValues[odd ^ (n >> 24)];
	odd   = g_nRandomValues[even  ^ ((n >> 16) & 0xff)];
	even  = g_nRandomValues[odd ^ ((n >> 8) &  0xff)];
	odd   = g_nRandomValues[even  ^ (n & 0xff)];

	return (even << 8) | odd;
}


//-----------------------------------------------------------------------------
// 16-byte hash
//-----------------------------------------------------------------------------
unsigned FASTCALL Hash16( const void *pKey )
{
	const uint32 *	p = (const uint32 *) pKey;
	unsigned		even,
					odd,
					n;
	n     = *p;
	even  = g_nRandomValues[n & 0xff];
	odd   = g_nRandomValues[((n >> 8) & 0xff)];

	even  = g_nRandomValues[odd ^ (n >> 24)];
	odd   = g_nRandomValues[even ^ ((n >> 16) & 0xff)];
	even  = g_nRandomValues[odd ^ ((n >> 8) &  0xff)];
	odd   = g_nRandomValues[even  ^ (n & 0xff)];

	n     = *(p+1);
	even  = g_nRandomValues[odd ^ (n >> 24)];
	odd   = g_nRandomValues[even  ^ ((n >> 16) & 0xff)];
	even  = g_nRandomValues[odd ^ ((n >> 8) &  0xff)];
	odd   = g_nRandomValues[even  ^ (n & 0xff)];

	n     = *(p+2);
	even  = g_nRandomValues[odd ^ (n >> 24)];
	odd   = g_nRandomValues[even  ^ ((n >> 16) & 0xff)];
	even  = g_nRandomValues[odd ^ ((n >> 8) &  0xff)];
	odd   = g_nRandomValues[even  ^ (n & 0xff)];

	n     = *(p+3);
	even  = g_nRandomValues[odd ^ (n >> 24)];
	odd   = g_nRandomValues[even  ^ ((n >> 16) & 0xff)];
	even  = g_nRandomValues[odd ^ ((n >> 8) &  0xff)];
	odd   = g_nRandomValues[even  ^ (n & 0xff)];

	return (even << 8) | odd;
}


//-----------------------------------------------------------------------------
// Arbitrary fixed length hash
//-----------------------------------------------------------------------------
unsigned FASTCALL HashBlock( const void *pKey, unsigned size )
{
	const uint8 *	k    = (const uint8 *) pKey;
	unsigned 		even = 0,
					odd  = 0,
					n;

	while (size)
	{
		--size;
		n    = *k++;
		even = g_nRandomValues[odd ^ n];
		if (size)
		{
			--size;
			n   = *k++;
			odd = g_nRandomValues[even ^ n];
		}
		else
			break;
	}

	return (even << 8) | odd;
}


//-----------------------------------------------------------------------------
// Murmur hash
//-----------------------------------------------------------------------------
uint32 MurmurHash2( const void * key, int len, uint32 seed )
{
	// 'm' and 'r' are mixing constants generated offline.
	// They're not really 'magic', they just happen to work well.

	const uint32 m = 0x5bd1e995;
	const int r = 24;

	// Initialize the hash to a 'random' value

	uint32 h = seed ^ len;

	// Mix 4 bytes at a time into the hash

	const unsigned char * data = (const unsigned char *)key;

	while(len >= 4)
	{
		uint32 k = LittleDWord( *(uint32 *)data );

		k *= m; 
		k ^= k >> r; 
		k *= m; 

		h *= m; 
		h ^= k;

		data += 4;
		len -= 4;
	}

	// Handle the last few bytes of the input array

	switch(len)
	{
	case 3: h ^= data[2] << 16;
	case 2: h ^= data[1] << 8;
	case 1: h ^= data[0];
		h *= m;
	};

	// Do a few final mixes of the hash to ensure the last few
	// bytes are well-incorporated.

	h ^= h >> 13;
	h *= m;
	h ^= h >> 15;

	return h;
}

#define TOLOWERU( c ) ( ( uint32 ) ( ( ( c >= 'A' ) && ( c <= 'Z' ) )? c + 32 : c ) )
uint32 MurmurHash2LowerCase( char const *pString, uint32 nSeed )
{
	int nLen = ( int )strlen( pString );
	char *p = ( char * ) stackalloc( nLen + 1 );
	for( int i = 0; i < nLen ; i++ )
	{
		p[i] = TOLOWERU( pString[i] );
	}
	return MurmurHash2( p, nLen, nSeed );
}


//-----------------------------------------------------------------------------
// Murmur hash, 64 bit- endian neutral
//-----------------------------------------------------------------------------
uint64 MurmurHash64( const void * key, int len, uint32 seed )
{
	// 'm' and 'r' are mixing constants generated offline.
	// They're not really 'magic', they just happen to work well.

	const uint32 m = 0x5bd1e995;
	const int r = 24;

	// Initialize the hash to a 'random' value

	uint32 h1 = seed ^ len;
	uint32 h2 = 0;

	// Mix 4 bytes at a time into the hash

	const uint32 * data = (const uint32 *)key;
	while ( len >= 8 )
	{
		uint32 k1 = LittleDWord( *data++ );
		k1 *= m; k1 ^= k1 >> r; k1 *= m;
		h1 *= m; h1 ^= k1;
		len -= 4;

		uint32 k2 = LittleDWord( *data++ );
		k2 *= m; k2 ^= k2 >> r; k2 *= m;
		h2 *= m; h2 ^= k2;
		len -= 4;
	}

	if(len >= 4)
	{
		uint32 k1 = LittleDWord( *data++ );
		k1 *= m; k1 ^= k1 >> r; k1 *= m;
		h1 *= m; h1 ^= k1;
		len -= 4;
	}

	// Handle the last few bytes of the input array
	switch(len)
	{
	case 3: h2 ^= ((uint8*)data)[2] << 16;
	case 2: h2 ^= ((uint8*)data)[1] << 8;
	case 1: h2 ^= ((uint8*)data)[0];
			h2 *= m;
	};

	h1 ^= h2 >> 18; h1 *= m;
	h2 ^= h1 >> 22; h2 *= m;
	h1 ^= h2 >> 17; h1 *= m;
	h2 ^= h1 >> 19; h2 *= m;

	uint64 h = h1;

	h = (h << 32) | h2;

	return h;
}