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);
}
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)
{
@ -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)
{
seen_value_t new_seen = { v, seen };
if (is_object(v) && !(is_float(v) || is_byte_string(v) || is_builtin_fn(v)))
if (is_float(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)
{
if (v == sv->value)
@ -509,53 +528,34 @@ static value_t _get_hash_value(value_t v, seen_value_t *seen)
return 0;
}
}
}
if (!is_object(v))
{
/* Non-objects compare by value */
return fixnum_value(v ^ (v >> 2));
}
else if (is_float(v))
{
double d = _get_float(v);
return fixnum_value(dbj2_hash((uint8_t*)&d, sizeof d));
}
else if (is_builtin_fn(v))
{
return fixnum_value((uintptr_t)_get_builtin_fn(v) >> 2);
}
else if (is_pair(v))
{
/* Lists and trees compare by value, not reference. */
value_t seed = fixnum_value(0);
seed = combine_hash_values(seed, _get_hash_value(_CAR(v), &new_seen));
seed = combine_hash_values(seed, _get_hash_value(_CDR(v), &new_seen));
return seed;
}
else if (is_box(v) || is_weak_box(v))
{
/* Boxes compare by value, not by reference. */
return _get_hash_value(_get_box(v)->value, &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);
if (is_pair(v))
{
/* Lists and trees compare by value, not reference. */
value_t seed = fixnum_value(0);
seed = combine_hash_values(seed, _get_hash_value(_CAR(v), &new_seen));
seed = combine_hash_values(seed, _get_hash_value(_CDR(v), &new_seen));
return seed;
}
else if (is_box(v) || is_weak_box(v))
{
/* Boxes compare by value, not by reference. */
return _get_hash_value(_get_box(v)->value, &new_seen);
}
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);
}
}
}