[json-glib] node: Add json_node_ref() and json_node_unref()



commit 1de237a502ceee96df7091c2df4492b8bc08b2c5
Author: Philip Withnall <philip withnall collabora co uk>
Date:   Sat Nov 7 17:38:22 2015 +0100

    node: Add json_node_ref() and json_node_unref()
    
    Add reference counting semantics to JsonNode, in addition to the
    existing init/unset and alloc/free semantics.
    
    json_node_free() must only be used with nodes allocated using
    json_node_alloc(). json_node_unref() may be used with all nodes (if
    correctly paired; it may be paired with json_node_alloc()).
    
    It is not valid to call json_node_free() on a node whose reference count
    is not 1.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=756121

 doc/reference/json-glib-sections.txt |    2 +
 json-glib/json-array.c               |    6 +-
 json-glib/json-builder.c             |    4 +-
 json-glib/json-generator.c           |    4 +-
 json-glib/json-gobject.c             |    4 +-
 json-glib/json-gvariant.c            |    2 +-
 json-glib/json-node.c                |  129 +++++++++++++++++++++++++---------
 json-glib/json-object.c              |    4 +-
 json-glib/json-parser.c              |   24 +++---
 json-glib/json-path.c                |    4 +-
 json-glib/json-reader.c              |    4 +-
 json-glib/json-types-private.h       |   13 +++-
 json-glib/json-types.h               |    5 ++
 13 files changed, 141 insertions(+), 64 deletions(-)
---
diff --git a/doc/reference/json-glib-sections.txt b/doc/reference/json-glib-sections.txt
index 2dccde9..21e1f0d 100644
--- a/doc/reference/json-glib-sections.txt
+++ b/doc/reference/json-glib-sections.txt
@@ -110,6 +110,8 @@ json_node_init_array
 json_node_new
 json_node_copy
 json_node_free
+json_node_ref
+json_node_unref
 json_node_is_immutable
 json_node_seal
 
diff --git a/json-glib/json-array.c b/json-glib/json-array.c
index 05cde4a..cc9c979 100644
--- a/json-glib/json-array.c
+++ b/json-glib/json-array.c
@@ -124,7 +124,7 @@ json_array_unref (JsonArray *array)
       guint i;
 
       for (i = 0; i < array->elements->len; i++)
-        json_node_free (g_ptr_array_index (array->elements, i));
+        json_node_unref (g_ptr_array_index (array->elements, i));
 
       g_ptr_array_free (array->elements, TRUE);
       array->elements = NULL;
@@ -217,7 +217,7 @@ json_array_get_elements (JsonArray *array)
  * element at @index_ inside a #JsonArray
  *
  * Return value: (transfer full): a copy of the #JsonNode at the requested
- *   index. Use json_node_free() when done.
+ *   index. Use json_node_unref() when done.
  *
  * Since: 0.6
  */
@@ -706,7 +706,7 @@ json_array_remove_element (JsonArray *array,
   g_return_if_fail (array != NULL);
   g_return_if_fail (index_ < array->elements->len);
 
-  json_node_free (g_ptr_array_remove_index (array->elements, index_));
+  json_node_unref (g_ptr_array_remove_index (array->elements, index_));
 }
 
 /**
diff --git a/json-glib/json-builder.c b/json-glib/json-builder.c
index 6531b0c..66a5796 100644
--- a/json-glib/json-builder.c
+++ b/json-glib/json-builder.c
@@ -125,7 +125,7 @@ json_builder_free_all_state (JsonBuilder *builder)
 
   if (builder->priv->root)
     {
-      json_node_free (builder->priv->root);
+      json_node_unref (builder->priv->root);
       builder->priv->root = NULL;
     }
 }
@@ -272,7 +272,7 @@ json_builder_new_immutable (void)
  * (ie: all opened objects, object members and arrays are being closed).
  *
  * Return value: (transfer full): the #JsonNode, or %NULL if the build is not complete.
- *   Free the returned value with json_node_free().
+ *   Free the returned value with json_node_unref().
  */
 JsonNode *
 json_builder_get_root (JsonBuilder *builder)
diff --git a/json-glib/json-generator.c b/json-glib/json-generator.c
index 8eed152..c47e7fe 100644
--- a/json-glib/json-generator.c
+++ b/json-glib/json-generator.c
@@ -140,7 +140,7 @@ json_generator_finalize (GObject *gobject)
 
   priv = json_generator_get_instance_private ((JsonGenerator *) gobject);
   if (priv->root != NULL)
-    json_node_free (priv->root);
+    json_node_unref (priv->root);
 
   G_OBJECT_CLASS (json_generator_parent_class)->finalize (gobject);
 }
@@ -722,7 +722,7 @@ json_generator_set_root (JsonGenerator *generator,
 
   if (generator->priv->root != NULL)
     {
-      json_node_free (generator->priv->root);
+      json_node_unref (generator->priv->root);
       generator->priv->root = NULL;
     }
 
diff --git a/json-glib/json-gobject.c b/json-glib/json-gobject.c
index d39088e..34a43c8 100644
--- a/json-glib/json-gobject.c
+++ b/json-glib/json-gobject.c
@@ -839,7 +839,7 @@ json_gobject_deserialize (GType     gtype,
  * map to a property of the #GObject
  *
  * Return value: (transfer full): the newly created #JsonNode
- *   of type %JSON_NODE_OBJECT. Use json_node_free() to free
+ *   of type %JSON_NODE_OBJECT. Use json_node_unref() to free
  *   the resources allocated by this function
  *
  * Since: 0.10
@@ -1012,7 +1012,7 @@ json_gobject_to_data (GObject *gobject,
   data = json_generator_to_data (gen, length);
   g_object_unref (gen);
 
-  json_node_free (root);
+  json_node_unref (root);
 
   return data;
 }
diff --git a/json-glib/json-gvariant.c b/json-glib/json-gvariant.c
index f8058df..6d55fb8 100644
--- a/json-glib/json-gvariant.c
+++ b/json-glib/json-gvariant.c
@@ -440,7 +440,7 @@ json_gvariant_serialize_data (GVariant *variant, gsize *length)
 
   g_object_unref (generator);
 
-  json_node_free (json_node);
+  json_node_unref (json_node);
 
   return json;
 }
diff --git a/json-glib/json-node.c b/json-glib/json-node.c
index 092a27f..35a7918 100644
--- a/json-glib/json-node.c
+++ b/json-glib/json-node.c
@@ -55,9 +55,18 @@
  * possibility of a value deep within the tree changing and affecting hash
  * values. Immutable #JsonNodes may be passed to functions which retain a
  * reference to them without needing to take a copy.
+ *
+ * #JsonNode supports two types of memory management: alloc/free semantics, and
+ * ref/unref semantics. The two may be mixed to a limited extent: nodes may be
+ * allocated (which gives them a reference count of 1), referenced zero or more
+ * times, unreferenced exactly that number of times (using json_node_unref()),
+ * then either unreferenced exactly once more or freed (using json_node_free())
+ * to destroy them. json_node_free() must not be used when a node might have a
+ * reference count not equal to 1. To this end, json-glib uses json_node_copy()
+ * and json_node_unref() internally.
  */
 
-G_DEFINE_BOXED_TYPE (JsonNode, json_node, json_node_copy, json_node_free);
+G_DEFINE_BOXED_TYPE (JsonNode, json_node, json_node_copy, json_node_unref);
 
 /**
  * json_node_get_value_type:
@@ -111,12 +120,20 @@ json_node_get_value_type (JsonNode *node)
 JsonNode *
 json_node_alloc (void)
 {
-  return g_slice_new0 (JsonNode);
+  JsonNode *node = NULL;
+
+  node = g_slice_new0 (JsonNode);
+  node->ref_count = 1;
+  node->allocated = TRUE;
+
+  return node;
 }
 
 static void
 json_node_unset (JsonNode *node)
 {
+  /* Note: Don't use JSON_NODE_IS_VALID here because this may legitimately be
+   * called with (node->ref_count == 0) from json_node_unref(). */
   g_assert (node != NULL);
 
   switch (node->type)
@@ -161,6 +178,7 @@ json_node_init (JsonNode *node,
 {
   g_return_val_if_fail (type >= JSON_NODE_OBJECT &&
                         type <= JSON_NODE_NULL, NULL);
+  g_return_val_if_fail (node->ref_count == 1, NULL);
 
   json_node_unset (node);
 
@@ -392,9 +410,9 @@ json_node_copy (JsonNode *node)
 {
   JsonNode *copy;
 
-  g_return_val_if_fail (node != NULL, NULL);
+  g_return_val_if_fail (JSON_NODE_IS_VALID (node), NULL);
 
-  copy = g_slice_new0 (JsonNode);
+  copy = json_node_alloc ();
   copy->type = node->type;
   copy->immutable = node->immutable;
 
@@ -427,6 +445,47 @@ json_node_copy (JsonNode *node)
 }
 
 /**
+ * json_node_ref:
+ * @node: a #JsonNode
+ *
+ * Increment the reference count of @node.
+ *
+ * Since: UNRELEASED
+ * Returns: (transfer full): a pointer to @node
+ */
+JsonNode *
+json_node_ref (JsonNode *node)
+{
+  g_return_val_if_fail (JSON_NODE_IS_VALID (node), NULL);
+
+  g_atomic_int_inc (&node->ref_count);
+
+  return node;
+}
+
+/**
+ * json_node_unref:
+ * @node: (transfer full): a #JsonNode
+ *
+ * Decrement the reference count of @node. If it reaches zero, the node is
+ * freed.
+ *
+ * Since: UNRELEASED
+ */
+void
+json_node_unref (JsonNode *node)
+{
+  g_return_if_fail (JSON_NODE_IS_VALID (node));
+
+  if (g_atomic_int_dec_and_test (&node->ref_count))
+    {
+      json_node_unset (node);
+      if (node->allocated)
+        g_slice_free (JsonNode, node);
+    }
+}
+
+/**
  * json_node_set_object:
  * @node: a #JsonNode initialized to %JSON_NODE_OBJECT
  * @object: (nullable): a #JsonObject
@@ -441,7 +500,7 @@ void
 json_node_set_object (JsonNode   *node,
                       JsonObject *object)
 {
-  g_return_if_fail (node != NULL);
+  g_return_if_fail (JSON_NODE_IS_VALID (node));
   g_return_if_fail (JSON_NODE_TYPE (node) == JSON_NODE_OBJECT);
   g_return_if_fail (!node->immutable);
 
@@ -467,7 +526,7 @@ void
 json_node_take_object (JsonNode   *node,
                        JsonObject *object)
 {
-  g_return_if_fail (node != NULL);
+  g_return_if_fail (JSON_NODE_IS_VALID (node));
   g_return_if_fail (JSON_NODE_TYPE (node) == JSON_NODE_OBJECT);
   g_return_if_fail (!node->immutable);
 
@@ -492,7 +551,7 @@ json_node_take_object (JsonNode   *node,
 JsonObject *
 json_node_get_object (JsonNode *node)
 {
-  g_return_val_if_fail (node != NULL, NULL);
+  g_return_val_if_fail (JSON_NODE_IS_VALID (node), NULL);
   g_return_val_if_fail (JSON_NODE_TYPE (node) == JSON_NODE_OBJECT, NULL);
 
   return node->data.object;
@@ -510,7 +569,7 @@ json_node_get_object (JsonNode *node)
 JsonObject *
 json_node_dup_object (JsonNode *node)
 {
-  g_return_val_if_fail (node != NULL, NULL);
+  g_return_val_if_fail (JSON_NODE_IS_VALID (node), NULL);
   g_return_val_if_fail (JSON_NODE_TYPE (node) == JSON_NODE_OBJECT, NULL);
 
   if (node->data.object)
@@ -532,7 +591,7 @@ void
 json_node_set_array (JsonNode  *node,
                      JsonArray *array)
 {
-  g_return_if_fail (node != NULL);
+  g_return_if_fail (JSON_NODE_IS_VALID (node));
   g_return_if_fail (JSON_NODE_TYPE (node) == JSON_NODE_ARRAY);
   g_return_if_fail (!node->immutable);
 
@@ -558,7 +617,7 @@ void
 json_node_take_array (JsonNode  *node,
                       JsonArray *array)
 {
-  g_return_if_fail (node != NULL);
+  g_return_if_fail (JSON_NODE_IS_VALID (node));
   g_return_if_fail (JSON_NODE_TYPE (node) == JSON_NODE_ARRAY);
   g_return_if_fail (!node->immutable);
 
@@ -583,7 +642,7 @@ json_node_take_array (JsonNode  *node,
 JsonArray *
 json_node_get_array (JsonNode *node)
 {
-  g_return_val_if_fail (node != NULL, NULL);
+  g_return_val_if_fail (JSON_NODE_IS_VALID (node), NULL);
   g_return_val_if_fail (JSON_NODE_TYPE (node) == JSON_NODE_ARRAY, NULL);
 
   return node->data.array;
@@ -602,7 +661,7 @@ json_node_get_array (JsonNode *node)
 JsonArray *
 json_node_dup_array (JsonNode *node)
 {
-  g_return_val_if_fail (node != NULL, NULL);
+  g_return_val_if_fail (JSON_NODE_IS_VALID (node), NULL);
   g_return_val_if_fail (JSON_NODE_TYPE (node) == JSON_NODE_ARRAY, NULL);
 
   if (node->data.array)
@@ -623,7 +682,7 @@ void
 json_node_get_value (JsonNode *node,
                      GValue   *value)
 {
-  g_return_if_fail (node != NULL);
+  g_return_if_fail (JSON_NODE_IS_VALID (node));
   g_return_if_fail (JSON_NODE_TYPE (node) == JSON_NODE_VALUE);
 
   if (node->data.value)
@@ -666,7 +725,7 @@ void
 json_node_set_value (JsonNode     *node,
                      const GValue *value)
 {
-  g_return_if_fail (node != NULL);
+  g_return_if_fail (JSON_NODE_IS_VALID (node));
   g_return_if_fail (JSON_NODE_TYPE (node) == JSON_NODE_VALUE);
   g_return_if_fail (G_VALUE_TYPE (value) != G_TYPE_INVALID);
   g_return_if_fail (!node->immutable);
@@ -707,7 +766,7 @@ json_node_set_value (JsonNode     *node,
       break;
 
     default:
-      g_warning ("Invalid value of type '%s'",
+      g_message ("Invalid value of type '%s'",
                  g_type_name (G_VALUE_TYPE (value)));
       return;
     }
@@ -723,8 +782,14 @@ json_node_set_value (JsonNode     *node,
 void
 json_node_free (JsonNode *node)
 {
+  g_return_if_fail (node == NULL || JSON_NODE_IS_VALID (node));
+  g_return_if_fail (node == NULL || node->allocated);
+
   if (G_LIKELY (node))
     {
+      if (node->ref_count > 1)
+        g_warning ("Freeing a JsonNode %p owned by other code.", node);
+
       json_node_unset (node);
       g_slice_free (JsonNode, node);
     }
@@ -746,9 +811,7 @@ json_node_free (JsonNode *node)
 void
 json_node_seal (JsonNode *node)
 {
-  g_return_if_fail (node != NULL);
-  g_return_if_fail (node->type >= JSON_NODE_OBJECT &&
-                    node->type <= JSON_NODE_NULL);
+  g_return_if_fail (JSON_NODE_IS_VALID (node));
 
   if (node->immutable)
     return;
@@ -789,9 +852,7 @@ json_node_seal (JsonNode *node)
 gboolean
 json_node_is_immutable (JsonNode *node)
 {
-  g_return_val_if_fail (node != NULL, FALSE);
-  g_return_val_if_fail (node->type >= JSON_NODE_OBJECT &&
-                        node->type <= JSON_NODE_NULL, FALSE);
+  g_return_val_if_fail (JSON_NODE_IS_VALID (node), FALSE);
 
   return node->immutable;
 }
@@ -866,7 +927,7 @@ void
 json_node_set_parent (JsonNode *node,
                       JsonNode *parent)
 {
-  g_return_if_fail (node != NULL);
+  g_return_if_fail (JSON_NODE_IS_VALID (node));
   g_return_if_fail (parent == NULL ||
                     !json_node_is_immutable (parent));
 
@@ -885,7 +946,7 @@ json_node_set_parent (JsonNode *node,
 JsonNode *
 json_node_get_parent (JsonNode *node)
 {
-  g_return_val_if_fail (node != NULL, NULL);
+  g_return_val_if_fail (JSON_NODE_IS_VALID (node), NULL);
 
   return node->parent;
 }
@@ -904,7 +965,7 @@ void
 json_node_set_string (JsonNode    *node,
                       const gchar *value)
 {
-  g_return_if_fail (node != NULL);
+  g_return_if_fail (JSON_NODE_IS_VALID (node));
   g_return_if_fail (JSON_NODE_TYPE (node) == JSON_NODE_VALUE);
   g_return_if_fail (!node->immutable);
 
@@ -927,7 +988,7 @@ json_node_set_string (JsonNode    *node,
 const gchar *
 json_node_get_string (JsonNode *node)
 {
-  g_return_val_if_fail (node != NULL, NULL);
+  g_return_val_if_fail (JSON_NODE_IS_VALID (node), NULL);
 
   if (JSON_NODE_TYPE (node) == JSON_NODE_NULL)
     return NULL;
@@ -950,7 +1011,7 @@ json_node_get_string (JsonNode *node)
 gchar *
 json_node_dup_string (JsonNode *node)
 {
-  g_return_val_if_fail (node != NULL, NULL);
+  g_return_val_if_fail (JSON_NODE_IS_VALID (node), NULL);
 
   return g_strdup (json_node_get_string (node));
 }
@@ -969,7 +1030,7 @@ void
 json_node_set_int (JsonNode *node,
                    gint64    value)
 {
-  g_return_if_fail (node != NULL);
+  g_return_if_fail (JSON_NODE_IS_VALID (node));
   g_return_if_fail (JSON_NODE_TYPE (node) == JSON_NODE_VALUE);
   g_return_if_fail (!node->immutable);
 
@@ -992,7 +1053,7 @@ json_node_set_int (JsonNode *node,
 gint64
 json_node_get_int (JsonNode *node)
 {
-  g_return_val_if_fail (node != NULL, 0);
+  g_return_val_if_fail (JSON_NODE_IS_VALID (node), 0);
 
   if (JSON_NODE_TYPE (node) == JSON_NODE_NULL)
     return 0;
@@ -1023,7 +1084,7 @@ void
 json_node_set_double (JsonNode *node,
                       gdouble   value)
 {
-  g_return_if_fail (node != NULL);
+  g_return_if_fail (JSON_NODE_IS_VALID (node));
   g_return_if_fail (JSON_NODE_TYPE (node) == JSON_NODE_VALUE);
   g_return_if_fail (!node->immutable);
 
@@ -1046,7 +1107,7 @@ json_node_set_double (JsonNode *node,
 gdouble
 json_node_get_double (JsonNode *node)
 {
-  g_return_val_if_fail (node != NULL, 0.0);
+  g_return_val_if_fail (JSON_NODE_IS_VALID (node), 0.0);
 
   if (JSON_NODE_TYPE (node) == JSON_NODE_NULL)
     return 0;
@@ -1077,7 +1138,7 @@ void
 json_node_set_boolean (JsonNode *node,
                        gboolean  value)
 {
-  g_return_if_fail (node != NULL);
+  g_return_if_fail (JSON_NODE_IS_VALID (node));
   g_return_if_fail (JSON_NODE_TYPE (node) == JSON_NODE_VALUE);
   g_return_if_fail (!node->immutable);
 
@@ -1100,7 +1161,7 @@ json_node_set_boolean (JsonNode *node,
 gboolean
 json_node_get_boolean (JsonNode *node)
 {
-  g_return_val_if_fail (node != NULL, FALSE);
+  g_return_val_if_fail (JSON_NODE_IS_VALID (node), FALSE);
 
   if (JSON_NODE_TYPE (node) == JSON_NODE_NULL)
     return FALSE;
@@ -1130,7 +1191,7 @@ json_node_get_boolean (JsonNode *node)
 JsonNodeType
 json_node_get_node_type (JsonNode *node)
 {
-  g_return_val_if_fail (node != NULL, JSON_NODE_NULL);
+  g_return_val_if_fail (JSON_NODE_IS_VALID (node), JSON_NODE_NULL);
 
   return node->type;
 }
@@ -1151,7 +1212,7 @@ json_node_get_node_type (JsonNode *node)
 gboolean
 json_node_is_null (JsonNode *node)
 {
-  g_return_val_if_fail (node != NULL, TRUE);
+  g_return_val_if_fail (JSON_NODE_IS_VALID (node), TRUE);
 
   return node->type == JSON_NODE_NULL;
 }
diff --git a/json-glib/json-object.c b/json-glib/json-object.c
index 574d04d..acb72f7 100644
--- a/json-glib/json-object.c
+++ b/json-glib/json-object.c
@@ -66,7 +66,7 @@ json_object_new (void)
   object->ref_count = 1;
   object->members = g_hash_table_new_full (g_str_hash, g_str_equal,
                                            g_free,
-                                           (GDestroyNotify) json_node_free);
+                                           (GDestroyNotify) json_node_unref);
   object->members_ordered = NULL;
 
   return object;
@@ -525,7 +525,7 @@ json_object_get_values (JsonObject *object)
  * inside a #JsonObject
  *
  * Return value: (transfer full): a copy of the node for the requested
- *   object member or %NULL. Use json_node_free() when done.
+ *   object member or %NULL. Use json_node_unref() when done.
  *
  * Since: 0.6
  */
diff --git a/json-glib/json-parser.c b/json-glib/json-parser.c
index 8f1c40c..a7b1c32 100644
--- a/json-glib/json-parser.c
+++ b/json-glib/json-parser.c
@@ -134,7 +134,7 @@ json_parser_clear (JsonParser *parser)
 
   if (priv->root)
     {
-      json_node_free (priv->root);
+      json_node_unref (priv->root);
       priv->root = NULL;
     }
 }
@@ -553,7 +553,7 @@ json_parse_array (JsonParser   *parser,
         {
           /* the json_parse_* functions will have set the error code */
           json_array_unref (array);
-          json_node_free (priv->current_node);
+          json_node_unref (priv->current_node);
           priv->current_node = old_current;
 
           return token;
@@ -585,8 +585,8 @@ json_parse_array (JsonParser   *parser,
               priv->error_code = JSON_PARSER_ERROR_TRAILING_COMMA;
 
               json_array_unref (array);
-              json_node_free (priv->current_node);
-              json_node_free (element);
+              json_node_unref (priv->current_node);
+              json_node_unref (element);
               priv->current_node = old_current;
 
               return G_TOKEN_RIGHT_BRACE;
@@ -669,7 +669,7 @@ json_parse_object (JsonParser   *parser,
           priv->error_code = JSON_PARSER_ERROR_INVALID_BAREWORD;
 
           json_object_unref (object);
-          json_node_free (priv->current_node);
+          json_node_unref (priv->current_node);
           priv->current_node = old_current;
 
           return G_TOKEN_STRING;
@@ -685,7 +685,7 @@ json_parse_object (JsonParser   *parser,
           priv->error_code = JSON_PARSER_ERROR_EMPTY_MEMBER_NAME;
 
           json_object_unref (object);
-          json_node_free (priv->current_node);
+          json_node_unref (priv->current_node);
           priv->current_node = old_current;
 
           return G_TOKEN_STRING;
@@ -703,7 +703,7 @@ json_parse_object (JsonParser   *parser,
 
           g_free (name);
           json_object_unref (object);
-          json_node_free (priv->current_node);
+          json_node_unref (priv->current_node);
           priv->current_node = old_current;
 
           return ':';
@@ -739,7 +739,7 @@ json_parse_object (JsonParser   *parser,
           /* the json_parse_* functions will have set the error code */
           g_free (name);
           json_object_unref (object);
-          json_node_free (priv->current_node);
+          json_node_unref (priv->current_node);
           priv->current_node = old_current;
 
           return token;
@@ -757,8 +757,8 @@ json_parse_object (JsonParser   *parser,
               priv->error_code = JSON_PARSER_ERROR_TRAILING_COMMA;
 
               json_object_unref (object);
-              json_node_free (member);
-              json_node_free (priv->current_node);
+              json_node_unref (member);
+              json_node_unref (priv->current_node);
               priv->current_node = old_current;
 
               return G_TOKEN_RIGHT_BRACE;
@@ -769,8 +769,8 @@ json_parse_object (JsonParser   *parser,
           priv->error_code = JSON_PARSER_ERROR_MISSING_COMMA;
 
           json_object_unref (object);
-          json_node_free (member);
-          json_node_free (priv->current_node);
+          json_node_unref (member);
+          json_node_unref (priv->current_node);
           priv->current_node = old_current;
 
           return G_TOKEN_COMMA;
diff --git a/json-glib/json-path.c b/json-glib/json-path.c
index 3ccf98f..4604cd9 100644
--- a/json-glib/json-path.c
+++ b/json-glib/json-path.c
@@ -936,7 +936,7 @@ walk_path_node (GList      *path,
  *
  * Return value: (transfer full): a newly-created #JsonNode of type
  *   %JSON_NODE_ARRAY containing an array of matching #JsonNodes.
- *   Use json_node_free() when done
+ *   Use json_node_unref() when done
  *
  * Since: 0.14
  */
@@ -976,7 +976,7 @@ json_path_match (JsonPath *path,
  *
  * Return value: (transfer full): a newly-created #JsonNode of type
  *   %JSON_NODE_ARRAY containing an array of matching #JsonNodes.
- *   Use json_node_free() when done
+ *   Use json_node_unref() when done
  *
  * Since: 0.14
  */
diff --git a/json-glib/json-reader.c b/json-glib/json-reader.c
index 8c552e5..afc2414 100644
--- a/json-glib/json-reader.c
+++ b/json-glib/json-reader.c
@@ -113,7 +113,7 @@ json_reader_finalize (GObject *gobject)
   JsonReaderPrivate *priv = JSON_READER (gobject)->priv;
 
   if (priv->root != NULL)
-    json_node_free (priv->root);
+    json_node_unref (priv->root);
 
   if (priv->error != NULL)
     g_clear_error (&priv->error);
@@ -258,7 +258,7 @@ json_reader_set_root (JsonReader *reader,
 
   if (priv->root != NULL)
     {
-      json_node_free (priv->root);
+      json_node_unref (priv->root);
       priv->root = NULL;
       priv->current_node = NULL;
       priv->previous_node = NULL;
diff --git a/json-glib/json-types-private.h b/json-glib/json-types-private.h
index 34a3160..8934e9a 100644
--- a/json-glib/json-types-private.h
+++ b/json-glib/json-types-private.h
@@ -28,6 +28,12 @@
 
 G_BEGIN_DECLS
 
+#define JSON_NODE_IS_VALID(n) \
+  ((n) != NULL && \
+   (n)->type >= JSON_NODE_OBJECT && \
+   (n)->type <= JSON_NODE_NULL && \
+   (n)->ref_count >= 1)
+
 typedef struct _JsonValue JsonValue;
 
 typedef enum {
@@ -43,7 +49,10 @@ struct _JsonNode
 {
   /*< private >*/
   JsonNodeType type;
+
+  volatile gint ref_count;
   gboolean immutable : 1;
+  gboolean allocated : 1;
 
   union {
     JsonObject *object;
@@ -54,8 +63,8 @@ struct _JsonNode
   JsonNode *parent;
 };
 
-#define JSON_VALUE_INIT                 { JSON_VALUE_INVALID, 1, { 0 } }
-#define JSON_VALUE_INIT_TYPE(t)         { (t), 1, { 0 } }
+#define JSON_VALUE_INIT                 { JSON_VALUE_INVALID, 1, FALSE, { 0 }, NULL }
+#define JSON_VALUE_INIT_TYPE(t)         { (t), 1, FALSE, { 0 }, NULL }
 #define JSON_VALUE_IS_VALID(v)          ((v) != NULL && (v)->type != JSON_VALUE_INVALID)
 #define JSON_VALUE_HOLDS(v,t)           ((v) != NULL && (v)->type == (t))
 #define JSON_VALUE_HOLDS_INT(v)         (JSON_VALUE_HOLDS((v), JSON_VALUE_INT))
diff --git a/json-glib/json-types.h b/json-glib/json-types.h
index 5f2a084..33180b4 100644
--- a/json-glib/json-types.h
+++ b/json-glib/json-types.h
@@ -213,6 +213,11 @@ JsonNode *            json_node_copy            (JsonNode     *node);
 JSON_AVAILABLE_IN_1_0
 void                  json_node_free            (JsonNode     *node);
 
+JSON_AVAILABLE_IN_1_2
+JsonNode *            json_node_ref             (JsonNode     *node);
+JSON_AVAILABLE_IN_1_2
+void                  json_node_unref           (JsonNode     *node);
+
 JSON_AVAILABLE_IN_1_0
 JsonNodeType          json_node_get_node_type   (JsonNode     *node);
 JSON_AVAILABLE_IN_1_0


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]