1
0
mirror of https://github.com/janet-lang/janet synced 2024-12-25 07:50:27 +00:00

Change object implementaion to use open hashing. Currently

using simple linear probing.
This commit is contained in:
Calvin Rose 2017-04-16 09:39:41 -04:00
parent e90b66af58
commit f456de5fac
7 changed files with 158 additions and 153 deletions

View File

@ -918,21 +918,18 @@ static Slot compile_object(GstCompiler *c, FormOptions opts, GstObject *obj) {
GstScope *scope = c->tail;
FormOptions subOpts = form_options_default();
GstBuffer *buffer = c->buffer;
GstBucket *bucket;
Slot ret;
SlotTracker tracker;
uint32_t i, cap;
cap = obj->capacity;
ret = compiler_get_target(c, opts);
tracker_init(c, &tracker);
for (i = 0; i < cap; ++i) {
bucket = obj->buckets[i];
while (bucket != NULL) {
Slot slot = compile_value(c, subOpts, bucket->key);
for (i = 0; i < cap; i += 2) {
if (obj->data[i].type != GST_NIL) {
Slot slot = compile_value(c, subOpts, obj->data[i]);
compiler_tracker_push(c, &tracker, compiler_realize_slot(c, slot));
slot = compile_value(c, subOpts, bucket->value);
slot = compile_value(c, subOpts, obj->data[i + 1]);
compiler_tracker_push(c, &tracker, compiler_realize_slot(c, slot));
bucket = bucket->next;
}
}
compiler_tracker_free(c, scope, &tracker);
@ -1034,15 +1031,10 @@ void gst_compiler_global(GstCompiler *c, const char *name, GstValue x) {
/* Add many global variables */
void gst_compiler_globals(GstCompiler *c, GstObject *env) {
uint32_t i;
GstBucket *bucket;
for (i = 0; i < env->capacity; ++i) {
bucket = env->buckets[i];
while (bucket) {
if (bucket->key.type == GST_STRING) {
compiler_declare_symbol(c, c->tail, bucket->key);
gst_array_push(c->vm, c->env, bucket->value);
}
bucket = bucket->next;
for (i = 0; i < env->capacity; i += 2) {
if (env->data[i].type == GST_STRING) {
compiler_declare_symbol(c, c->tail, env->data[i]);
gst_array_push(c->vm, c->env, env->data[i + 1]);
}
}
}

165
core/ds.c
View File

@ -153,50 +153,60 @@ void *gst_userdata(Gst *vm, uint32_t size, GstObject *meta) {
/* Create a new dictionary */
GstObject* gst_object(Gst *vm, uint32_t capacity) {
GstObject *o = gst_alloc(vm, sizeof(GstObject));
GstBucket **buckets = gst_zalloc(vm, capacity * sizeof(GstBucket *));
o->buckets = buckets;
GstValue *data = gst_zalloc(vm, capacity * sizeof(GstValue));
o->data = data;
o->capacity = capacity;
o->count = 0;
o->parent = NULL;
o->deleted = 0;
return o;
}
/* Find the bucket that contains the given key. Will also return
* bucket where key should go if not in object. */
static GstValue *gst_object_find(GstObject *o, GstValue key) {
uint32_t index = (gst_hash(key) % (o->capacity / 2)) * 2;
uint32_t i, j;
uint32_t start[2], end[2];
start[0] = index; end[0] = o->capacity;
start[1] = 0; end[1] = index;
for (j = 0; j < 2; ++j)
for (i = start[j]; i < end[j]; i += 2) {
if (o->data[i].type == GST_NIL) {
if (o->data[i + 1].type == GST_NIL) {
/* Empty */
return o->data + i;
}
} else if (gst_equals(o->data[i], key)) {
return o->data + i;
}
}
return NULL;
}
/* Resize the dictionary table. */
static void gst_object_rehash(Gst *vm, GstObject *o, uint32_t size) {
GstBucket **newBuckets = gst_zalloc(vm, size * sizeof(GstBucket *));
uint32_t i, count;
for (i = 0, count = o->capacity; i < count; ++i) {
GstBucket *bucket = o->buckets[i];
while (bucket) {
uint32_t index;
GstBucket *next = bucket->next;
index = gst_hash(bucket->key) % size;
bucket->next = newBuckets[index];
newBuckets[index] = bucket;
bucket = next;
GstValue *olddata = o->data;
GstValue *newdata = gst_zalloc(vm, size * sizeof(GstValue));
uint32_t i, oldcapacity;
oldcapacity = o->capacity;
o->data = newdata;
o->capacity = size;
o->deleted = 0;
for (i = 0; i < oldcapacity; i += 2) {
if (olddata[i].type != GST_NIL) {
GstValue *bucket = gst_object_find(o, olddata[i]);
bucket[0] = olddata[i];
bucket[1] = olddata[i + 1];
}
}
o->buckets = newBuckets;
o->capacity = size;
}
/* Find the bucket that contains the given key */
static GstBucket *gst_object_find(GstObject *o, GstValue key) {
uint32_t index = gst_hash(key) % o->capacity;
GstBucket *bucket = o->buckets[index];
while (bucket) {
if (gst_equals(bucket->key, key))
return bucket;
bucket = bucket->next;
}
return (GstBucket *)0;
}
/* Get a value out of the object */
GstValue gst_object_get(GstObject *o, GstValue key) {
GstBucket *bucket = gst_object_find(o, key);
if (bucket) {
return bucket->value;
GstValue *bucket = gst_object_find(o, key);
if (bucket && bucket[0].type != GST_NIL) {
return bucket[1];
} else {
GstValue nil;
nil.type = GST_NIL;
@ -205,75 +215,60 @@ GstValue gst_object_get(GstObject *o, GstValue key) {
}
/* Remove an entry from the dictionary */
GstValue gst_object_remove(Gst * vm, GstObject *o, GstValue key) {
GstBucket *bucket, *previous;
uint32_t index = gst_hash(key) % o->capacity;
bucket = o->buckets[index];
previous = (GstBucket *)0;
while (bucket) {
if (gst_equals(bucket->key, key)) {
if (previous) {
previous->next = bucket->next;
} else {
o->buckets[index] = bucket->next;
}
if (o->count < o->capacity / 4) {
gst_object_rehash(vm, o, o->capacity / 2);
}
--o->count;
return bucket->value;
}
previous = bucket;
bucket = bucket->next;
}
/* Return nil if we found nothing */
{
GstValue gst_object_remove(GstObject *o, GstValue key) {
GstValue *bucket = gst_object_find(o, key);
if (bucket && bucket[0].type != GST_NIL) {
GstValue ret = bucket[1];
o->count--;
o->deleted++;
bucket[0].type = GST_NIL;
bucket[1].type = GST_BOOLEAN;
return ret;
} else {
GstValue nil;
nil.type = GST_NIL;
return nil;
}
}
/* Put a value into the dictionary. */
/* Put a value into the object */
void gst_object_put(Gst *vm, GstObject *o, GstValue key, GstValue value) {
GstBucket *bucket, *previous;
uint32_t index = gst_hash(key) % o->capacity;
if (key.type == GST_NIL) return;
/* Do a removal if value is nil */
if (value.type == GST_NIL) {
bucket = o->buckets[index];
previous = (GstBucket *)0;
while (bucket) {
if (gst_equals(bucket->key, key)) {
if (previous) {
previous->next = bucket->next;
} else {
o->buckets[index] = bucket->next;
}
if (o->count < o->capacity / 4) {
gst_object_rehash(vm, o, o->capacity / 2);
}
--o->count;
return;
}
previous = bucket;
bucket = bucket->next;
}
gst_object_remove(o, key);
} else {
bucket = gst_object_find(o, key);
if (bucket) {
bucket->value = value;
GstValue *bucket = gst_object_find(o, key);
if (bucket && bucket[0].type != GST_NIL) {
bucket[1] = value;
} else {
if (o->count >= 2 * o->capacity) {
gst_object_rehash(vm, o, 2 * o->capacity);
if (!bucket || 4 * (o->count + o->deleted) >= o->capacity) {
gst_object_rehash(vm, o, 4 * o->count + 6);
}
bucket = gst_alloc(vm, sizeof(GstBucket));
bucket->next = o->buckets[index];
bucket->value = value;
bucket->key = key;
o->buckets[index] = bucket;
bucket = gst_object_find(o, key);
bucket[0] = key;
bucket[1] = value;
++o->count;
}
}
}
/* Find next key in an object. Returns nil if no next key. */
GstValue gst_object_next(GstObject *o, GstValue key) {
GstValue ret;
GstValue *bucket;
if (key.type == GST_NIL)
bucket = o->data - 2;
else
bucket = gst_object_find(o, key);
if (bucket && bucket[0].type != GST_NIL) {
GstValue *nextbucket, *end;
end = o->data + o->capacity;
for (nextbucket = bucket + 2; nextbucket < end; nextbucket += 2) {
if (nextbucket[0].type != GST_NIL)
return nextbucket[0];
}
}
ret.type = GST_NIL;
return ret;
}

View File

@ -142,16 +142,12 @@ void gst_mark(Gst *vm, GstValueUnion x, GstType type) {
case GST_OBJECT:
if (gc_header(x.object)->color != vm->black) {
uint32_t i;
GstBucket *bucket;
gc_header(x.object)->color = vm->black;
gc_header(x.object->buckets)->color = vm->black;
for (i = 0; i < x.object->capacity; ++i) {
bucket = x.object->buckets[i];
while (bucket) {
gc_header(bucket)->color = vm->black;
gst_mark_value(vm, bucket->key);
gst_mark_value(vm, bucket->value);
bucket = bucket->next;
gc_header(x.object->data)->color = vm->black;
for (i = 0; i < x.object->capacity; i += 2) {
if (x.object->data[i].type != GST_NIL) {
gst_mark_value(vm, x.object->data[i]);
gst_mark_value(vm, x.object->data[i + 1]);
}
}
if (x.object->parent != NULL) {

View File

@ -205,32 +205,40 @@ void gst_cache_remove_struct(Gst *vm, char *structmem) {
/* Begin creation of a struct */
GstValue *gst_struct_begin(Gst *vm, uint32_t count) {
char *data = gst_alloc(vm, sizeof(uint32_t) * 2 + 4 * count * sizeof(GstValue));
char *data = gst_zalloc(vm, sizeof(uint32_t) * 2 + 4 * count * sizeof(GstValue));
GstValue *st = (GstValue *) (data + 2 * sizeof(uint32_t));
gst_struct_length(st) = count;
return st;
}
/* Put a kv pair into a struct that has not yet been fully constructed. */
void gst_struct_put(GstValue *st, GstValue key, GstValue value) {
/* Find an item in a struct */
static const GstValue *gst_struct_find(const GstValue *st, GstValue key) {
uint32_t cap = gst_struct_capacity(st);
uint32_t index = (gst_hash(key) % (cap / 2)) * 2;
uint32_t i;
for (i = index; i < cap; i += 2) {
if (st[i + 1].type == GST_NIL) {
st[i] = key;
st[i + 1] = value;
return;
if (st[i].type == GST_NIL || gst_equals(st[i], key)) {
return st + i;
}
}
for (i = 0; i < index; i += 2) {
if (st[i + 1].type == GST_NIL) {
st[i] = key;
st[i + 1] = value;
return;
if (st[i].type == GST_NIL || gst_equals(st[i], key)) {
return st + i;
}
}
/* Should not get here if struct was initialized with proper size */
return NULL;
}
/* Put a kv pair into a struct that has not yet been fully constructed.
* Behavior is undefined if too many keys are added, or if a key is added
* twice. Nil keys and values are ignored. */
void gst_struct_put(GstValue *st, GstValue key, GstValue value) {
GstValue *bucket;
if (key.type == GST_NIL || value.type == GST_NIL) return;
bucket = (GstValue *) gst_struct_find(st, key);
if (!bucket) return;
bucket[0] = key;
bucket[1] = value;
}
/* Finish building a struct */
@ -246,27 +254,35 @@ const GstValue *gst_struct_end(Gst *vm, GstValue *st) {
/* Get an item from a struct */
GstValue gst_struct_get(const GstValue *st, GstValue key) {
GstValue *bucket = gst_struct_find(st, key);
if (!bucket || bucket[0].type == GST_NIL) {
GstValue ret;
ret.type = GST_NIL;
return ret;
} else {
return bucket[1];
}
}
/* Get the next key in a struct */
GstValue gst_struct_next(const GstValue *st, GstValue key) {
GstValue ret;
uint32_t cap = gst_struct_capacity(st);
uint32_t index = (gst_hash(key) % (cap / 2)) * 2;
uint32_t i;
for (i = index; i < cap; i += 2) {
if (st[i + 1].type == GST_NIL) {
goto notfound;
} else if (gst_equals(st[i], key)) {
return st[i + 1];
const GstValue *bucket;
if (key.type == GST_NIL)
bucket = st - 2;
else
bucket = gst_struct_find(st, key);
if (bucket && bucket[0].type != GST_NIL) {
const GstValue *nextbucket, *end;
end = st + gst_struct_capacity(st);
for (nextbucket = bucket + 2; nextbucket < end; nextbucket += 2) {
if (nextbucket[0].type != GST_NIL)
return nextbucket[0];
}
}
for (i = 0; i < index; i += 2) {
if (st[i + 1].type == GST_NIL) {
goto notfound;
} else if (gst_equals(st[i], key)) {
return st[i + 1];
}
}
notfound:
ret.type = GST_NIL;
return ret;
}
/****/

View File

@ -237,7 +237,7 @@ int gst_stl_object(Gst *vm) {
if (count % 2 != 0) {
gst_c_throwc(vm, "expected even number of arguments");
}
object = gst_object(vm, count / 2);
object = gst_object(vm, count * 2);
for (i = 0; i < count; i += 2) {
gst_object_put(vm, object, gst_arg(vm, i), gst_arg(vm, i + 1));
}
@ -255,7 +255,7 @@ int gst_stl_struct(Gst *vm) {
if (count % 2 != 0) {
gst_c_throwc(vm, "expected even number of arguments");
}
st = gst_struct_begin(vm, count / 2);
st = gst_struct_begin(vm, count * 2);
for (i = 0; i < count; i += 2) {
gst_struct_put(st, gst_arg(vm, i), gst_arg(vm, i + 1));
}
@ -340,6 +340,19 @@ int gst_stl_rawset(Gst *vm) {
}
}
/* Get next key in struct or object */
int gst_stl_next(Gst *vm) {
GstValue ds = gst_arg(vm, 0);
GstValue key = gst_arg(vm, 1);
if (ds.type == GST_OBJECT) {
gst_c_return(vm, gst_object_next(ds.data.object, key));
} else if (ds.type == GST_STRUCT) {
gst_c_return(vm, gst_struct_next(ds.data.st, key));
} else {
gst_c_throwc(vm, "expected object or struct");
}
}
/* Print values for inspection */
int gst_stl_print(Gst *vm) {
uint32_t j, count;

View File

@ -371,7 +371,7 @@ static int gst_continue_size(Gst *vm, uint32_t stackBase) {
{
uint32_t i = 3;
uint32_t kvs = pc[2];
GstObject *o = gst_object(vm, kvs + 2);
GstObject *o = gst_object(vm, 2 * kvs + 2);
kvs = kvs + 3;
while (i < kvs) {
v1 = stack[pc[i++]];

View File

@ -134,9 +134,6 @@ typedef struct GstFuncDef GstFuncDef;
typedef struct GstFuncEnv GstFuncEnv;
typedef union GstValueUnion GstValueUnion;
/* Definitely implementation details */
typedef struct GstBucket GstBucket;
/* API Types */
typedef struct GstModuleItem GstModuleItem;
@ -208,7 +205,8 @@ struct GstBuffer {
struct GstObject {
uint32_t count;
uint32_t capacity;
GstBucket **buckets;
uint32_t deleted;
GstValue *data;
GstObject *parent;
};
@ -240,13 +238,6 @@ struct GstFunction {
GstFunction *parent;
};
/* A hash table bucket in an object */
struct GstBucket {
GstValue key;
GstValue value;
GstBucket *next;
};
/* Contains information about userdata */
struct GstUserdataHeader {
uint32_t size;
@ -381,6 +372,7 @@ GstValue *gst_struct_begin(Gst *vm, uint32_t count);
void gst_struct_put(GstValue *st, GstValue key, GstValue value);
const GstValue *gst_struct_end(Gst *vm, GstValue *st);
GstValue gst_struct_get(const GstValue *st, GstValue key);
GstValue gst_struct_next(const GstValue *st, GstValue key);
/****/
/* Object functions */
@ -388,8 +380,9 @@ GstValue gst_struct_get(const GstValue *st, GstValue key);
GstObject *gst_object(Gst *vm, uint32_t capacity);
GstValue gst_object_get(GstObject *obj, GstValue key);
GstValue gst_object_remove(Gst *vm, GstObject *obj, GstValue key);
GstValue gst_object_remove(GstObject *obj, GstValue key);
void gst_object_put(Gst *vm, GstObject *obj, GstValue key, GstValue value);
GstValue gst_object_next(GstObject *o, GstValue key);
/****/
/* Threads */