Add a primitive operation to calculate a 30-bit hash from any value.
Pairs, boxes, and strings are hashed by values; vectors and structures are "hashed" by reference. Takes into account the possibility of cycles. This is a prelude to implementing hash-tables.
This commit is contained in:
parent
5d8a302225
commit
96b3bded17
|
|
@ -37,6 +37,7 @@ unary-expr: up to 255, 1 out, 1 in
|
||||||
29 (set! out (byte-string-size in))
|
29 (set! out (byte-string-size in))
|
||||||
2a (set! out (struct-nslots in))
|
2a (set! out (struct-nslots in))
|
||||||
2b (set! out (struct-type in))
|
2b (set! out (struct-type in))
|
||||||
|
2c (set! out (hash-value in))
|
||||||
|
|
||||||
; ISO C floating-point
|
; ISO C floating-point
|
||||||
30 (set! out (acos in))
|
30 (set! out (acos in))
|
||||||
|
|
|
||||||
114
gc.c
114
gc.c
|
|
@ -33,6 +33,12 @@ gc_stats_t gc_stats;
|
||||||
/* The default of 128 KB/block should require a 2 KB bitmap. */
|
/* The default of 128 KB/block should require a 2 KB bitmap. */
|
||||||
#define GC_DIRTY_BLOCK_SIZE (128UL << 10)
|
#define GC_DIRTY_BLOCK_SIZE (128UL << 10)
|
||||||
|
|
||||||
|
typedef struct seen_value
|
||||||
|
{
|
||||||
|
value_t value;
|
||||||
|
struct seen_value *prev;
|
||||||
|
} seen_value_t;
|
||||||
|
|
||||||
/****************************************************************************/
|
/****************************************************************************/
|
||||||
|
|
||||||
static value_t gc_weak_box_list;
|
static value_t gc_weak_box_list;
|
||||||
|
|
@ -69,6 +75,13 @@ void unregister_gc_root(gc_root_t *root)
|
||||||
|
|
||||||
/****************************************************************************/
|
/****************************************************************************/
|
||||||
|
|
||||||
|
static value_t make_hash_value(void)
|
||||||
|
{
|
||||||
|
static fixnum_t hash_seed = 0x67f76bc8;
|
||||||
|
hash_seed = (33 * hash_seed) ^ (fixnum_t)clock();
|
||||||
|
return fixnum_value(hash_seed);
|
||||||
|
}
|
||||||
|
|
||||||
bool get_boolean(value_t v)
|
bool get_boolean(value_t v)
|
||||||
{
|
{
|
||||||
release_assert(is_boolean(v));
|
release_assert(is_boolean(v));
|
||||||
|
|
@ -149,6 +162,7 @@ value_t make_vector(size_t nelem, value_t initial_value)
|
||||||
vec = (vector_t*)gc_alloc(VECTOR_BYTES(nelem));
|
vec = (vector_t*)gc_alloc(VECTOR_BYTES(nelem));
|
||||||
vec->tag = TYPE_TAG_VECTOR;
|
vec->tag = TYPE_TAG_VECTOR;
|
||||||
vec->size = nelem;
|
vec->size = nelem;
|
||||||
|
vec->hash = make_hash_value();
|
||||||
|
|
||||||
for (int i = 0; i < nelem; ++i)
|
for (int i = 0; i < nelem; ++i)
|
||||||
vec->elements[i] = iv_root.value;
|
vec->elements[i] = iv_root.value;
|
||||||
|
|
@ -227,6 +241,7 @@ value_t make_struct(value_t type, size_t nslots)
|
||||||
s->tag = TYPE_TAG_STRUCT;
|
s->tag = TYPE_TAG_STRUCT;
|
||||||
s->type = type_root.value;
|
s->type = type_root.value;
|
||||||
s->nslots = nslots;
|
s->nslots = nslots;
|
||||||
|
s->hash = make_hash_value();
|
||||||
|
|
||||||
for (int i = 0; i < nslots; ++i)
|
for (int i = 0; i < nslots; ++i)
|
||||||
s->slots[i] = UNDEFINED;
|
s->slots[i] = UNDEFINED;
|
||||||
|
|
@ -343,6 +358,93 @@ 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)
|
||||||
|
{
|
||||||
|
size_t hash = 5381;
|
||||||
|
|
||||||
|
for (size_t i = 0; i < size; ++i)
|
||||||
|
{
|
||||||
|
hash = (33 * hash) ^ (size_t)bytes[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
return hash;
|
||||||
|
}
|
||||||
|
|
||||||
|
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)))
|
||||||
|
{
|
||||||
|
for (seen_value_t *sv = seen; sv; sv = sv->prev)
|
||||||
|
{
|
||||||
|
if (v == sv->value)
|
||||||
|
{
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
value_t get_hash_value(value_t v)
|
||||||
|
{
|
||||||
|
return _get_hash_value(v, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
value_t combine_hash_values(value_t f1, value_t f2)
|
||||||
|
{
|
||||||
|
fixnum_t h1 = _get_fixnum(f1);
|
||||||
|
fixnum_t h2 = _get_fixnum(f2);
|
||||||
|
return fixnum_value(h1 ^ (h2 + 0x9e3779b9 + (h1 << 6) + (h1 >> 2)));
|
||||||
|
}
|
||||||
|
|
||||||
/*************************** Common Collector Code **************************/
|
/*************************** Common Collector Code **************************/
|
||||||
|
|
||||||
static bool gc_enabled;
|
static bool gc_enabled;
|
||||||
|
|
@ -796,6 +898,9 @@ static size_t transfer_vector(vector_t *vec)
|
||||||
{
|
{
|
||||||
assert(vec->tag == TYPE_TAG_VECTOR);
|
assert(vec->tag == TYPE_TAG_VECTOR);
|
||||||
|
|
||||||
|
/* Should be fixnum, but just in case... */
|
||||||
|
transfer_object(&vec->hash);
|
||||||
|
|
||||||
for (size_t i = 0; i < vec->size; ++i)
|
for (size_t i = 0; i < vec->size; ++i)
|
||||||
transfer_object(&vec->elements[i]);
|
transfer_object(&vec->elements[i]);
|
||||||
|
|
||||||
|
|
@ -808,6 +913,9 @@ static size_t transfer_struct(struct_t *s)
|
||||||
|
|
||||||
transfer_object(&s->type);
|
transfer_object(&s->type);
|
||||||
|
|
||||||
|
/* Should be fixnum, but just in case... */
|
||||||
|
transfer_object(&s->hash);
|
||||||
|
|
||||||
for (size_t i = 0; i < s->nslots; ++i)
|
for (size_t i = 0; i < s->nslots; ++i)
|
||||||
transfer_object(&s->slots[i]);
|
transfer_object(&s->slots[i]);
|
||||||
|
|
||||||
|
|
@ -1282,12 +1390,6 @@ void _release_assert(bool expr, const char *str, const char *file, int line)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
typedef struct seen_value
|
|
||||||
{
|
|
||||||
value_t value;
|
|
||||||
struct seen_value *prev;
|
|
||||||
} seen_value_t;
|
|
||||||
|
|
||||||
static void _fprint_value(FILE *f, value_t v, seen_value_t *seen)
|
static void _fprint_value(FILE *f, value_t v, seen_value_t *seen)
|
||||||
{
|
{
|
||||||
seen_value_t new_seen = { v, seen };
|
seen_value_t new_seen = { v, seen };
|
||||||
|
|
|
||||||
5
gc.h
5
gc.h
|
|
@ -109,6 +109,7 @@ typedef struct vector
|
||||||
{
|
{
|
||||||
value_t tag; /* TYPE_TAG_VECTOR */
|
value_t tag; /* TYPE_TAG_VECTOR */
|
||||||
size_t size;
|
size_t size;
|
||||||
|
value_t hash;
|
||||||
value_t elements[0];
|
value_t elements[0];
|
||||||
} vector_t;
|
} vector_t;
|
||||||
|
|
||||||
|
|
@ -125,6 +126,7 @@ typedef struct structure
|
||||||
value_t tag; /* TYPE_TAG_STRUCT */
|
value_t tag; /* TYPE_TAG_STRUCT */
|
||||||
value_t type;
|
value_t type;
|
||||||
size_t nslots;
|
size_t nslots;
|
||||||
|
value_t hash;
|
||||||
value_t slots[0];
|
value_t slots[0];
|
||||||
} struct_t;
|
} struct_t;
|
||||||
|
|
||||||
|
|
@ -208,6 +210,9 @@ char *value_to_string(value_t v);
|
||||||
/* Like strcmp(), but for byte strings. */
|
/* Like strcmp(), but for byte strings. */
|
||||||
int byte_strcmp(value_t s1, value_t s2);
|
int byte_strcmp(value_t s1, value_t s2);
|
||||||
|
|
||||||
|
value_t get_hash_value(value_t val);
|
||||||
|
value_t combine_hash_values(value_t h1, value_t h2);
|
||||||
|
|
||||||
value_t make_struct(value_t type, size_t nslots);
|
value_t make_struct(value_t type, size_t nslots);
|
||||||
struct_t *get_struct(value_t v);
|
struct_t *get_struct(value_t v);
|
||||||
|
|
||||||
|
|
|
||||||
1
interp.c
1
interp.c
|
|
@ -417,6 +417,7 @@ static value_t eval_unary_expression(interp_state_t *state, uint8_t subcode, uin
|
||||||
case 0x29: return fixnum_value(get_byte_string(ST1)->size);
|
case 0x29: return fixnum_value(get_byte_string(ST1)->size);
|
||||||
case 0x2a: return fixnum_value(get_struct(ST1)->nslots);
|
case 0x2a: return fixnum_value(get_struct(ST1)->nslots);
|
||||||
case 0x2b: return get_struct(ST1)->type;
|
case 0x2b: return get_struct(ST1)->type;
|
||||||
|
case 0x2c: return get_hash_value(ST1);
|
||||||
case 0x30: return make_float(acos(get_float(ST1)));
|
case 0x30: return make_float(acos(get_float(ST1)));
|
||||||
case 0x31: return make_float(asin(get_float(ST1)));
|
case 0x31: return make_float(asin(get_float(ST1)));
|
||||||
case 0x32: return make_float(atan(get_float(ST1)));
|
case 0x32: return make_float(atan(get_float(ST1)));
|
||||||
|
|
|
||||||
|
|
@ -44,6 +44,7 @@
|
||||||
(%byte-string-size #x29 byte-string-size)
|
(%byte-string-size #x29 byte-string-size)
|
||||||
(%struct-nslots #x2a struct-nslots)
|
(%struct-nslots #x2a struct-nslots)
|
||||||
(%struct-type #x2b struct-type)
|
(%struct-type #x2b struct-type)
|
||||||
|
(%hash-value #x2c hash-value)
|
||||||
(%acos #x30 acos)
|
(%acos #x30 acos)
|
||||||
(%asin #x31 asin)
|
(%asin #x31 asin)
|
||||||
(%atan #x32 atan)
|
(%atan #x32 atan)
|
||||||
|
|
|
||||||
|
|
@ -25,6 +25,7 @@
|
||||||
(define (byte-string-size x) (byte-string-size x))
|
(define (byte-string-size x) (byte-string-size x))
|
||||||
(define (struct-nslots x) (struct-nslots x))
|
(define (struct-nslots x) (struct-nslots x))
|
||||||
(define (struct-type x) (struct-type x))
|
(define (struct-type x) (struct-type x))
|
||||||
|
(define (hash-value x) (hash-value x))
|
||||||
(define (acos x) (acos x))
|
(define (acos x) (acos x))
|
||||||
(define (asin x) (asin x))
|
(define (asin x) (asin x))
|
||||||
(define (atan x) (atan x))
|
(define (atan x) (atan x))
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue