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:
parent
e90b66af58
commit
f456de5fac
@ -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
165
core/ds.c
@ -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;
|
||||
}
|
||||
|
||||
|
14
core/gc.c
14
core/gc.c
@ -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) {
|
||||
|
72
core/ids.c
72
core/ids.c
@ -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;
|
||||
|
||||
}
|
||||
|
||||
/****/
|
||||
|
17
core/stl.c
17
core/stl.c
@ -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;
|
||||
|
@ -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++]];
|
||||
|
@ -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 */
|
||||
|
Loading…
Reference in New Issue
Block a user