CityHash.cpp #3

  • //
  • guest/
  • ShadauxCat/
  • Sprawl/
  • Mainline/
  • hash/
  • CityHash.cpp
  • View
  • Commits
  • Open Download .zip Download (6 KB)
#include "CityHash.hpp"
#include <time.h>
#include <stdint.h>
#include <string.h>
#include "../common/compat.hpp"

#ifndef __BIG_ENDIAN__

#define INORDER32(x) (x)
#define INORDER64(x) (x)

#else

#ifdef _WIN32
#	include <stdlib.h>
#	define bswap_32(x) _byteswap_ulong(x)
#	define bswap_64(x) _byteswap_uint64(x)
#elif defined(__APPLE__)
#	include <libkern/OSByteOrder.h>
#	define bswap_32(x) OSSwapInt32(x)
#	define bswap_64(x) OSSwapInt64(x)
#else
#	include <byteswap.h>
#endif

#define INORDER32(x) (bswap_32(x))
#define INORDER64(x) (bswap_64(x))

#endif  // __BIG_ENDIAN__

namespace sprawl
{
	namespace cityhash
	{
		namespace CityHashStatic
		{
			struct uint128_t
			{
				uint64_t first;
				uint64_t second;
				uint128_t(uint64_t first_, uint64_t second_)
					: first(first_)
					, second(second_)
				{
					//
				}
			};

			static const uint64_t k0 = 0xc3a5c85c97cb3127ULL;
			static const uint64_t k1 = 0xb492b66fbe98f273ULL;
			static const uint64_t k2 = 0x9ae16a3b2f90404fULL;
			static const uint64_t k3 = 0xc949d7c7509e6557ULL;

			static inline uint64_t LoadUnaligned_32(const char *p)
			{
				uint64_t result;
				memcpy(&result, p, sizeof(result));
				return result;
			}

			static inline uint64_t LoadUnaligned_64(const char *p)
			{
				uint32_t result;
				memcpy(&result, p, sizeof(result));
				return result;
			}

			static inline uint64_t Fetch64(const char *p)
			{
				return INORDER64(LoadUnaligned_64(p));
			}

			static inline uint32_t Fetch32(const char *p)
			{
				return INORDER32(LoadUnaligned_32(p));
			}

			static inline uint64_t Rotate(uint64_t val, int shift)
			{
				return shift == 0 ? val : ((val >> shift) | (val << (64 - shift)));
			}

			static inline uint64_t RotateByAtLeastOne(uint64_t val, int shift)
			{
				return (val >> shift) | (val << (64 - shift));
			}

			static inline uint64_t ShiftMix(uint64_t val)
			{
				return val ^ (val >> 47);
			}

			static inline uint64_t Hash128to64(uint128_t const& x)
			{
				const uint64_t kMul = 0x9ddfea08eb382d69ULL;
				uint64_t a = (x.first ^ x.second) * kMul;
				a ^= (a >> 47);
				uint64_t b = (x.second ^ a) * kMul;
				b ^= (b >> 47);
				b *= kMul;
				return b;
			}

			static inline uint64_t Hash16(uint64_t u, uint64_t v)
			{
				return Hash128to64(uint128_t(u, v));
			}

			static uint64_t Hash0to16(char const* const data, size_t length)
			{
				if(length > 8)
				{
					uint64_t a = Fetch64(data);
					uint64_t b = Fetch64(data + length - 8);
					return Hash16(a, RotateByAtLeastOne(b + length, length)) ^ b;
				}
				if(length >= 4)
				{
					uint64_t a = Fetch32(data);
					return Hash16(length + (a << 3), Fetch32(data + length - 4));
				}
				if(length > 0)
				{
					uint8_t a = data[0];
					uint8_t b = data[length >> 1];
					uint8_t c = data[length - 1];
					uint32_t y = static_cast<uint32_t>(a) + (static_cast<uint32_t>(b) << 8);
					uint32_t z = length + (static_cast<uint32_t>(c) << 2);
					return ShiftMix(y * k2 ^ z * k3) * k2;
				}
				return k2;
			}

			static uint64_t Hash17to32(char const* const data, size_t length)
			{
				uint64_t a = Fetch64(data) * k1;
				uint64_t b = Fetch64(data + 8);
				uint64_t c = Fetch64(data + length - 8) * k2;
				uint64_t d = Fetch64(data + length - 16) * k0;
				return Hash16(Rotate(a - b, 43) + Rotate(c, 30) + d, a + Rotate(b ^ k3, 20) - c + length);
			}

			static uint64_t Hash33to64(char const* const data, size_t length)
			{
				uint64_t z = Fetch64(data + 24);
				uint64_t a = Fetch64(data) + (length + Fetch64(data + length - 16)) * k0;
				uint64_t b = Rotate(a + z, 52);
				uint64_t c = Rotate(a, 37);
				a += Fetch64(data + 8);
				c += Rotate(a, 7);
				a += Fetch64(data + 16);
				uint64_t vf = a + z;
				uint64_t vs = b + Rotate(a, 31) + c;
				a = Fetch64(data + 16) + Fetch64(data + length - 32);
				z = Fetch64(data + length - 8);
				b = Rotate(a + z, 52);
				c = Rotate(a, 37);
				a += Fetch64(data + length - 24);
				c += Rotate(a, 7);
				a += Fetch64(data + length - 16);
				uint64_t wf = a + z;
				uint64_t ws = b + Rotate(a, 31) + c;
				uint64_t r = ShiftMix((vf + ws) * k2 + (wf + vs) * k0);
				return ShiftMix(r * k0 + vs) * k2;
			}

			static inline uint128_t WeakHashLen32WithSeeds(uint64_t w, uint64_t x, uint64_t y, uint64_t z, uint64_t a, uint64_t b)
			{
				a += w;
				b = Rotate(b + a + z, 21);
				uint64_t c = a;
				a += x;
				a += y;
				b += Rotate(a, 44);
				return uint128_t(a + z, b + c);
			}

			static inline uint128_t WeakHashLen32WithSeeds(char const* const data, uint64_t a, uint64_t b)
			{
				return WeakHashLen32WithSeeds(
					Fetch64(data),
					Fetch64(data + 8),
					Fetch64(data + 16),
					Fetch64(data + 24),
					a,
					b
				);
			}
		}

		size_t Hash(void const* data, size_t length)
		{
			const char* data_ = static_cast<char const*>(data);
			if(length <= 32)
			{
				if(length <= 16)
				{
					return CityHashStatic::Hash0to16(data_, length);
				}
				return CityHashStatic::Hash17to32(data_, length);
			}
			else if(length <= 64)
			{
				return CityHashStatic::Hash33to64(data_, length);
			}

			uint64_t x = CityHashStatic::Fetch64(data_ + length - 40);
			uint64_t y = CityHashStatic::Fetch64(data_ + length - 16) + CityHashStatic::Fetch64(data_ + length - 56);
			uint64_t z = CityHashStatic::Hash16(CityHashStatic::Fetch64(data_ + length - 48) + length, CityHashStatic::Fetch64(data_ + length - 24));
			CityHashStatic::uint128_t v = CityHashStatic::WeakHashLen32WithSeeds(data_ + length - 64, length, z);
			CityHashStatic::uint128_t w = CityHashStatic::WeakHashLen32WithSeeds(data_ + length - 32, y + CityHashStatic::k1, x);
			x = x * CityHashStatic::k1 + CityHashStatic::Fetch64(data_);

			length = (length - 1) & ~static_cast<size_t>(63);

			do
			{
				x = CityHashStatic::Rotate(x + y + v.first + CityHashStatic::Fetch64(data_ + 8), 37) * CityHashStatic::k1;
				y = CityHashStatic::Rotate(y + v.second + CityHashStatic::Fetch64(data_ + 48), 42) * CityHashStatic::k1;
				x ^= w.second;
				y += v.first + CityHashStatic::Fetch64(data_ + 40);
				z = CityHashStatic::Rotate(z + w.first, 33) * CityHashStatic::k1;
				v = CityHashStatic::WeakHashLen32WithSeeds(data_, v.second * CityHashStatic::k1, x + w.first);
				w = CityHashStatic::WeakHashLen32WithSeeds(data_ + 32, z + w.second, y + CityHashStatic::Fetch64(data_ + 16));

				uint64_t temp = z;
				z = x;
				x = temp;

				data_ += 64;
				length -= 64;
			  } while (length != 0);
			  return CityHashStatic::Hash16(CityHashStatic::Hash16(v.first, w.first) + CityHashStatic::ShiftMix(y) * CityHashStatic::k1 + z, CityHashStatic::Hash16(v.second, w.second) + x);
		}
	}
}
# Change User Description Committed
#3 19906 ShadauxCat - Added tag, compile time string type
- Since tag requires visual studio 2015, removed compatibility code for earlier versions of visual studio
- Improved compiler detection
- Added endianness detection
- Added template if/else helper
- Fixed bug with murmur3 64 bit
- Added seed argument for murmur3

#review-19907
#2 14783 ShadauxCat Style corrections (placement of const)

#review-14784
#1 11496 ShadauxCat Initial checkin: Current states for csbuild and libSprawl