diff --git a/gc.c b/gc.c index 99de0aa..df58cfb 100644 --- a/gc.c +++ b/gc.c @@ -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); + } } }