* 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) {
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;
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;
}
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;
}
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;
}
}
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];
}
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;
}
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;
}
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;
}
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;
}
}
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;
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);
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;
}
}
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;
}
struct object_slot {
int next; /* next slot with same hash, for collisions */
uint32_t hash;
- jvp_string* string;
+ jv string;
jv value;
};
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;
}
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;
}
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_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;
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;
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);
}
}
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);
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);
}
}
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);
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;
}
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;
}
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
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);
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;
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;
}
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) {
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;