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)
*/
#define KIND_MASK 0xf
jv_kind jv_get_kind(jv x) {
return x.kind;
return x.kind_flags & KIND_MASK;
}
const char* jv_kind_name(jv_kind k) {
@@ -57,9 +59,9 @@ const char* jv_kind_name(jv_kind k) {
return "<unknown>";
}
static const jv JV_NULL = {JV_KIND_NULL, 0, 0, {0}};
static const jv JV_FALSE = {JV_KIND_FALSE, 0, 0, {0}};
static const jv JV_TRUE = {JV_KIND_TRUE, 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, {0}};
static const jv JV_TRUE = {JV_KIND_TRUE, 0, 0, 0, {0}};
jv jv_true() {
return JV_TRUE;
@@ -91,7 +93,7 @@ jv jv_invalid_with_msg(jv err) {
i->refcnt = JV_REFCNT_INIT;
i->errmsg = err;
jv x = {JV_KIND_INVALID, 0, 0, {&i->refcnt}};
jv x = {JV_KIND_INVALID, 0, 0, 0, {&i->refcnt}};
return x;
}
@@ -127,7 +129,7 @@ static void jvp_invalid_free(jv x) {
jv jv_number(double x) {
jv j;
j.kind = JV_KIND_NUMBER;
j.kind_flags = JV_KIND_NUMBER;
j.size = 0;
j.u.number = x;
return j;
@@ -171,7 +173,7 @@ static jvp_array* jvp_array_alloc(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;
}
@@ -234,7 +236,7 @@ static jv* jvp_array_write(jv* a, int i) {
}
new_array->length = new_length;
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;
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;
s->data[length] = 0;
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;
}
@@ -408,7 +410,7 @@ static jv jvp_string_new(const char* data, uint32_t length) {
s->length_hashed = length << 1;
memcpy(s->data, data, length);
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;
}
@@ -416,27 +418,18 @@ static jv jvp_string_empty_new(uint32_t length) {
jvp_string* s = jvp_string_alloc(length);
s->length_hashed = 0;
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;
}
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)) {
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) {
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);
news->data[currlen + len] = 0;
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;
}
}
@@ -479,7 +472,8 @@ static uint32_t rotl32 (uint32_t x, int8_t 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)
return str->hash;
@@ -534,15 +528,6 @@ static uint32_t jvp_string_hash(jvp_string* str) {
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) {
assert(jv_get_kind(a) == 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) {
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);
return hash;
}
@@ -757,8 +742,8 @@ jv jv_string_slice(jv j, int start, int end) {
}
jv jv_string_concat(jv a, jv b) {
jvp_string* sb = jvp_string_ptr(b);
a = jvp_string_append(a, sb->data, jvp_string_length(sb));
a = jvp_string_append(a, jv_string_value(b),
jvp_string_length(jvp_string_ptr(b)));
jv_free(b);
return a;
}
@@ -818,7 +803,7 @@ jv jv_string_fmt(const char* fmt, ...) {
struct object_slot {
int next; /* next slot with same hash, for collisions */
uint32_t hash;
jvp_string* string;
jv string;
jv value;
};
@@ -842,7 +827,7 @@ static jv jvp_object_new(int size) {
obj->refcnt.count = 1;
for (int i=0; i<size; i++) {
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].value = JV_NULL;
}
@@ -851,9 +836,7 @@ static jv jvp_object_new(int size) {
for (int i=0; i<size*2; i++) {
hashbuckets[i] = -1;
}
jv r = {JV_KIND_OBJECT, 0, size, {&obj->refcnt}};
/* jv_nontrivial r = {&obj->refcnt,
{size*2 - 1, (char*)hashbuckets - (char*)obj}}; */
jv r = {JV_KIND_OBJECT, 0, 0, size, {&obj->refcnt}};
return r;
}
@@ -876,7 +859,7 @@ static int* jvp_object_buckets(jv o) {
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));
}
@@ -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);
}
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);
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 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);
int newslot_idx = o->next_free;
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;
}
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);
struct object_slot* slot = jvp_object_find_slot(object, key, bucket);
if (slot == 0) return 0;
@@ -926,8 +911,8 @@ static void jvp_object_free(jv o) {
if (jvp_refcnt_dec(o.u.ptr)) {
for (int i=0; i<jvp_object_size(o); i++) {
struct object_slot* slot = jvp_object_get_slot(o, i);
if (slot->string) {
jvp_string_free_p(slot->string);
if (jv_get_kind(slot->string) != JV_KIND_NULL) {
jvp_string_free(slot->string);
jv_free(slot->value);
}
}
@@ -942,8 +927,7 @@ static jv jvp_object_rehash(jv object) {
jv new_object = jvp_object_new(size * 2);
for (int i=0; i<size; 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);
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);
@@ -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* new_slot = jvp_object_get_slot(new_object, i);
*new_slot = *old_slot;
if (old_slot->string) {
new_slot->string = jvp_string_copy_p(old_slot->string);
if (jv_get_kind(old_slot->string) != JV_KIND_NULL) {
new_slot->string = jv_copy(old_slot->string);
new_slot->value = jv_copy(old_slot->value);
}
}
@@ -981,13 +965,13 @@ static jv jvp_object_unshare(jv 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);
int* bucket = jvp_object_find_bucket(*object, key);
struct object_slot* slot = jvp_object_find_slot(*object, key, bucket);
if (slot) {
// already has the key
jvp_string_free_p(key);
jvp_string_free(key);
return &slot->value;
}
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;
}
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);
int* bucket = jvp_object_find_bucket(*object, key);
int* prev_ptr = bucket;
uint32_t hash = jvp_string_hash(key);
for (struct object_slot* curr = jvp_object_get_slot(*object, *bucket);
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;
jvp_string_free_p(curr->string);
curr->string = 0;
jvp_string_free(curr->string);
curr->string = JV_NULL;
jv_free(curr->value);
return 1;
}
@@ -1027,7 +1013,7 @@ static int jvp_object_length(jv object) {
int n = 0;
for (int i=0; i<jvp_object_size(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;
}
@@ -1037,7 +1023,7 @@ static int jvp_object_equal(jv o1, jv o2) {
int len1 = 0;
for (int i=0; i<jvp_object_size(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);
if (!slot2) return 0;
// FIXME: do less refcounting here
@@ -1058,7 +1044,7 @@ jv jv_object() {
jv jv_object_get(jv object, jv key) {
assert(jv_get_kind(object) == JV_KIND_OBJECT);
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;
if (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(key) == JV_KIND_STRING);
// 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);
*slot = value;
return object;
@@ -1083,7 +1069,7 @@ jv jv_object_set(jv object, jv key, jv value) {
jv jv_object_delete(jv object, jv key) {
assert(jv_get_kind(object) == JV_KIND_OBJECT);
assert(jv_get_kind(key) == JV_KIND_STRING);
jvp_object_delete(&object, jvp_string_ptr(key));
jvp_object_delete(&object, key);
jv_free(key);
return object;
}
@@ -1147,15 +1133,16 @@ int jv_object_iter_next(jv object, int iter) {
if (iter >= jvp_object_size(object))
return ITER_FINISHED;
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;
}
jv jv_object_iter_key(jv object, int iter) {
jvp_string* s = jvp_object_get_slot(object, iter)->string;
assert(s);
jv j = {JV_KIND_STRING, 0, 0, {&s->refcnt}};
return jv_copy(j);
jv s = jvp_object_get_slot(object, iter)->string;
assert(jv_get_kind(s) == JV_KIND_STRING);
return jv_copy(s);
}
jv jv_object_iter_value(jv object, int iter) {
@@ -1208,7 +1195,7 @@ int jv_equal(jv a, jv b) {
r = 0;
} else if (jv_get_kind(a) == JV_KIND_NUMBER) {
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.u.ptr == b.u.ptr) {
r = 1;
+2 -1
View File
@@ -20,7 +20,8 @@ struct jv_refcnt;
/* All of the fields of this struct are private.
Really. Do not play with them. */
typedef struct {
unsigned char kind;
unsigned char kind_flags;
unsigned char pad_;
unsigned short offset; /* array offsets */
int size;
union {