1 /* json-array.c - JSON array implementation
2  *
3  * This file is part of JSON-GLib
4  * Copyright (C) 2007  OpenedHand Ltd.
5  * Copyright (C) 2009  Intel Corp.
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library. If not, see <http://www.gnu.org/licenses/>.
19  *
20  * Author:
21  *   Emmanuele Bassi  <ebassi@linux.intel.com>
22  */
23 
24 #include "config.h"
25 
26 #include "json-types-private.h"
27 
28 /**
29  * SECTION:json-array
30  * @short_description: a JSON array representation
31  *
32  * #JsonArray is the representation of the array type inside JSON. It contains
33  * #JsonNode elements, which may contain fundamental types, other arrays or
34  * objects.
35  *
36  * Since arrays can be expensive, they are reference counted. You can control
37  * the lifetime of a #JsonArray using json_array_ref() and json_array_unref().
38  *
39  * To append an element, use json_array_add_element().
40  * To extract an element at a given index, use json_array_get_element().
41  * To retrieve the entire array in list form, use json_array_get_elements().
42  * To retrieve the length of the array, use json_array_get_length().
43  */
44 
45 G_DEFINE_BOXED_TYPE (JsonArray, json_array, json_array_ref, json_array_unref);
46 
47 /**
48  * json_array_new: (constructor)
49  *
50  * Creates a new #JsonArray.
51  *
52  * Return value: (transfer full): the newly created #JsonArray
53  */
54 JsonArray *
json_array_new(void)55 json_array_new (void)
56 {
57   JsonArray *array;
58 
59   array = g_slice_new0 (JsonArray);
60 
61   array->ref_count = 1;
62   array->elements = g_ptr_array_new ();
63 
64   return array;
65 }
66 
67 /**
68  * json_array_sized_new: (constructor)
69  * @n_elements: number of slots to pre-allocate
70  *
71  * Creates a new #JsonArray with @n_elements slots already allocated.
72  *
73  * Return value: (transfer full): the newly created #JsonArray
74  */
75 JsonArray *
json_array_sized_new(guint n_elements)76 json_array_sized_new (guint n_elements)
77 {
78   JsonArray *array;
79 
80   array = g_slice_new0 (JsonArray);
81 
82   array->ref_count = 1;
83   array->elements = g_ptr_array_sized_new (n_elements);
84 
85   return array;
86 }
87 
88 /**
89  * json_array_ref:
90  * @array: a #JsonArray
91  *
92  * Increase by one the reference count of a #JsonArray.
93  *
94  * Return value: (transfer none): the passed #JsonArray, with the reference count
95  *   increased by one.
96  */
97 JsonArray *
json_array_ref(JsonArray * array)98 json_array_ref (JsonArray *array)
99 {
100   g_return_val_if_fail (array != NULL, NULL);
101   g_return_val_if_fail (array->ref_count > 0, NULL);
102 
103   array->ref_count++;
104 
105   return array;
106 }
107 
108 /**
109  * json_array_unref:
110  * @array: a #JsonArray
111  *
112  * Decreases by one the reference count of a #JsonArray. If the
113  * reference count reaches zero, the array is destroyed and all
114  * its allocated resources are freed.
115  */
116 void
json_array_unref(JsonArray * array)117 json_array_unref (JsonArray *array)
118 {
119   g_return_if_fail (array != NULL);
120   g_return_if_fail (array->ref_count > 0);
121 
122   if (--array->ref_count == 0)
123     {
124       guint i;
125 
126       for (i = 0; i < array->elements->len; i++)
127         json_node_unref (g_ptr_array_index (array->elements, i));
128 
129       g_ptr_array_free (array->elements, TRUE);
130       array->elements = NULL;
131 
132       g_slice_free (JsonArray, array);
133     }
134 }
135 
136 /**
137  * json_array_seal:
138  * @array: a #JsonArray
139  *
140  * Seals the #JsonArray, making it immutable to further changes. This will
141  * recursively seal all elements in the array too.
142  *
143  * If the @array is already immutable, this is a no-op.
144  *
145  * Since: 1.2
146  */
147 void
json_array_seal(JsonArray * array)148 json_array_seal (JsonArray *array)
149 {
150   guint i;
151 
152   g_return_if_fail (array != NULL);
153   g_return_if_fail (array->ref_count > 0);
154 
155   if (array->immutable)
156     return;
157 
158   /* Propagate to all members. */
159   for (i = 0; i < array->elements->len; i++)
160     json_node_seal (g_ptr_array_index (array->elements, i));
161 
162   array->immutable_hash = json_array_hash (array);
163   array->immutable = TRUE;
164 }
165 
166 /**
167  * json_array_is_immutable:
168  * @array: a #JsonArray
169  *
170  * Check whether the given @array has been marked as immutable by calling
171  * json_array_seal() on it.
172  *
173  * Since: 1.2
174  * Returns: %TRUE if the @array is immutable
175  */
176 gboolean
json_array_is_immutable(JsonArray * array)177 json_array_is_immutable (JsonArray *array)
178 {
179   g_return_val_if_fail (array != NULL, FALSE);
180   g_return_val_if_fail (array->ref_count > 0, FALSE);
181 
182   return array->immutable;
183 }
184 
185 /**
186  * json_array_get_elements:
187  * @array: a #JsonArray
188  *
189  * Gets the elements of a #JsonArray as a list of #JsonNode instances.
190  *
191  * Return value: (element-type JsonNode) (transfer container): a #GList
192  *   containing the elements of the array. The contents of the list are
193  *   owned by the array and should never be modified or freed. Use
194  *   g_list_free() on the returned list when done using it
195  */
196 GList *
json_array_get_elements(JsonArray * array)197 json_array_get_elements (JsonArray *array)
198 {
199   GList *retval;
200   guint i;
201 
202   g_return_val_if_fail (array != NULL, NULL);
203 
204   retval = NULL;
205   for (i = 0; i < array->elements->len; i++)
206     retval = g_list_prepend (retval,
207                              g_ptr_array_index (array->elements, i));
208 
209   return g_list_reverse (retval);
210 }
211 
212 /**
213  * json_array_dup_element:
214  * @array: a #JsonArray
215  * @index_: the index of the element to retrieve
216  *
217  * Retrieves a copy of the #JsonNode containing the value of the
218  * element at @index_ inside a #JsonArray
219  *
220  * Return value: (transfer full): a copy of the #JsonNode at the requested
221  *   index. Use json_node_unref() when done.
222  *
223  * Since: 0.6
224  */
225 JsonNode *
json_array_dup_element(JsonArray * array,guint index_)226 json_array_dup_element (JsonArray *array,
227                         guint      index_)
228 {
229   JsonNode *retval;
230 
231   g_return_val_if_fail (array != NULL, NULL);
232   g_return_val_if_fail (index_ < array->elements->len, NULL);
233 
234   retval = json_array_get_element (array, index_);
235   if (!retval)
236     return NULL;
237 
238   return json_node_copy (retval);
239 }
240 
241 /**
242  * json_array_get_element:
243  * @array: a #JsonArray
244  * @index_: the index of the element to retrieve
245  *
246  * Retrieves the #JsonNode containing the value of the element at @index_
247  * inside a #JsonArray.
248  *
249  * Return value: (transfer none): a pointer to the #JsonNode at the requested index
250  */
251 JsonNode *
json_array_get_element(JsonArray * array,guint index_)252 json_array_get_element (JsonArray *array,
253                         guint      index_)
254 {
255   g_return_val_if_fail (array != NULL, NULL);
256   g_return_val_if_fail (index_ < array->elements->len, NULL);
257 
258   return g_ptr_array_index (array->elements, index_);
259 }
260 
261 /**
262  * json_array_get_int_element:
263  * @array: a #JsonArray
264  * @index_: the index of the element to retrieve
265  *
266  * Conveniently retrieves the integer value of the element at @index_
267  * inside @array
268  *
269  * See also: json_array_get_element(), json_node_get_int()
270  *
271  * Return value: the integer value
272  *
273  * Since: 0.8
274  */
275 gint64
json_array_get_int_element(JsonArray * array,guint index_)276 json_array_get_int_element (JsonArray *array,
277                             guint      index_)
278 {
279   JsonNode *node;
280 
281   g_return_val_if_fail (array != NULL, 0);
282   g_return_val_if_fail (index_ < array->elements->len, 0);
283 
284   node = g_ptr_array_index (array->elements, index_);
285   g_return_val_if_fail (node != NULL, 0);
286   g_return_val_if_fail (JSON_NODE_TYPE (node) == JSON_NODE_VALUE, 0);
287 
288   return json_node_get_int (node);
289 }
290 
291 /**
292  * json_array_get_double_element:
293  * @array: a #JsonArray
294  * @index_: the index of the element to retrieve
295  *
296  * Conveniently retrieves the floating point value of the element at
297  * @index_ inside @array
298  *
299  * See also: json_array_get_element(), json_node_get_double()
300  *
301  * Return value: the floating point value
302  *
303  * Since: 0.8
304  */
305 gdouble
json_array_get_double_element(JsonArray * array,guint index_)306 json_array_get_double_element (JsonArray *array,
307                                guint      index_)
308 {
309   JsonNode *node;
310 
311   g_return_val_if_fail (array != NULL, 0.0);
312   g_return_val_if_fail (index_ < array->elements->len, 0.0);
313 
314   node = g_ptr_array_index (array->elements, index_);
315   g_return_val_if_fail (node != NULL, 0.0);
316   g_return_val_if_fail (JSON_NODE_TYPE (node) == JSON_NODE_VALUE, 0.0);
317 
318   return json_node_get_double (node);
319 }
320 
321 /**
322  * json_array_get_boolean_element:
323  * @array: a #JsonArray
324  * @index_: the index of the element to retrieve
325  *
326  * Conveniently retrieves the boolean value of the element at @index_
327  * inside @array
328  *
329  * See also: json_array_get_element(), json_node_get_boolean()
330  *
331  * Return value: the integer value
332  *
333  * Since: 0.8
334  */
335 gboolean
json_array_get_boolean_element(JsonArray * array,guint index_)336 json_array_get_boolean_element (JsonArray *array,
337                                 guint      index_)
338 {
339   JsonNode *node;
340 
341   g_return_val_if_fail (array != NULL, FALSE);
342   g_return_val_if_fail (index_ < array->elements->len, FALSE);
343 
344   node = g_ptr_array_index (array->elements, index_);
345   g_return_val_if_fail (node != NULL, FALSE);
346   g_return_val_if_fail (JSON_NODE_TYPE (node) == JSON_NODE_VALUE, FALSE);
347 
348   return json_node_get_boolean (node);
349 }
350 
351 /**
352  * json_array_get_string_element:
353  * @array: a #JsonArray
354  * @index_: the index of the element to retrieve
355  *
356  * Conveniently retrieves the string value of the element at @index_
357  * inside @array
358  *
359  * See also: json_array_get_element(), json_node_get_string()
360  *
361  * Return value: the string value; the returned string is owned by
362  *   the #JsonArray and should not be modified or freed
363  *
364  * Since: 0.8
365  */
366 const gchar *
json_array_get_string_element(JsonArray * array,guint index_)367 json_array_get_string_element (JsonArray *array,
368                                guint      index_)
369 {
370   JsonNode *node;
371 
372   g_return_val_if_fail (array != NULL, NULL);
373   g_return_val_if_fail (index_ < array->elements->len, NULL);
374 
375   node = g_ptr_array_index (array->elements, index_);
376   g_return_val_if_fail (node != NULL, NULL);
377   g_return_val_if_fail (JSON_NODE_HOLDS_VALUE (node) || JSON_NODE_HOLDS_NULL (node), NULL);
378 
379   if (JSON_NODE_HOLDS_NULL (node))
380     return NULL;
381 
382   return json_node_get_string (node);
383 }
384 
385 /**
386  * json_array_get_null_element:
387  * @array: a #JsonArray
388  * @index_: the index of the element to retrieve
389  *
390  * Conveniently retrieves whether the element at @index_ is set to null
391  *
392  * See also: json_array_get_element(), JSON_NODE_TYPE(), %JSON_NODE_NULL
393  *
394  * Return value: %TRUE if the element is null
395  *
396  * Since: 0.8
397  */
398 gboolean
json_array_get_null_element(JsonArray * array,guint index_)399 json_array_get_null_element (JsonArray *array,
400                              guint      index_)
401 {
402   JsonNode *node;
403 
404   g_return_val_if_fail (array != NULL, FALSE);
405   g_return_val_if_fail (index_ < array->elements->len, FALSE);
406 
407   node = g_ptr_array_index (array->elements, index_);
408   g_return_val_if_fail (node != NULL, FALSE);
409 
410   if (JSON_NODE_HOLDS_NULL (node))
411     return TRUE;
412 
413   if (JSON_NODE_HOLDS_ARRAY (node))
414     return json_node_get_array (node) == NULL;
415 
416   if (JSON_NODE_HOLDS_OBJECT (node))
417     return json_node_get_object (node) == NULL;
418 
419   return FALSE;
420 }
421 
422 /**
423  * json_array_get_array_element:
424  * @array: a #JsonArray
425  * @index_: the index of the element to retrieve
426  *
427  * Conveniently retrieves the array from the element at @index_
428  * inside @array
429  *
430  * See also: json_array_get_element(), json_node_get_array()
431  *
432  * Return value: (transfer none): the array
433  *
434  * Since: 0.8
435  */
436 JsonArray *
json_array_get_array_element(JsonArray * array,guint index_)437 json_array_get_array_element (JsonArray *array,
438                               guint      index_)
439 {
440   JsonNode *node;
441 
442   g_return_val_if_fail (array != NULL, NULL);
443   g_return_val_if_fail (index_ < array->elements->len, NULL);
444 
445   node = g_ptr_array_index (array->elements, index_);
446   g_return_val_if_fail (node != NULL, NULL);
447   g_return_val_if_fail (JSON_NODE_HOLDS_ARRAY (node) || JSON_NODE_HOLDS_NULL (node), NULL);
448 
449   if (JSON_NODE_HOLDS_NULL (node))
450     return NULL;
451 
452   return json_node_get_array (node);
453 }
454 
455 /**
456  * json_array_get_object_element:
457  * @array: a #JsonArray
458  * @index_: the index of the element to retrieve
459  *
460  * Conveniently retrieves the object from the element at @index_
461  * inside @array
462  *
463  * See also: json_array_get_element(), json_node_get_object()
464  *
465  * Return value: (transfer none): the object
466  *
467  * Since: 0.8
468  */
469 JsonObject *
json_array_get_object_element(JsonArray * array,guint index_)470 json_array_get_object_element (JsonArray *array,
471                                guint      index_)
472 {
473   JsonNode *node;
474 
475   g_return_val_if_fail (array != NULL, NULL);
476   g_return_val_if_fail (index_ < array->elements->len, NULL);
477 
478   node = g_ptr_array_index (array->elements, index_);
479   g_return_val_if_fail (node != NULL, NULL);
480   g_return_val_if_fail (JSON_NODE_HOLDS_OBJECT (node) || JSON_NODE_HOLDS_NULL (node), NULL);
481 
482   if (JSON_NODE_HOLDS_NULL (node))
483     return NULL;
484 
485   return json_node_get_object (node);
486 }
487 
488 /**
489  * json_array_get_length:
490  * @array: a #JsonArray
491  *
492  * Retrieves the length of a #JsonArray
493  *
494  * Return value: the length of the array
495  */
496 guint
json_array_get_length(JsonArray * array)497 json_array_get_length (JsonArray *array)
498 {
499   g_return_val_if_fail (array != NULL, 0);
500 
501   return array->elements->len;
502 }
503 
504 /**
505  * json_array_add_element:
506  * @array: a #JsonArray
507  * @node: (transfer full): a #JsonNode
508  *
509  * Appends @node inside @array. The array will take ownership of the
510  * #JsonNode.
511  */
512 void
json_array_add_element(JsonArray * array,JsonNode * node)513 json_array_add_element (JsonArray *array,
514                         JsonNode  *node)
515 {
516   g_return_if_fail (array != NULL);
517   g_return_if_fail (node != NULL);
518 
519   g_ptr_array_add (array->elements, node);
520 }
521 
522 /**
523  * json_array_add_int_element:
524  * @array: a #JsonArray
525  * @value: an integer value
526  *
527  * Conveniently adds an integer @value into @array
528  *
529  * See also: json_array_add_element(), json_node_set_int()
530  *
531  * Since: 0.8
532  */
533 void
json_array_add_int_element(JsonArray * array,gint64 value)534 json_array_add_int_element (JsonArray *array,
535                             gint64     value)
536 {
537   g_return_if_fail (array != NULL);
538 
539   json_array_add_element (array, json_node_init_int (json_node_alloc (), value));
540 }
541 
542 /**
543  * json_array_add_double_element:
544  * @array: a #JsonArray
545  * @value: a floating point value
546  *
547  * Conveniently adds a floating point @value into @array
548  *
549  * See also: json_array_add_element(), json_node_set_double()
550  *
551  * Since: 0.8
552  */
553 void
json_array_add_double_element(JsonArray * array,gdouble value)554 json_array_add_double_element (JsonArray *array,
555                                gdouble    value)
556 {
557   g_return_if_fail (array != NULL);
558 
559   json_array_add_element (array, json_node_init_double (json_node_alloc (), value));
560 }
561 
562 /**
563  * json_array_add_boolean_element:
564  * @array: a #JsonArray
565  * @value: a boolean value
566  *
567  * Conveniently adds a boolean @value into @array
568  *
569  * See also: json_array_add_element(), json_node_set_boolean()
570  *
571  * Since: 0.8
572  */
573 void
json_array_add_boolean_element(JsonArray * array,gboolean value)574 json_array_add_boolean_element (JsonArray *array,
575                                 gboolean   value)
576 {
577   g_return_if_fail (array != NULL);
578 
579   json_array_add_element (array, json_node_init_boolean (json_node_alloc (), value));
580 }
581 
582 /**
583  * json_array_add_string_element:
584  * @array: a #JsonArray
585  * @value: a string value
586  *
587  * Conveniently adds a string @value into @array
588  *
589  * See also: json_array_add_element(), json_node_set_string()
590  *
591  * Since: 0.8
592  */
593 void
json_array_add_string_element(JsonArray * array,const gchar * value)594 json_array_add_string_element (JsonArray   *array,
595                                const gchar *value)
596 {
597   JsonNode *node;
598 
599   g_return_if_fail (array != NULL);
600 
601   node = json_node_alloc ();
602 
603   if (value != NULL)
604     json_node_init_string (node, value);
605   else
606     json_node_init_null (node);
607 
608   json_array_add_element (array, node);
609 }
610 
611 /**
612  * json_array_add_null_element:
613  * @array: a #JsonArray
614  *
615  * Conveniently adds a null element into @array
616  *
617  * See also: json_array_add_element(), %JSON_NODE_NULL
618  *
619  * Since: 0.8
620  */
621 void
json_array_add_null_element(JsonArray * array)622 json_array_add_null_element (JsonArray *array)
623 {
624   g_return_if_fail (array != NULL);
625 
626   json_array_add_element (array, json_node_init_null (json_node_alloc ()));
627 }
628 
629 /**
630  * json_array_add_array_element:
631  * @array: a #JsonArray
632  * @value: (allow-none) (transfer full): a #JsonArray
633  *
634  * Conveniently adds an array into @array. The @array takes ownership
635  * of the newly added #JsonArray
636  *
637  * See also: json_array_add_element(), json_node_take_array()
638  *
639  * Since: 0.8
640  */
641 void
json_array_add_array_element(JsonArray * array,JsonArray * value)642 json_array_add_array_element (JsonArray *array,
643                               JsonArray *value)
644 {
645   JsonNode *node;
646 
647   g_return_if_fail (array != NULL);
648 
649   node = json_node_alloc ();
650 
651   if (value != NULL)
652     {
653       json_node_init_array (node, value);
654       json_array_unref (value);
655     }
656   else
657     json_node_init_null (node);
658 
659   json_array_add_element (array, node);
660 }
661 
662 /**
663  * json_array_add_object_element:
664  * @array: a #JsonArray
665  * @value: (transfer full): a #JsonObject
666  *
667  * Conveniently adds an object into @array. The @array takes ownership
668  * of the newly added #JsonObject
669  *
670  * See also: json_array_add_element(), json_node_take_object()
671  *
672  * Since: 0.8
673  */
674 void
json_array_add_object_element(JsonArray * array,JsonObject * value)675 json_array_add_object_element (JsonArray  *array,
676                                JsonObject *value)
677 {
678   JsonNode *node;
679 
680   g_return_if_fail (array != NULL);
681 
682   node = json_node_alloc ();
683 
684   if (value != NULL)
685     {
686       json_node_init_object (node, value);
687       json_object_unref (value);
688     }
689   else
690     json_node_init_null (node);
691 
692   json_array_add_element (array, node);
693 }
694 
695 /**
696  * json_array_remove_element:
697  * @array: a #JsonArray
698  * @index_: the position of the element to be removed
699  *
700  * Removes the #JsonNode inside @array at @index_ freeing its allocated
701  * resources.
702  */
703 void
json_array_remove_element(JsonArray * array,guint index_)704 json_array_remove_element (JsonArray *array,
705                            guint      index_)
706 {
707   g_return_if_fail (array != NULL);
708   g_return_if_fail (index_ < array->elements->len);
709 
710   json_node_unref (g_ptr_array_remove_index (array->elements, index_));
711 }
712 
713 /**
714  * json_array_foreach_element:
715  * @array: a #JsonArray
716  * @func: (scope call): the function to be called on each element
717  * @data: (closure): data to be passed to the function
718  *
719  * Iterates over all elements of @array and calls @func on
720  * each one of them.
721  *
722  * It is safe to change the value of a #JsonNode of the @array
723  * from within the iterator @func, but it is not safe to add or
724  * remove elements from the @array.
725  *
726  * Since: 0.8
727  */
728 void
json_array_foreach_element(JsonArray * array,JsonArrayForeach func,gpointer data)729 json_array_foreach_element (JsonArray        *array,
730                             JsonArrayForeach  func,
731                             gpointer          data)
732 {
733   gint i;
734 
735   g_return_if_fail (array != NULL);
736   g_return_if_fail (func != NULL);
737 
738   for (i = 0; i < array->elements->len; i++)
739     {
740       JsonNode *element_node;
741 
742       element_node = g_ptr_array_index (array->elements, i);
743 
744       (* func) (array, i, element_node, data);
745     }
746 }
747 
748 /**
749  * json_array_hash:
750  * @key: (type JsonArray): a JSON array to hash
751  *
752  * Calculate a hash value for the given @key (a #JsonArray).
753  *
754  * The hash is calculated over the array and all its elements, recursively. If
755  * the array is immutable, this is a fast operation; otherwise, it scales
756  * proportionally with the length of the array.
757  *
758  * Returns: hash value for @key
759  * Since: 1.2
760  */
761 guint
json_array_hash(gconstpointer key)762 json_array_hash (gconstpointer key)
763 {
764   JsonArray *array;  /* unowned */
765   guint hash = 0;
766   guint i;
767 
768   g_return_val_if_fail (key != NULL, 0);
769 
770   array = (JsonArray *) key;
771 
772   /* If the array is immutable, we can use the calculated hash. */
773   if (array->immutable)
774     return array->immutable_hash;
775 
776   /* Otherwise, calculate the hash. */
777   for (i = 0; i < array->elements->len; i++)
778     {
779       JsonNode *node = g_ptr_array_index (array->elements, i);
780       hash ^= (i ^ json_node_hash (node));
781     }
782 
783   return hash;
784 }
785 
786 /**
787  * json_array_equal:
788  * @a: (type JsonArray): a JSON array
789  * @b: (type JsonArray): another JSON array
790  *
791  * Check whether @a and @b are equal #JsonArrays, meaning they have the same
792  * number of elements, and the values of elements in corresponding positions
793  * are equal.
794  *
795  * Returns: %TRUE if @a and @b are equal; %FALSE otherwise
796  * Since: 1.2
797  */
798 gboolean
json_array_equal(gconstpointer a,gconstpointer b)799 json_array_equal (gconstpointer a,
800                   gconstpointer b)
801 {
802   JsonArray *array_a, *array_b;  /* unowned */
803   guint length_a, length_b, i;
804 
805   g_return_val_if_fail (a != NULL, FALSE);
806   g_return_val_if_fail (b != NULL, FALSE);
807 
808   array_a = (JsonArray *) a;
809   array_b = (JsonArray *) b;
810 
811   /* Identity comparison. */
812   if (array_a == array_b)
813     return TRUE;
814 
815   /* Check lengths. */
816   length_a = json_array_get_length (array_a);
817   length_b = json_array_get_length (array_b);
818 
819   if (length_a != length_b)
820     return FALSE;
821 
822   /* Check elements. */
823   for (i = 0; i < length_a; i++)
824     {
825       JsonNode *child_a, *child_b;  /* unowned */
826 
827       child_a = json_array_get_element (array_a, i);
828       child_b = json_array_get_element (array_b, i);
829 
830       if (!json_node_equal (child_a, child_b))
831         return FALSE;
832     }
833 
834   return TRUE;
835 }
836