Clean up string/object interactions in jv.

This commit is contained in:
Stephen Dolan committed 2013-12-08 22:49:28 +00:00
1 parent 74a14f5de7
commit a7dd3ab793
2 files changed
+58 -70

No files matched your search

+56 -69
View File
@@ -38,8 +38,10 @@ static int jvp_refcnt_unshared(jv_refcnt* c) {
* Simple values (true, false, null) * Simple values (true, false, null)
*/ */
#define KIND_MASK 0xf
jv_kind jv_get_kind(jv x) { jv_kind jv_get_kind(jv x) {
return x.kind; return x.kind_flags & KIND_MASK;
} }
const char* jv_kind_name(jv_kind k) { const char* jv_kind_name(jv_kind k) {
@@ -57,9 +59,9 @@ const char* jv_kind_name(jv_kind k) {
return "<unknown>"; return "<unknown>";
} }
static const jv JV_NULL = {JV_KIND_NULL, 0, 0, {0}}; static const jv JV_NULL = {JV_KIND_NULL, 0, 0, 0, {0}};
static const jv JV_FALSE = {JV_KIND_FALSE, 0, 0, {0}}; static const jv JV_FALSE = {JV_KIND_FALSE, 0, 0, 0, {0}};
static const jv JV_TRUE = {JV_KIND_TRUE, 0, 0, {0}}; static const jv JV_TRUE = {JV_KIND_TRUE, 0, 0, 0, {0}};
jv jv_true() { jv jv_true() {
return JV_TRUE; return JV_TRUE;
@@ -91,7 +93,7 @@ jv jv_invalid_with_msg(jv err) {
i->refcnt = JV_REFCNT_INIT; i->refcnt = JV_REFCNT_INIT;
i->errmsg = err; i->errmsg = err;
jv x = {JV_KIND_INVALID, 0, 0, {&i->refcnt}}; jv x = {JV_KIND_INVALID, 0, 0, 0, {&i->refcnt}};
return x; return x;
} }
@@ -127,7 +129,7 @@ static void jvp_invalid_free(jv x) {
jv jv_number(double x) { jv jv_number(double x) {
jv j; jv j;
j.kind = JV_KIND_NUMBER; j.kind_flags = JV_KIND_NUMBER;
j.size = 0; j.size = 0;
j.u.number = x; j.u.number = x;
return j; return j;
@@ -171,7 +173,7 @@ static jvp_array* jvp_array_alloc(unsigned size) {
} }
static jv jvp_array_new(unsigned size) { static jv jvp_array_new(unsigned size) {
jv r = {JV_KIND_ARRAY, 0, 0, {&jvp_array_alloc(size)->refcnt}}; jv r = {JV_KIND_ARRAY, 0, 0, 0, {&jvp_array_alloc(size)->refcnt}};
return r; return r;
} }
@@ -234,7 +236,7 @@ static jv* jvp_array_write(jv* a, int i) {
} }
new_array->length = new_length; new_array->length = new_length;
jvp_array_free(*a); jvp_array_free(*a);
jv new_jv = {JV_KIND_ARRAY, 0, new_length, {&new_array->refcnt}}; jv new_jv = {JV_KIND_ARRAY, 0, 0, new_length, {&new_array->refcnt}};
*a = new_jv; *a = new_jv;
return &new_array->elements[i]; return &new_array->elements[i];
} }
@@ -398,7 +400,7 @@ static jv jvp_string_copy_replace_bad(const char* data, uint32_t length) {
length = out - s->data; length = out - s->data;
s->data[length] = 0; s->data[length] = 0;
s->length_hashed = length << 1; s->length_hashed = length << 1;
jv r = {JV_KIND_STRING, 0, 0, {&s->refcnt}}; jv r = {JV_KIND_STRING, 0, 0, 0, {&s->refcnt}};
return r; return r;
} }
@@ -408,7 +410,7 @@ static jv jvp_string_new(const char* data, uint32_t length) {
s->length_hashed = length << 1; s->length_hashed = length << 1;
memcpy(s->data, data, length); memcpy(s->data, data, length);
s->data[length] = 0; s->data[length] = 0;
jv r = {JV_KIND_STRING, 0, 0, {&s->refcnt}}; jv r = {JV_KIND_STRING, 0, 0, 0, {&s->refcnt}};
return r; return r;
} }
@@ -416,27 +418,18 @@ static jv jvp_string_empty_new(uint32_t length) {
jvp_string* s = jvp_string_alloc(length); jvp_string* s = jvp_string_alloc(length);
s->length_hashed = 0; s->length_hashed = 0;
memset(s->data, 0, length); memset(s->data, 0, length);
jv r = {JV_KIND_STRING, 0, 0, {&s->refcnt}}; jv r = {JV_KIND_STRING, 0, 0, 0, {&s->refcnt}};
return r; return r;
} }
static void jvp_string_free_p(jvp_string* s) { static void jvp_string_free(jv js) {
jvp_string* s = jvp_string_ptr(js);
if (jvp_refcnt_dec(&s->refcnt)) { if (jvp_refcnt_dec(&s->refcnt)) {
jv_mem_free(s); jv_mem_free(s);
} }
} }
static void jvp_string_free(jv s) {
assert(jv_get_kind(s) == JV_KIND_STRING);
jvp_string_free_p(jvp_string_ptr(s));
}
static jvp_string* jvp_string_copy_p(jvp_string* s) {
jvp_refcnt_inc(&s->refcnt);
return s;
}
static uint32_t jvp_string_length(jvp_string* s) { static uint32_t jvp_string_length(jvp_string* s) {
return s->length_hashed >> 1; return s->length_hashed >> 1;
} }
@@ -468,7 +461,7 @@ static jv jvp_string_append(jv string, const char* data, uint32_t len) {
memcpy(news->data + currlen, data, len); memcpy(news->data + currlen, data, len);
news->data[currlen + len] = 0; news->data[currlen + len] = 0;
jvp_string_free(string); jvp_string_free(string);
jv r = {JV_KIND_STRING, 0, 0, {&news->refcnt}}; jv r = {JV_KIND_STRING, 0, 0, 0, {&news->refcnt}};
return r; return r;
} }
} }
@@ -479,7 +472,8 @@ static uint32_t rotl32 (uint32_t x, int8_t r){
return (x << r) | (x >> (32 - r)); return (x << r) | (x >> (32 - r));
} }
static uint32_t jvp_string_hash(jvp_string* str) { static uint32_t jvp_string_hash(jv jstr) {
jvp_string* str = jvp_string_ptr(jstr);
if (str->length_hashed & 1) if (str->length_hashed & 1)
return str->hash; return str->hash;
@@ -534,15 +528,6 @@ static uint32_t jvp_string_hash(jvp_string* str) {
return h1; return h1;
} }
static int jvp_string_equal_hashed(jvp_string* a, jvp_string* b) {
assert(a->length_hashed & 1);
assert(b->length_hashed & 1);
if (a == b) return 1;
if (a->hash != b->hash) return 0;
if (a->length_hashed != b->length_hashed) return 0;
return memcmp(a->data, b->data, jvp_string_length(a)) == 0;
}
static int jvp_string_equal(jv a, jv b) { static int jvp_string_equal(jv a, jv b) {
assert(jv_get_kind(a) == JV_KIND_STRING); assert(jv_get_kind(a) == JV_KIND_STRING);
assert(jv_get_kind(b) == JV_KIND_STRING); assert(jv_get_kind(b) == JV_KIND_STRING);
@@ -689,7 +674,7 @@ jv jv_string_implode(jv j) {
unsigned long jv_string_hash(jv j) { unsigned long jv_string_hash(jv j) {
assert(jv_get_kind(j) == JV_KIND_STRING); assert(jv_get_kind(j) == JV_KIND_STRING);
uint32_t hash = jvp_string_hash(jvp_string_ptr(j)); uint32_t hash = jvp_string_hash(j);
jv_free(j); jv_free(j);
return hash; return hash;
} }
@@ -757,8 +742,8 @@ jv jv_string_slice(jv j, int start, int end) {
} }
jv jv_string_concat(jv a, jv b) { jv jv_string_concat(jv a, jv b) {
jvp_string* sb = jvp_string_ptr(b); a = jvp_string_append(a, jv_string_value(b),
a = jvp_string_append(a, sb->data, jvp_string_length(sb)); jvp_string_length(jvp_string_ptr(b)));
jv_free(b); jv_free(b);
return a; return a;
} }
@@ -818,7 +803,7 @@ jv jv_string_fmt(const char* fmt, ...) {
struct object_slot { struct object_slot {
int next; /* next slot with same hash, for collisions */ int next; /* next slot with same hash, for collisions */
uint32_t hash; uint32_t hash;
jvp_string* string; jv string;
jv value; jv value;
}; };
@@ -842,7 +827,7 @@ static jv jvp_object_new(int size) {
obj->refcnt.count = 1; obj->refcnt.count = 1;
for (int i=0; i<size; i++) { for (int i=0; i<size; i++) {
obj->elements[i].next = i - 1; obj->elements[i].next = i - 1;
obj->elements[i].string = 0; obj->elements[i].string = JV_NULL;
obj->elements[i].hash = 0; obj->elements[i].hash = 0;
obj->elements[i].value = JV_NULL; obj->elements[i].value = JV_NULL;
} }
@@ -851,9 +836,7 @@ static jv jvp_object_new(int size) {
for (int i=0; i<size*2; i++) { for (int i=0; i<size*2; i++) {
hashbuckets[i] = -1; hashbuckets[i] = -1;
} }
jv r = {JV_KIND_OBJECT, 0, size, {&obj->refcnt}}; jv r = {JV_KIND_OBJECT, 0, 0, size, {&obj->refcnt}};
/* jv_nontrivial r = {&obj->refcnt,
{size*2 - 1, (char*)hashbuckets - (char*)obj}}; */
return r; return r;
} }
@@ -876,7 +859,7 @@ static int* jvp_object_buckets(jv o) {
return (int*)(&jvp_object_ptr(o)->elements[o.size]); return (int*)(&jvp_object_ptr(o)->elements[o.size]);
} }
static int* jvp_object_find_bucket(jv object, jvp_string* key) { static int* jvp_object_find_bucket(jv object, jv key) {
return jvp_object_buckets(object) + (jvp_object_mask(object) & jvp_string_hash(key)); return jvp_object_buckets(object) + (jvp_object_mask(object) & jvp_string_hash(key));
} }
@@ -890,18 +873,19 @@ static struct object_slot* jvp_object_next_slot(jv object, struct object_slot* s
return jvp_object_get_slot(object, slot->next); return jvp_object_get_slot(object, slot->next);
} }
static struct object_slot* jvp_object_find_slot(jv object, jvp_string* keystr, int* bucket) { static struct object_slot* jvp_object_find_slot(jv object, jv keystr, int* bucket) {
uint32_t hash = jvp_string_hash(keystr);
for (struct object_slot* curr = jvp_object_get_slot(object, *bucket); for (struct object_slot* curr = jvp_object_get_slot(object, *bucket);
curr; curr;
curr = jvp_object_next_slot(object, curr)) { curr = jvp_object_next_slot(object, curr)) {
if (jvp_string_equal_hashed(keystr, curr->string)) { if (curr->hash == hash && jvp_string_equal(keystr, curr->string)) {
return curr; return curr;
} }
} }
return 0; return 0;
} }
static struct object_slot* jvp_object_add_slot(jv object, jvp_string* key, int* bucket) { static struct object_slot* jvp_object_add_slot(jv object, jv key, int* bucket) {
jvp_object* o = jvp_object_ptr(object); jvp_object* o = jvp_object_ptr(object);
int newslot_idx = o->next_free; int newslot_idx = o->next_free;
if (newslot_idx == jvp_object_size(object)) return 0; if (newslot_idx == jvp_object_size(object)) return 0;
@@ -914,7 +898,8 @@ static struct object_slot* jvp_object_add_slot(jv object, jvp_string* key, int*
return newslot; return newslot;
} }
static jv* jvp_object_read(jv object, jvp_string* key) { static jv* jvp_object_read(jv object, jv key) {
assert(jv_get_kind(key) == JV_KIND_STRING);
int* bucket = jvp_object_find_bucket(object, key); int* bucket = jvp_object_find_bucket(object, key);
struct object_slot* slot = jvp_object_find_slot(object, key, bucket); struct object_slot* slot = jvp_object_find_slot(object, key, bucket);
if (slot == 0) return 0; if (slot == 0) return 0;
@@ -926,8 +911,8 @@ static void jvp_object_free(jv o) {
if (jvp_refcnt_dec(o.u.ptr)) { if (jvp_refcnt_dec(o.u.ptr)) {
for (int i=0; i<jvp_object_size(o); i++) { for (int i=0; i<jvp_object_size(o); i++) {
struct object_slot* slot = jvp_object_get_slot(o, i); struct object_slot* slot = jvp_object_get_slot(o, i);
if (slot->string) { if (jv_get_kind(slot->string) != JV_KIND_NULL) {
jvp_string_free_p(slot->string); jvp_string_free(slot->string);
jv_free(slot->value); jv_free(slot->value);
} }
} }
@@ -942,8 +927,7 @@ static jv jvp_object_rehash(jv object) {
jv new_object = jvp_object_new(size * 2); jv new_object = jvp_object_new(size * 2);
for (int i=0; i<size; i++) { for (int i=0; i<size; i++) {
struct object_slot* slot = jvp_object_get_slot(object, i); struct object_slot* slot = jvp_object_get_slot(object, i);
if (!slot->string) continue; if (jv_get_kind(slot->string) == JV_KIND_NULL) continue;
int* new_bucket = jvp_object_find_bucket(new_object, slot->string); int* new_bucket = jvp_object_find_bucket(new_object, slot->string);
assert(!jvp_object_find_slot(new_object, slot->string, new_bucket)); assert(!jvp_object_find_slot(new_object, slot->string, new_bucket));
struct object_slot* new_slot = jvp_object_add_slot(new_object, slot->string, new_bucket); struct object_slot* new_slot = jvp_object_add_slot(new_object, slot->string, new_bucket);
@@ -966,8 +950,8 @@ static jv jvp_object_unshare(jv object) {
struct object_slot* old_slot = jvp_object_get_slot(object, i); struct object_slot* old_slot = jvp_object_get_slot(object, i);
struct object_slot* new_slot = jvp_object_get_slot(new_object, i); struct object_slot* new_slot = jvp_object_get_slot(new_object, i);
*new_slot = *old_slot; *new_slot = *old_slot;
if (old_slot->string) { if (jv_get_kind(old_slot->string) != JV_KIND_NULL) {
new_slot->string = jvp_string_copy_p(old_slot->string); new_slot->string = jv_copy(old_slot->string);
new_slot->value = jv_copy(old_slot->value); new_slot->value = jv_copy(old_slot->value);
} }
} }
@@ -981,13 +965,13 @@ static jv jvp_object_unshare(jv object) {
return new_object; return new_object;
} }
static jv* jvp_object_write(jv* object, jvp_string* key) { static jv* jvp_object_write(jv* object, jv key) {
*object = jvp_object_unshare(*object); *object = jvp_object_unshare(*object);
int* bucket = jvp_object_find_bucket(*object, key); int* bucket = jvp_object_find_bucket(*object, key);
struct object_slot* slot = jvp_object_find_slot(*object, key, bucket); struct object_slot* slot = jvp_object_find_slot(*object, key, bucket);
if (slot) { if (slot) {
// already has the key // already has the key
jvp_string_free_p(key); jvp_string_free(key);
return &slot->value; return &slot->value;
} }
slot = jvp_object_add_slot(*object, key, bucket); slot = jvp_object_add_slot(*object, key, bucket);
@@ -1004,17 +988,19 @@ static jv* jvp_object_write(jv* object, jvp_string* key) {
return &slot->value; return &slot->value;
} }
static int jvp_object_delete(jv* object, jvp_string* key) { static int jvp_object_delete(jv* object, jv key) {
assert(jv_get_kind(key) == JV_KIND_STRING);
*object = jvp_object_unshare(*object); *object = jvp_object_unshare(*object);
int* bucket = jvp_object_find_bucket(*object, key); int* bucket = jvp_object_find_bucket(*object, key);
int* prev_ptr = bucket; int* prev_ptr = bucket;
uint32_t hash = jvp_string_hash(key);
for (struct object_slot* curr = jvp_object_get_slot(*object, *bucket); for (struct object_slot* curr = jvp_object_get_slot(*object, *bucket);
curr; curr;
curr = jvp_object_next_slot(*object, curr)) { curr = jvp_object_next_slot(*object, curr)) {
if (jvp_string_equal_hashed(key, curr->string)) { if (hash == curr->hash && jvp_string_equal(key, curr->string)) {
*prev_ptr = curr->next; *prev_ptr = curr->next;
jvp_string_free_p(curr->string); jvp_string_free(curr->string);
curr->string = 0; curr->string = JV_NULL;
jv_free(curr->value); jv_free(curr->value);
return 1; return 1;
} }
@@ -1027,7 +1013,7 @@ static int jvp_object_length(jv object) {
int n = 0; int n = 0;
for (int i=0; i<jvp_object_size(object); i++) { for (int i=0; i<jvp_object_size(object); i++) {
struct object_slot* slot = jvp_object_get_slot(object, i); struct object_slot* slot = jvp_object_get_slot(object, i);
if (slot->string) n++; if (jv_get_kind(slot->string) != JV_KIND_NULL) n++;
} }
return n; return n;
} }
@@ -1037,7 +1023,7 @@ static int jvp_object_equal(jv o1, jv o2) {
int len1 = 0; int len1 = 0;
for (int i=0; i<jvp_object_size(o1); i++) { for (int i=0; i<jvp_object_size(o1); i++) {
struct object_slot* slot = jvp_object_get_slot(o1, i); struct object_slot* slot = jvp_object_get_slot(o1, i);
if (!slot->string) continue; if (jv_get_kind(slot->string) == JV_KIND_NULL) continue;
jv* slot2 = jvp_object_read(o2, slot->string); jv* slot2 = jvp_object_read(o2, slot->string);
if (!slot2) return 0; if (!slot2) return 0;
// FIXME: do less refcounting here // FIXME: do less refcounting here
@@ -1058,7 +1044,7 @@ jv jv_object() {
jv jv_object_get(jv object, jv key) { jv jv_object_get(jv object, jv key) {
assert(jv_get_kind(object) == JV_KIND_OBJECT); assert(jv_get_kind(object) == JV_KIND_OBJECT);
assert(jv_get_kind(key) == JV_KIND_STRING); assert(jv_get_kind(key) == JV_KIND_STRING);
jv* slot = jvp_object_read(object, jvp_string_ptr(key)); jv* slot = jvp_object_read(object, key);
jv val; jv val;
if (slot) { if (slot) {
val = jv_copy(*slot); val = jv_copy(*slot);
@@ -1074,7 +1060,7 @@ jv jv_object_set(jv object, jv key, jv value) {
assert(jv_get_kind(object) == JV_KIND_OBJECT); assert(jv_get_kind(object) == JV_KIND_OBJECT);
assert(jv_get_kind(key) == JV_KIND_STRING); assert(jv_get_kind(key) == JV_KIND_STRING);
// copy/free of object, key, value coalesced // copy/free of object, key, value coalesced
jv* slot = jvp_object_write(&object, jvp_string_ptr(key)); jv* slot = jvp_object_write(&object, key);
jv_free(*slot); jv_free(*slot);
*slot = value; *slot = value;
return object; return object;
@@ -1083,7 +1069,7 @@ jv jv_object_set(jv object, jv key, jv value) {
jv jv_object_delete(jv object, jv key) { jv jv_object_delete(jv object, jv key) {
assert(jv_get_kind(object) == JV_KIND_OBJECT); assert(jv_get_kind(object) == JV_KIND_OBJECT);
assert(jv_get_kind(key) == JV_KIND_STRING); assert(jv_get_kind(key) == JV_KIND_STRING);
jvp_object_delete(&object, jvp_string_ptr(key)); jvp_object_delete(&object, key);
jv_free(key); jv_free(key);
return object; return object;
} }
@@ -1147,15 +1133,16 @@ int jv_object_iter_next(jv object, int iter) {
if (iter >= jvp_object_size(object)) if (iter >= jvp_object_size(object))
return ITER_FINISHED; return ITER_FINISHED;
slot = jvp_object_get_slot(object, iter); slot = jvp_object_get_slot(object, iter);
} while (!slot->string); } while (jv_get_kind(slot->string) == JV_KIND_NULL);
assert(jv_get_kind(jvp_object_get_slot(object,iter)->string)
== JV_KIND_STRING);
return iter; return iter;
} }
jv jv_object_iter_key(jv object, int iter) { jv jv_object_iter_key(jv object, int iter) {
jvp_string* s = jvp_object_get_slot(object, iter)->string; jv s = jvp_object_get_slot(object, iter)->string;
assert(s); assert(jv_get_kind(s) == JV_KIND_STRING);
jv j = {JV_KIND_STRING, 0, 0, {&s->refcnt}}; return jv_copy(s);
return jv_copy(j);
} }
jv jv_object_iter_value(jv object, int iter) { jv jv_object_iter_value(jv object, int iter) {
@@ -1208,7 +1195,7 @@ int jv_equal(jv a, jv b) {
r = 0; r = 0;
} else if (jv_get_kind(a) == JV_KIND_NUMBER) { } else if (jv_get_kind(a) == JV_KIND_NUMBER) {
r = jv_number_value(a) == jv_number_value(b); r = jv_number_value(a) == jv_number_value(b);
} else if (a.kind == b.kind && } else if (a.kind_flags == b.kind_flags &&
a.size == b.size && a.size == b.size &&
a.u.ptr == b.u.ptr) { a.u.ptr == b.u.ptr) {
r = 1; r = 1;
+2 -1
View File
@@ -20,7 +20,8 @@ struct jv_refcnt;
/* All of the fields of this struct are private. /* All of the fields of this struct are private.
Really. Do not play with them. */ Really. Do not play with them. */
typedef struct { typedef struct {
unsigned char kind; unsigned char kind_flags;
unsigned char pad_;
unsigned short offset; /* array offsets */ unsigned short offset; /* array offsets */
int size; int size;
union { union {