diff options
author | Emmanuele Bassi <ebassi@linux.intel.com> | 2009-10-26 22:36:01 +0000 |
---|---|---|
committer | Emmanuele Bassi <ebassi@linux.intel.com> | 2009-10-26 22:36:01 +0000 |
commit | cba7db96581343e3cbd8e5eb067026efb8cac24e (patch) | |
tree | b1f21cf077c394293c175debe180b7e336ca2816 /json-glib/json-object.c | |
parent | d5bebce0286aef5c4b4110c16c22a8ef3dc38405 (diff) | |
download | json-glib-cba7db96581343e3cbd8e5eb067026efb8cac24e.tar.gz |
object: Guarantee insertion order
When iterating over the members of a JsonObject, or when retrieving
the list of members, the insertion order should be preserved by the
JsonObject. This is simply implemented by keeping a mirror list of
the member names.
Apparently, though JSON does not guarantee any ordering, it is somewhat
expected by JSON (and ECMAScript) users.
Diffstat (limited to 'json-glib/json-object.c')
-rw-r--r-- | json-glib/json-object.c | 67 |
1 files changed, 35 insertions, 32 deletions
diff --git a/json-glib/json-object.c b/json-glib/json-object.c index 69f9d15..862cd0e 100644 --- a/json-glib/json-object.c +++ b/json-glib/json-object.c @@ -123,7 +123,9 @@ json_object_unref (JsonObject *object) g_atomic_int_compare_and_exchange (&object->ref_count, old_ref, old_ref - 1); else { + g_list_free (object->members_ordered); g_hash_table_destroy (object->members); + object->members_ordered = NULL; object->members = NULL; g_slice_free (JsonObject, object); @@ -135,9 +137,12 @@ object_set_member_internal (JsonObject *object, const gchar *member_name, JsonNode *node) { - g_hash_table_replace (object->members, - g_strdup (member_name), - node); + gchar *name = g_strdup (member_name); + + if (g_hash_table_lookup (object->members, name) == NULL) + object->members_ordered = g_list_prepend (object->members_ordered, name); + + g_hash_table_replace (object->members, name, node); } /** @@ -459,9 +464,13 @@ g_hash_table_get_values (GHashTable *hash_table) GList * json_object_get_members (JsonObject *object) { + GList *copy; + g_return_val_if_fail (object != NULL, NULL); - return g_hash_table_get_keys (object->members); + copy = g_list_copy (object->members_ordered); + + return g_list_reverse (copy); } /** @@ -795,32 +804,23 @@ void json_object_remove_member (JsonObject *object, const gchar *member_name) { + GList *l; + g_return_if_fail (object != NULL); g_return_if_fail (member_name != NULL); - g_hash_table_remove (object->members, member_name); -} - -typedef struct _ForeachClosure ForeachClosure; - -struct _ForeachClosure -{ - JsonObject *object; - - JsonObjectForeach func; - gpointer data; -}; + for (l = object->members_ordered; l != NULL; l = l->next) + { + const gchar *name = l->data; -static void -json_object_foreach_internal (gpointer key, - gpointer value, - gpointer data) -{ - ForeachClosure *clos = data; - const gchar *member_name = key; - JsonNode *member_node = value; + if (g_strcmp0 (name, member_name) == 0) + { + object->members_ordered = g_list_delete_link (object->members_ordered, l); + break; + } + } - clos->func (clos->object, member_name, member_node, clos->data); + g_hash_table_remove (object->members, member_name); } /** @@ -843,15 +843,18 @@ json_object_foreach_member (JsonObject *object, JsonObjectForeach func, gpointer data) { - ForeachClosure clos; + GList *members, *l; g_return_if_fail (object != NULL); g_return_if_fail (func != NULL); - clos.object = object; - clos.func = func; - clos.data = data; - g_hash_table_foreach (object->members, - json_object_foreach_internal, - &clos); + /* the list is stored in reverse order to have constant time additions */ + members = g_list_last (object->members_ordered); + for (l = members; l != NULL; l = l->prev) + { + const gchar *member_name = l->data; + JsonNode *member_node = g_hash_table_lookup (object->members, member_name); + + func (object, member_name, member_node, data); + } } |