]> granicus.if.org Git - jq/commitdiff
Clean up string/object interactions in jv.
authorStephen Dolan <mu@netsoc.tcd.ie>
Sun, 8 Dec 2013 22:23:43 +0000 (22:23 +0000)
committerStephen Dolan <mu@netsoc.tcd.ie>
Sun, 8 Dec 2013 22:49:28 +0000 (22:49 +0000)
jv.c
jv.h

diff --git a/jv.c b/jv.c
index e03051a4d4f3d6dfd286b80d770baf46abda8825..eea6a290a7696f15f1fc71faf238f1f1e8423405 100644 (file)
--- a/jv.c
+++ b/jv.c
@@ -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;
diff --git a/jv.h b/jv.h
index e0a15147aebcdf142cbc83ab5b425a4c24c44e1e..8d61d104474fe19c2eb55afa03531ce74a689d05 100644 (file)
--- a/jv.h
+++ b/jv.h
@@ -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 {