summaryrefslogtreecommitdiff
path: root/json-glib/json-object.c
diff options
context:
space:
mode:
Diffstat (limited to 'json-glib/json-object.c')
-rw-r--r--json-glib/json-object.c99
1 files changed, 98 insertions, 1 deletions
diff --git a/json-glib/json-object.c b/json-glib/json-object.c
index acb72f7..5b1ec9e 100644
--- a/json-glib/json-object.c
+++ b/json-glib/json-object.c
@@ -61,7 +61,7 @@ json_object_new (void)
{
JsonObject *object;
- object = g_slice_new (JsonObject);
+ object = g_slice_new0 (JsonObject);
object->ref_count = 1;
object->members = g_hash_table_new_full (g_str_hash, g_str_equal,
@@ -146,6 +146,7 @@ json_object_seal (JsonObject *object)
while (json_object_iter_next (&iter, NULL, &node))
json_node_seal (node);
+ object->immutable_hash = json_object_hash (object);
object->immutable = TRUE;
}
@@ -904,6 +905,102 @@ json_object_foreach_member (JsonObject *object,
}
/**
+ * json_object_hash:
+ * @key: (type JsonObject): a JSON object to hash
+ *
+ * Calculate a hash value for the given @key (a #JsonObject).
+ *
+ * The hash is calculated over the object and all its members, recursively. If
+ * the object is immutable, this is a fast operation; otherwise, it scales
+ * proportionally with the number of members in the object.
+ *
+ * Returns: hash value for @key
+ * Since: UNRELEASED
+ */
+guint
+json_object_hash (gconstpointer key)
+{
+ JsonObject *object = (JsonObject *) key;
+ guint hash = 0;
+ JsonObjectIter iter;
+ const gchar *member_name;
+ JsonNode *node;
+
+ g_return_val_if_fail (object != NULL, 0);
+
+ /* If the object is immutable, use the cached hash. */
+ if (object->immutable)
+ return object->immutable_hash;
+
+ /* Otherwise, calculate from scratch. */
+ json_object_iter_init (&iter, object);
+
+ while (json_object_iter_next (&iter, &member_name, &node))
+ hash ^= (json_string_hash (member_name) ^ json_node_hash (node));
+
+ return hash;
+}
+
+/**
+ * json_object_equal:
+ * @a: (type JsonObject): a JSON object
+ * @b: (type JsonObject): another JSON object
+ *
+ * Check whether @a and @b are equal #JsonObjects, meaning they have the same
+ * set of members, and the values of corresponding members are equal.
+ *
+ * Returns: %TRUE if @a and @b are equal; %FALSE otherwise
+ * Since: UNRELEASED
+ */
+gboolean
+json_object_equal (gconstpointer a,
+ gconstpointer b)
+{
+ JsonObject *object_a, *object_b;
+ guint size_a, size_b;
+ JsonObjectIter iter_a;
+ JsonNode *child_a, *child_b; /* unowned */
+ const gchar *member_name;
+
+ object_a = (JsonObject *) a;
+ object_b = (JsonObject *) b;
+
+ /* Identity comparison. */
+ if (object_a == object_b)
+ return TRUE;
+
+ /* Check sizes. */
+ size_a = json_object_get_size (object_a);
+ size_b = json_object_get_size (object_b);
+
+ if (size_a != size_b)
+ return FALSE;
+
+ /* Check member names and values. Check the member names first
+ * to avoid expensive recursive value comparisons which might
+ * be unnecessary. */
+ json_object_iter_init (&iter_a, object_a);
+
+ while (json_object_iter_next (&iter_a, &member_name, NULL))
+ {
+ if (!json_object_has_member (object_b, member_name))
+ return FALSE;
+ }
+
+ json_object_iter_init (&iter_a, object_a);
+
+ while (json_object_iter_next (&iter_a, &member_name, &child_a))
+ {
+ child_b = json_object_get_member (object_b, member_name);
+
+ if (!json_node_equal (child_a, child_b))
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+/**
* json_object_iter_init:
* @iter: an uninitialised #JsonObjectIter
* @object: the #JsonObject to iterate over