Improve hash for hierarchical names.

Signed-off-by: Leonardo de Moura <leonardo@microsoft.com>
This commit is contained in:
Leonardo de Moura 2013-07-24 11:00:29 -07:00
parent 59592ed36b
commit ed3df178ac
5 changed files with 35 additions and 20 deletions

View file

@ -26,10 +26,10 @@ struct sexpr_cell {
struct sexpr_string : public sexpr_cell {
std::string m_value;
sexpr_string(char const * v):
sexpr_cell(sexpr_kind::STRING, hash(v, strlen(v), 13)),
sexpr_cell(sexpr_kind::STRING, hash_str(strlen(v), v, 13)),
m_value(v) {}
sexpr_string(std::string const & v):
sexpr_cell(sexpr_kind::STRING, hash(v.c_str(), v.size(), 13)),
sexpr_cell(sexpr_kind::STRING, hash_str(v.size(), v.c_str(), 13)),
m_value(v) {}
};

View file

@ -44,8 +44,26 @@ static void tst1() {
lean_assert(name(2) > name(name(1), "foo"));
}
static name mk_big_name(unsigned num) {
name n("foo");
for (unsigned i = 0; i < num; i++) {
n = name(n, "bla");
}
return n;
}
static void tst2() {
name n1 = mk_big_name(2000);
name n2 = mk_big_name(2000);
lean_assert(n1.hash() == n2.hash());
for (unsigned i = 0; i < 10000; i++)
n1.hash();
std::cout << "n1.hash(): " << n1.hash() << "\n";
}
int main() {
continue_on_violation(true);
tst1();
tst2();
return has_violations() ? 1 : 0;
}

View file

@ -20,7 +20,7 @@ void mix(unsigned & a, unsigned & b, unsigned & c) {
// Bob Jenkin's hash function.
// http://burtleburtle.net/bob/hash/doobs.html
unsigned hash(char const * str, unsigned length, unsigned init_value) {
unsigned hash_str(unsigned length, char const * str, unsigned init_value) {
register unsigned a, b, c, len;
/* Set up the internal state */

View file

@ -11,7 +11,7 @@ namespace lean {
void mix(unsigned & a, unsigned & b, unsigned & c);
unsigned hash(char const * str, unsigned length, unsigned init_value);
unsigned hash_str(unsigned len, char const * str, unsigned init_value);
inline unsigned hash(unsigned h1, unsigned h2) {
h2 -= h1; h2 ^= (h1 << 8);

View file

@ -20,6 +20,7 @@ constexpr char const * anonymous_str = "[anonymous]";
struct name::imp {
MK_LEAN_RC()
bool m_is_string;
unsigned m_hash;
imp * m_prefix;
union {
char * m_str;
@ -41,7 +42,7 @@ struct name::imp {
}
}
imp(bool s, imp * p):m_rc(1), m_is_string(s), m_prefix(p) { if (p) p->inc_ref(); }
imp(bool s, imp * p):m_rc(1), m_is_string(s), m_hash(0), m_prefix(p) { if (p) p->inc_ref(); }
static void display_core(std::ostream & out, char const * sep, imp * p) {
lean_assert(p != nullptr);
@ -89,11 +90,19 @@ name::name(name const & prefix, char const * name) {
m_imp = new (mem) imp(true, prefix.m_imp);
memcpy(mem + sizeof(imp), name, sz + 1);
m_imp->m_str = mem + sizeof(imp);
if (m_imp->m_prefix)
m_imp->m_hash = hash_str(sz, name, m_imp->m_prefix->m_hash);
else
m_imp->m_hash = hash_str(sz, name, 0);
}
name::name(name const & prefix, unsigned k) {
m_imp = new imp(false, prefix.m_imp);
m_imp->m_k = k;
if (m_imp->m_prefix)
m_imp->m_hash = ::lean::hash(m_imp->m_prefix->m_hash, k);
else
m_imp->m_hash = k;
}
name::name(char const * n):name(name(), n) {
@ -158,6 +167,8 @@ bool operator==(name const & a, name const & b) {
return true;
if ((i1 == nullptr) != (i2 == nullptr))
return false;
if (i1->m_hash != i2->m_hash)
return false;
lean_assert(i1 != nullptr);
lean_assert(i2 != nullptr);
if (i1->m_is_string != i2->m_is_string)
@ -251,21 +262,7 @@ size_t name::size(char const * sep) const {
}
unsigned name::hash() const {
if (m_imp == nullptr)
return 17;
else {
unsigned h = 13;
imp const * i = m_imp;
do {
if (i->m_is_string)
h = ::lean::hash(i->m_str, strlen(i->m_str), h);
else
h = ::lean::hash(h, i->m_k);
i = i->m_prefix;
}
while (i != nullptr);
return h;
}
return m_imp->m_hash;
}
std::ostream & operator<<(std::ostream & out, name const & n) {