/*++ Copyright (c) 2006 Microsoft Corporation Module Name: hash.h Abstract: Basic hash computation support. Author: Leonardo de Moura (leonardo) 2006-09-11. Revision History: --*/ #ifndef _HASH_H_ #define _HASH_H_ #include #ifndef _WINDOWS #ifndef __fallthrough #define __fallthrough #endif #endif #define mix(a,b,c) \ { \ a -= b; a -= c; a ^= (c>>13); \ b -= c; b -= a; b ^= (a<<8); \ c -= a; c -= b; c ^= (b>>13); \ a -= b; a -= c; a ^= (c>>12); \ b -= c; b -= a; b ^= (a<<16); \ c -= a; c -= b; c ^= (b>>5); \ a -= b; a -= c; a ^= (c>>3); \ b -= c; b -= a; b ^= (a<<10); \ c -= a; c -= b; c ^= (b>>15); \ } inline unsigned hash_u(unsigned a) { a = (a+0x7ed55d16) + (a<<12); a = (a^0xc761c23c) ^ (a>>19); a = (a+0x165667b1) + (a<<5); a = (a+0xd3a2646c) ^ (a<<9); a = (a+0xfd7046c5) + (a<<3); a = (a^0xb55a4f09) ^ (a>>16); return a; } inline unsigned hash_ull(unsigned long long a) { a = (~a) + (a << 18); a ^= (a >> 31); a += (a << 2) + (a << 4); a ^= (a >> 11); a += (a << 6); a ^= (a >> 22); return static_cast(a); } inline unsigned combine_hash(unsigned h1, unsigned h2) { h2 -= h1; h2 ^= (h1 << 8); h1 -= h2; h2 ^= (h1 << 16); h2 -= h1; h2 ^= (h1 << 10); return h2; } inline unsigned hash_u_u(unsigned a, unsigned b) { return combine_hash(hash_u(a), hash_u(b)); } unsigned string_hash(const char * str, unsigned len, unsigned init_value); template unsigned get_composite_hash(Composite app, unsigned n, GetKindHashProc const & khasher = GetKindHashProc(), GetChildHashProc const & chasher = GetChildHashProc()) { unsigned a, b, c; SASSERT(n > 0); unsigned kind_hash = khasher(app); a = b = 0x9e3779b9; c = 11; switch (n) { case 1: a += kind_hash; b = chasher(app, 0); mix(a, b, c); return c; case 2: a += kind_hash; b += chasher(app, 0); c += chasher(app, 1); mix(a, b, c); return c; case 3: a += chasher(app, 0); b += chasher(app, 1); c += chasher(app, 2); mix(a, b, c); a += kind_hash; mix(a, b, c); return c; default: while (n >= 3) { n--; a += chasher(app, n); n--; b += chasher(app, n); n--; c += chasher(app, n); mix(a, b, c); } a += kind_hash; switch (n) { case 2: b += chasher(app, 1); __fallthrough; case 1: c += chasher(app, 0); } mix(a, b, c); return c; } } template struct default_kind_hash_proc { unsigned operator()(Composite const & c) const { return 17; } }; struct int_hash { typedef int data; unsigned operator()(int x) const { return static_cast(x); } }; struct unsigned_hash { typedef unsigned data; unsigned operator()(unsigned x) const { return x; } }; struct size_t_hash { typedef size_t data; unsigned operator()(size_t x) const { return static_cast(x); } }; struct bool_hash { typedef bool data; unsigned operator()(bool x) const { return static_cast(x); } }; template struct obj_hash { typedef T data; unsigned operator()(const T & e) const { return e.hash(); } }; template struct obj_ptr_hash { typedef T * data; unsigned operator()(T * a) const { return a->hash(); } }; template struct obj_ptr_pair_hash { typedef std::pair data; unsigned operator()(data const & d) const { return combine_hash(d.first->hash(), d.second->hash()); } }; template struct triple { T1 first; T2 second; T3 third; triple(): first(T1()), second(T2()), third(T3()) {} triple(T1 f, T2 s, T3 t): first(f), second(s), third(t) {} bool operator==(triple const& other) const { return first == other.first && second == other.second && third == other.third; } }; template struct triple_hash : private Hash1 { Hash2 m_hash2; Hash3 m_hash3; typedef triple data; triple_hash(Hash1 const & h1 = Hash1(), Hash2 const & h2 = Hash2(), Hash3 const & h3 = Hash3()): Hash1(h1), m_hash2(h2), m_hash3(h3) { } unsigned operator()(std::pair const & p) const { return combine_hash(combine_hash(Hash1::operator()(p.first), m_hash2.operator()(p.second)), m_hash3.operator()(p.third)); } }; template struct obj_ptr_triple_hash { typedef triple data; unsigned operator()(data const & d) const { return combine_hash(combine_hash(d.first->hash(), d.second->hash()), d.third->hash()); } }; template struct pair_hash : private Hash1 { Hash2 m_hash2; typedef std::pair data; pair_hash(Hash1 const & h1 = Hash1(), Hash2 const & h2 = Hash2()): Hash1(h1), m_hash2(h2) { } unsigned operator()(std::pair const & p) const { return combine_hash(Hash1::operator()(p.first), m_hash2.operator()(p.second)); } }; template inline unsigned get_ptr_hash(T * ptr) { return static_cast(reinterpret_cast(ptr)); } template struct ptr_hash { typedef T * data; unsigned operator()(T * ptr) const { return get_ptr_hash(ptr); } }; inline unsigned mk_mix(unsigned a, unsigned b, unsigned c) { mix(a, b, c); return c; } #endif /* _HASH_H_ */