Improve calculation of hash values.

This commit is contained in:
Jesse D. McDonald 2011-12-08 17:14:04 -06:00
parent d473552806
commit 173c117d86
1 changed files with 51 additions and 51 deletions

102
gc.c
View File

@ -484,9 +484,9 @@ builtin_fn_t *get_builtin_fn(value_t v)
return _get_builtin_fn(v); return _get_builtin_fn(v);
} }
static size_t dbj2_hash(uint8_t *bytes, size_t size) static fixnum_t dbj2_hash(uint8_t *bytes, size_t size)
{ {
size_t hash = 5381; fixnum_t hash = 5381;
for (size_t i = 0; i < size; ++i) for (size_t i = 0; i < size; ++i)
{ {
@ -498,10 +498,29 @@ static size_t dbj2_hash(uint8_t *bytes, size_t size)
static value_t _get_hash_value(value_t v, seen_value_t *seen) static value_t _get_hash_value(value_t v, seen_value_t *seen)
{ {
seen_value_t new_seen = { v, seen }; if (is_float(v))
if (is_object(v) && !(is_float(v) || is_byte_string(v) || is_builtin_fn(v)))
{ {
double d = _get_float(v);
return fixnum_value(dbj2_hash((uint8_t*)&d, sizeof d));
}
else if (is_byte_string(v))
{
byte_string_t *str = _get_byte_string(v);
return fixnum_value(dbj2_hash(str->bytes, str->size));
}
else if (is_builtin_fn(v))
{
return fixnum_value((uintptr_t)_get_builtin_fn(v) >> 2);
}
else if (!is_object(v))
{
/* Non-objects compare by value */
return fixnum_value(v + (v >> 2));
}
else
{
seen_value_t new_seen = { v, seen };
for (seen_value_t *sv = seen; sv; sv = sv->prev) for (seen_value_t *sv = seen; sv; sv = sv->prev)
{ {
if (v == sv->value) if (v == sv->value)
@ -509,53 +528,34 @@ static value_t _get_hash_value(value_t v, seen_value_t *seen)
return 0; return 0;
} }
} }
}
if (!is_object(v)) if (is_pair(v))
{ {
/* Non-objects compare by value */ /* Lists and trees compare by value, not reference. */
return fixnum_value(v ^ (v >> 2)); value_t seed = fixnum_value(0);
} seed = combine_hash_values(seed, _get_hash_value(_CAR(v), &new_seen));
else if (is_float(v)) seed = combine_hash_values(seed, _get_hash_value(_CDR(v), &new_seen));
{ return seed;
double d = _get_float(v); }
return fixnum_value(dbj2_hash((uint8_t*)&d, sizeof d)); else if (is_box(v) || is_weak_box(v))
} {
else if (is_builtin_fn(v)) /* Boxes compare by value, not by reference. */
{ return _get_hash_value(_get_box(v)->value, &new_seen);
return fixnum_value((uintptr_t)_get_builtin_fn(v) >> 2); }
} else if (is_vector(v))
else if (is_pair(v)) {
{ /* Vectors compare by reference. */
/* Lists and trees compare by value, not reference. */ return _get_vector(v)->hash;
value_t seed = fixnum_value(0); }
seed = combine_hash_values(seed, _get_hash_value(_CAR(v), &new_seen)); else if (is_struct(v))
seed = combine_hash_values(seed, _get_hash_value(_CDR(v), &new_seen)); {
return seed; /* Structures compare by reference. */
} return _get_struct(v)->hash;
else if (is_box(v) || is_weak_box(v)) }
{ else /* unknown object type */
/* Boxes compare by value, not by reference. */ {
return _get_hash_value(_get_box(v)->value, &new_seen); return _get_hash_value(_get_object(v)->tag, &new_seen);
} }
else if (is_byte_string(v))
{
byte_string_t *str = _get_byte_string(v);
return fixnum_value(dbj2_hash(str->bytes, str->size));
}
else if (is_vector(v))
{
/* Vectors compare by reference. */
return _get_vector(v)->hash;
}
else if (is_struct(v))
{
/* Structures compare by reference. */
return _get_struct(v)->hash;
}
else /* unknown object type */
{
return _get_hash_value(_get_object(v)->tag, &new_seen);
} }
} }