]> granicus.if.org Git - jq/commitdiff
Preserve insertion order in objects. Closes #169.
authorStephen Dolan <mu@netsoc.tcd.ie>
Wed, 4 Dec 2013 22:30:39 +0000 (22:30 +0000)
committerStephen Dolan <mu@netsoc.tcd.ie>
Wed, 4 Dec 2013 22:30:39 +0000 (22:30 +0000)
jv.c

diff --git a/jv.c b/jv.c
index 3197f313fcf7485c28455cce3f14dd5b2900b55d..71824456ba7a60468be35347d2a3034aa4eb53a5 100644 (file)
--- a/jv.c
+++ b/jv.c
@@ -640,15 +640,15 @@ jv jv_string_fmt(const char* fmt, ...) {
  */
 
 struct object_slot {
-  int next;
-  jvp_string* string;
+  int next; /* next slot with same hash, for collisions */
   uint32_t hash;
+  jvp_string* string;
   jv value;
 };
 
 typedef struct {
   jv_refcnt refcnt;
-  int first_free;
+  int next_free;
   struct object_slot elements[];
 } jvp_object;
 
@@ -669,7 +669,7 @@ static jv_nontrivial jvp_object_new(int size) {
     obj->elements[i].hash = 0;
     obj->elements[i].value = JV_NULL;
   }
-  obj->first_free = size - 1;
+  obj->next_free = 0;
   int* hashbuckets = (int*)(&obj->elements[size]);
   jv_nontrivial r = {&obj->refcnt, 
                   {size*2 - 1, (char*)hashbuckets - (char*)obj}};
@@ -724,10 +724,10 @@ static struct object_slot* jvp_object_find_slot(jv_nontrivial* object, jvp_strin
 
 static struct object_slot* jvp_object_add_slot(jv_nontrivial* object, jvp_string* key, int* bucket) {
   jvp_object* o = jvp_object_ptr(object);
-  int newslot_idx = o->first_free;
+  int newslot_idx = o->next_free;
+  if (newslot_idx == jvp_object_size(object)) return 0;
   struct object_slot* newslot = jvp_object_get_slot(object, newslot_idx);
-  if (newslot == 0) return 0;
-  o->first_free = newslot->next;
+  o->next_free++;
   newslot->next = *bucket;
   *bucket = newslot_idx;
   newslot->hash = jvp_string_hash(key);
@@ -735,16 +735,6 @@ static struct object_slot* jvp_object_add_slot(jv_nontrivial* object, jvp_string
   return newslot;
 }
 
-static void jvp_object_free_slot(jv_nontrivial* object, struct object_slot* slot) {
-  jvp_object* o = jvp_object_ptr(object);
-  slot->next = o->first_free;
-  assert(slot->string);
-  jvp_string_free_p(slot->string);
-  slot->string = 0;
-  jv_free(slot->value);
-  o->first_free = slot - jvp_object_get_slot(object, 0);
-}
-
 static jv* jvp_object_read(jv_nontrivial* object, jvp_string* key) {
   int* bucket = jvp_object_find_bucket(object, key);
   struct object_slot* slot = jvp_object_find_slot(object, key, bucket);
@@ -789,7 +779,7 @@ static void jvp_object_unshare(jv_nontrivial* object) {
     return;
 
   jv_nontrivial new_object = jvp_object_new(jvp_object_size(object));
-  jvp_object_ptr(&new_object)->first_free = jvp_object_ptr(object)->first_free;
+  jvp_object_ptr(&new_object)->next_free = jvp_object_ptr(object)->next_free;
   for (int i=0; i<jvp_object_size(&new_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);
@@ -841,7 +831,9 @@ static int jvp_object_delete(jv_nontrivial* object, jvp_string* key) {
        curr = jvp_object_next_slot(object, curr)) {
     if (jvp_string_equal_hashed(key, curr->string)) {
       *prev_ptr = curr->next;
-      jvp_object_free_slot(object, curr);
+      jvp_string_free_p(curr->string);
+      curr->string = 0;
+      jv_free(curr->value);
       return 1;
     }
     prev_ptr = &curr->next;