/* json-array.c - JSON array implementation * * This file is part of JSON-GLib * Copyright (C) 2007 OpenedHand Ltd. * Copyright (C) 2009 Intel Corp. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library. If not, see . * * Author: * Emmanuele Bassi */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "json-types-private.h" /* * SECTION:json-array * @short_description: a JSON array representation * * #JsonArray is the representation of the array type inside JSON. It contains * #JsonNodes, which may contain fundamental types, other arrays or * objects. * * Since arrays can be expensive, they are reference counted. You can control * the lifetime of a #JsonArray using json_array_ref() and json_array_unref(). * * To append an element, use json_array_add_element(). * To extract an element at a given index, use json_array_get_element(). * To retrieve the entire array in list form, use json_array_get_elements(). * To retrieve the length of the array, use json_array_get_length(). */ GType json_array_get_type (void) { static GType array_type = 0; if (G_UNLIKELY (!array_type)) array_type = g_boxed_type_register_static (g_intern_static_string ("JsonArray"), (GBoxedCopyFunc) json_array_ref, (GBoxedFreeFunc) json_array_unref); return array_type; } /* * json_array_new: * * Creates a new #JsonArray. * * Return value: the newly created #JsonArray */ JsonArray * json_array_new (void) { JsonArray *array; array = g_slice_new (JsonArray); array->ref_count = 1; array->elements = g_ptr_array_new (); return array; } /* * json_array_sized_new: * @n_elements: number of slots to pre-allocate * * Creates a new #JsonArray with @n_elements slots already allocated. * * Return value: the newly created #JsonArray */ JsonArray * json_array_sized_new (guint n_elements) { JsonArray *array; array = g_slice_new (JsonArray); array->ref_count = 1; array->elements = g_ptr_array_sized_new (n_elements); return array; } /* * json_array_ref: * @array: a #JsonArray * * Increase by one the reference count of a #JsonArray. * * Return value: the passed #JsonArray, with the reference count * increased by one. */ JsonArray * json_array_ref (JsonArray *array) { g_return_val_if_fail (array != NULL, NULL); g_return_val_if_fail (array->ref_count > 0, NULL); g_atomic_int_exchange_and_add (&array->ref_count, 1); return array; } /* * json_array_unref: * @array: a #JsonArray * * Decreases by one the reference count of a #JsonArray. If the * reference count reaches zero, the array is destroyed and all * its allocated resources are freed. */ void json_array_unref (JsonArray *array) { gint old_ref; g_return_if_fail (array != NULL); g_return_if_fail (array->ref_count > 0); old_ref = g_atomic_int_get (&array->ref_count); if (old_ref > 1) g_atomic_int_compare_and_exchange (&array->ref_count, old_ref, old_ref - 1); else { guint i; for (i = 0; i < array->elements->len; i++) json_node_free (g_ptr_array_index (array->elements, i)); g_ptr_array_free (array->elements, TRUE); array->elements = NULL; g_slice_free (JsonArray, array); } } /* * json_array_get_elements: * @array: a #JsonArray * * Gets the elements of a #JsonArray as a list of #JsonNodes. * * Return value: a #GList containing the elements of the array. The * contents of the list are owned by the array and should never be * modified or freed. Use g_list_free() on the returned list when * done using it */ GList * json_array_get_elements (JsonArray *array) { GList *retval; guint i; g_return_val_if_fail (array != NULL, NULL); retval = NULL; for (i = 0; i < array->elements->len; i++) retval = g_list_prepend (retval, g_ptr_array_index (array->elements, i)); return g_list_reverse (retval); } /* * json_array_dup_element: * @array: a #JsonArray * @index_: the index of the element to retrieve * * Retrieves a copy of the #JsonNode containing the value of the * element at @index_ inside a #JsonArray * * Return value: a copy of the #JsonNode at the requested index. * Use json_node_free() when done. * * Since: 0.6 */ JsonNode * json_array_dup_element (JsonArray *array, guint index_) { JsonNode *retval; g_return_val_if_fail (array != NULL, NULL); g_return_val_if_fail (index_ < array->elements->len, NULL); retval = json_array_get_element (array, index_); if (!retval) return NULL; return json_node_copy (retval); } /* * json_array_get_element: * @array: a #JsonArray * @index_: the index of the element to retrieve * * Retrieves the #JsonNode containing the value of the element at @index_ * inside a #JsonArray. * * Return value: a pointer to the #JsonNode at the requested index */ JsonNode * json_array_get_element (JsonArray *array, guint index_) { g_return_val_if_fail (array != NULL, NULL); g_return_val_if_fail (index_ < array->elements->len, NULL); return g_ptr_array_index (array->elements, index_); } /* * json_array_get_int_element: * @array: a #JsonArray * @index_: the index of the element to retrieve * * Conveniently retrieves the integer value of the element at @index_ * inside @array * * See also: json_array_get_element(), json_node_get_int() * * Return value: the integer value * * Since: 0.8 */ gint64 json_array_get_int_element (JsonArray *array, guint index_) { JsonNode *node; g_return_val_if_fail (array != NULL, 0); g_return_val_if_fail (index_ < array->elements->len, 0); node = g_ptr_array_index (array->elements, index_); g_return_val_if_fail (node != NULL, 0); g_return_val_if_fail (JSON_NODE_TYPE (node) == JSON_NODE_VALUE, 0); return json_node_get_int (node); } /* * json_array_get_double_element: * @array: a #JsonArray * @index_: the index of the element to retrieve * * Conveniently retrieves the floating point value of the element at * @index_ inside @array * * See also: json_array_get_element(), json_node_get_double() * * Return value: the floating point value * * Since: 0.8 */ gdouble json_array_get_double_element (JsonArray *array, guint index_) { JsonNode *node; g_return_val_if_fail (array != NULL, 0.0); g_return_val_if_fail (index_ < array->elements->len, 0.0); node = g_ptr_array_index (array->elements, index_); g_return_val_if_fail (node != NULL, 0.0); g_return_val_if_fail (JSON_NODE_TYPE (node) == JSON_NODE_VALUE, 0.0); return json_node_get_double (node); } /* * json_array_get_boolean_element: * @array: a #JsonArray * @index_: the index of the element to retrieve * * Conveniently retrieves the boolean value of the element at @index_ * inside @array * * See also: json_array_get_element(), json_node_get_boolean() * * Return value: the integer value * * Since: 0.8 */ gboolean json_array_get_boolean_element (JsonArray *array, guint index_) { JsonNode *node; g_return_val_if_fail (array != NULL, FALSE); g_return_val_if_fail (index_ < array->elements->len, FALSE); node = g_ptr_array_index (array->elements, index_); g_return_val_if_fail (node != NULL, FALSE); g_return_val_if_fail (JSON_NODE_TYPE (node) == JSON_NODE_VALUE, FALSE); return json_node_get_boolean (node); } /* * json_array_get_string_element: * @array: a #JsonArray * @index_: the index of the element to retrieve * * Conveniently retrieves the string value of the element at @index_ * inside @array * * See also: json_array_get_element(), json_node_get_string() * * Return value: the string value; the returned string is owned by * the #JsonArray and should not be modified or freed * * Since: 0.8 */ G_CONST_RETURN gchar * json_array_get_string_element (JsonArray *array, guint index_) { JsonNode *node; g_return_val_if_fail (array != NULL, NULL); g_return_val_if_fail (index_ < array->elements->len, NULL); node = g_ptr_array_index (array->elements, index_); g_return_val_if_fail (node != NULL, NULL); g_return_val_if_fail (JSON_NODE_HOLDS_VALUE (node) || JSON_NODE_HOLDS_NULL (node), NULL); if (JSON_NODE_HOLDS_NULL (node)) return NULL; return json_node_get_string (node); } /* * json_array_get_null_element: * @array: a #JsonArray * @index_: the index of the element to retrieve * * Conveniently retrieves whether the element at @index_ is set to null * * See also: json_array_get_element(), JSON_NODE_TYPE(), %JSON_NODE_NULL * * Return value: %TRUE if the element is null * * Since: 0.8 */ gboolean json_array_get_null_element (JsonArray *array, guint index_) { JsonNode *node; g_return_val_if_fail (array != NULL, FALSE); g_return_val_if_fail (index_ < array->elements->len, FALSE); node = g_ptr_array_index (array->elements, index_); g_return_val_if_fail (node != NULL, FALSE); return JSON_NODE_TYPE (node) == JSON_NODE_NULL; } /* * json_array_get_array_element: * @array: a #JsonArray * @index_: the index of the element to retrieve * * Conveniently retrieves the array from the element at @index_ * inside @array * * See also: json_array_get_element(), json_node_get_array() * * Return value: the array * * Since: 0.8 */ JsonArray * json_array_get_array_element (JsonArray *array, guint index_) { JsonNode *node; g_return_val_if_fail (array != NULL, NULL); g_return_val_if_fail (index_ < array->elements->len, NULL); node = g_ptr_array_index (array->elements, index_); g_return_val_if_fail (node != NULL, NULL); g_return_val_if_fail (JSON_NODE_HOLDS_ARRAY (node) || JSON_NODE_HOLDS_NULL (node), NULL); if (JSON_NODE_HOLDS_NULL (node)) return NULL; return json_node_get_array (node); } /* * json_array_get_object_element: * @array: a #JsonArray * @index_: the index of the element to retrieve * * Conveniently retrieves the object from the element at @index_ * inside @array * * See also: json_array_get_element(), json_node_get_object() * * Return value: the object * * Since: 0.8 */ JsonObject * json_array_get_object_element (JsonArray *array, guint index_) { JsonNode *node; g_return_val_if_fail (array != NULL, NULL); g_return_val_if_fail (index_ < array->elements->len, NULL); node = g_ptr_array_index (array->elements, index_); g_return_val_if_fail (node != NULL, NULL); g_return_val_if_fail (JSON_NODE_HOLDS_OBJECT (node) || JSON_NODE_HOLDS_NULL (node), NULL); if (JSON_NODE_HOLDS_NULL (node)) return NULL; return json_node_get_object (node); } /* * json_array_get_length: * @array: a #JsonArray * * Retrieves the length of a #JsonArray * * Return value: the length of the array */ guint json_array_get_length (JsonArray *array) { g_return_val_if_fail (array != NULL, 0); return array->elements->len; } /* * json_array_add_element: * @array: a #JsonArray * @node: a #JsonNode * * Appends @node inside @array. The array will take ownership of the * #JsonNode. */ void json_array_add_element (JsonArray *array, JsonNode *node) { g_return_if_fail (array != NULL); g_return_if_fail (node != NULL); g_ptr_array_add (array->elements, node); } /* * json_array_add_int_element: * @array: a #JsonArray * @value: an integer value * * Conveniently adds an integer @value into @array * * See also: json_array_add_element(), json_node_set_int() * * Since: 0.8 */ void json_array_add_int_element (JsonArray *array, gint64 value) { JsonNode *node; g_return_if_fail (array != NULL); node = json_node_new (JSON_NODE_VALUE); json_node_set_int (node, value); g_ptr_array_add (array->elements, node); } /* * json_array_add_double_element: * @array: a #JsonArray * @value: a floating point value * * Conveniently adds a floating point @value into @array * * See also: json_array_add_element(), json_node_set_double() * * Since: 0.8 */ void json_array_add_double_element (JsonArray *array, gdouble value) { JsonNode *node; g_return_if_fail (array != NULL); node = json_node_new (JSON_NODE_VALUE); json_node_set_double (node, value); g_ptr_array_add (array->elements, node); } /* * json_array_add_boolean_element: * @array: a #JsonArray * @value: a boolean value * * Conveniently adds a boolean @value into @array * * See also: json_array_add_element(), json_node_set_boolean() * * Since: 0.8 */ void json_array_add_boolean_element (JsonArray *array, gboolean value) { JsonNode *node; g_return_if_fail (array != NULL); node = json_node_new (JSON_NODE_VALUE); json_node_set_boolean (node, value); g_ptr_array_add (array->elements, node); } /* * json_array_add_string_element: * @array: a #JsonArray * @value: a string value * * Conveniently adds a string @value into @array * * See also: json_array_add_element(), json_node_set_string() * * Since: 0.8 */ void json_array_add_string_element (JsonArray *array, const gchar *value) { JsonNode *node; g_return_if_fail (array != NULL); g_return_if_fail (value != NULL); if (value != NULL) { node = json_node_new (JSON_NODE_VALUE); json_node_set_string (node, value); } else node = json_node_new (JSON_NODE_NULL); g_ptr_array_add (array->elements, node); } /* * json_array_add_null_element: * @array: a #JsonArray * * Conveniently adds a null element into @array * * See also: json_array_add_element(), %JSON_NODE_NULL * * Since: 0.8 */ void json_array_add_null_element (JsonArray *array) { JsonNode *node; g_return_if_fail (array != NULL); node = json_node_new (JSON_NODE_NULL); g_ptr_array_add (array->elements, node); } /* * json_array_add_array_element: * @array: a #JsonArray * @value: a #JsonArray * * Conveniently adds an array into @array. The @array takes ownership * of the newly added #JsonArray * * See also: json_array_add_element(), json_node_take_array() * * Since: 0.8 */ void json_array_add_array_element (JsonArray *array, JsonArray *value) { JsonNode *node; g_return_if_fail (array != NULL); g_return_if_fail (value != NULL); if (value != NULL) { node = json_node_new (JSON_NODE_ARRAY); json_node_take_array (node, value); } else node = json_node_new (JSON_NODE_NULL); g_ptr_array_add (array->elements, node); } /* * json_array_add_object_element: * @array: a #JsonArray * @value: a #JsonObject * * Conveniently adds an object into @array. The @array takes ownership * of the newly added #JsonObject * * See also: json_array_add_element(), json_node_take_object() * * Since: 0.8 */ void json_array_add_object_element (JsonArray *array, JsonObject *value) { JsonNode *node; g_return_if_fail (array != NULL); g_return_if_fail (value != NULL); if (value != NULL) { node = json_node_new (JSON_NODE_OBJECT); json_node_take_object (node, value); } else node = json_node_new (JSON_NODE_NULL); g_ptr_array_add (array->elements, node); } /* * json_array_remove_element: * @array: a #JsonArray * @index_: the position of the element to be removed * * Removes the #JsonNode inside @array at @index_ freeing its allocated * resources. */ void json_array_remove_element (JsonArray *array, guint index_) { 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_array_foreach_element: * @array: a #JsonArray * @func: the function to be called on each element * @data: data to be passed to the function * * Iterates over all elements of @array and calls @func on * each one of them. * * It is safe to change the value of a #JsonNode of the @array * from within the iterator @func, but it is not safe to add or * remove elements from the @array. * * Since: 0.8 */ void json_array_foreach_element (JsonArray *array, JsonArrayForeach func, gpointer data) { gint i; g_return_if_fail (array != NULL); g_return_if_fail (func != NULL); for (i = 0; i < array->elements->len; i++) { JsonNode *element_node; element_node = g_ptr_array_index (array->elements, i); (* func) (array, i, element_node, data); } }