blob: 173839b762b783d756c581b6eab8f161d503a0c4 [file] [log] [blame]
// Copyright 2011 Google Inc. All Rights Reserved.
//
// Hash functions for C++ builtin types. These are all of the fundamental
// integral and floating point types in the language as well as pointers. This
// library provides a minimal set of interfaces for hashing these values.
#ifndef UTIL_HASH_BUILTIN_TYPE_HASH_H_
#define UTIL_HASH_BUILTIN_TYPE_HASH_H_
#include <stddef.h>
#include <stdint.h>
#include "gutil/casts.h"
#include "gutil/integral_types.h"
#include "gutil/macros.h"
#include "gutil/hash/jenkins_lookup2.h"
inline uint32 Hash32NumWithSeed(uint32 num, uint32 c) {
uint32 b = 0x9e3779b9UL; // the golden ratio; an arbitrary value
mix(num, b, c);
return c;
}
inline uint64 Hash64NumWithSeed(uint64 num, uint64 c) {
uint64 b = GG_ULONGLONG(0xe08c1d668b756f82); // more of the golden ratio
mix(num, b, c);
return c;
}
// This function hashes pointer sized items and returns a 32b hash,
// convenienty hiding the fact that pointers may be 32b or 64b,
// depending on the architecture.
inline uint32 Hash32PointerWithSeed(const void* p, uint32 seed) {
uintptr_t pvalue = reinterpret_cast<uintptr_t>(p);
uint32 h = seed;
// Hash the pointer 32b at a time.
for (size_t i = 0; i < sizeof(pvalue); i += 4) {
h = Hash32NumWithSeed(static_cast<uint32>(pvalue >> (i*8)), h);
}
return h;
}
// ----------------------------------------------------------------------
// Hash64FloatWithSeed
// Hash64DoubleWithSeed
// Functions for computing a hash value of floating-point numbers.
// On systems where float and double comply with IEEE 754, these hashes
// guarantee that if a == b, Hash64FloatWithSeed(a, c) ==
// Hash64FloatWithSeed(b, c). Note that NaN does not compare equal to
// itself, so two NaN inputs will not necessarily hash to the same value.
//
// It is often a mistake to compare floating-point values for equality,
// since floating-point computations do not produce exact values, due to
// rounding. If equality comparison doesn't make sense in your situation,
// hashing almost certainly doesn't make sense either.
//
// Not guaranteed to return the same value in different builds, or to
// avoid any reserved values.
// ----------------------------------------------------------------------
inline uint64 Hash64FloatWithSeed(float num, uint64 seed) {
// +0 and -0 are the only floating point numbers which compare equal but
// have distinct bitwise representations in IEEE 754. To work around this,
// we force 0 to be +0.
if (num == 0) {
num = 0;
}
COMPILE_ASSERT(sizeof(float) == sizeof(uint32), float_has_wrong_size);
const uint64 kMul = 0xc6a4a7935bd1e995ULL;
uint64 a = (bit_cast<uint32>(num) + seed) * kMul;
a ^= (a >> 47);
a *= kMul;
a ^= (a >> 47);
a *= kMul;
return a;
}
inline uint64 Hash64DoubleWithSeed(double num, uint64 seed) {
if (num == 0) {
num = 0;
}
COMPILE_ASSERT(sizeof(double) == sizeof(uint64), double_has_wrong_size);
const uint64 kMul = 0xc6a4a7935bd1e995ULL;
uint64 a = (bit_cast<uint64>(num) + seed) * kMul;
a ^= (a >> 47);
a *= kMul;
a ^= (a >> 47);
a *= kMul;
return a;
}
#endif // UTIL_HASH_BUILTIN_TYPE_HASH_H_