* @file json_object_iterator.h
*
* Copyright (c) 2009-2012 Hewlett-Packard Development Company, L.P.
+* Copyright (c) 2026 Eric Hawicz
*
* This library is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See COPYING for details.
struct json_object_iterator
{
const void *opaque_;
+ // These could be used to make an interator that fails "faster"
+ // in the face of certain changes to the underlying object, but
+ // would still be vulnerable to skipping entries.
+ // Changing this structure size is an ABI change
+ // const lh_table *table;
+ // size_t begin_size;
};
/**
*/
JSON_EXPORT struct json_object_iterator json_object_iter_init_default(void);
-/** Retrieves an iterator to the first pair of the JSON Object.
- *
- * @warning Any modification of the underlying pair invalidates all
- * iterators to that pair.
+/** Retrieves an iterator to the first key/value pair of the JSON Object.
+ *
+ * @warning Any modification of the fields present on the object
+ * invalidates all iterators on that object, regardless of
+ * what key/value pair they are pointing to, other than the
+ * end iterator.
+ * Modifications include adding or removing any pair, even if
+ * set of keys appears unchanged after the modification.
+ * Modifying *values* is allowed, including replacing a value
+ * by calling json_object_add(), provided the key already exists.
+ * Attempting to use an invalidated iterator in any way, other
+ * than comparing it to the end iterator, is *undefined behavior*.
+ * Passing such an iterator to any of the the json_object_iterator
+ * functions is not even guaranteed to fail in any consistent way.
*
* @param obj JSON Object instance (MUST be of type json_object)
*
/** Returns an iterator to the next pair, if any
*
- * @warning Any modification of the underlying pair
- * invalidates all iterators to that pair.
+ * @warning Any modification of the fields of the object invalidates
+ * the iterator, see the warning on json_object_iter_begin()
+ * for details.
*
* @param iter [IN/OUT] Pointer to iterator that references a
* name/value pair; MUST be a valid, non-end iterator.
* @param iter pointer to iterator that references a name/value
* pair; MUST be a valid, non-end iterator.
*
- * @warning bad things will happen if an invalid or
- * "end" iterator is passed.
+ * @warning bad things will happen if an invalid or "end" iterator
+ * is passed. See the warning on json_object_iter_begin()
+ * for details.
*
* @return const char* Pointer to the name of the referenced
* name/value pair. The name memory belongs to the
* @param iter pointer to iterator that references a name/value
* pair; MUST be a valid, non-end iterator.
*
- * @warning bad things will happen if invalid or
- * "end" iterator is passed.
+ * @warning bad things will happen if an invalid or "end" iterator
+ * is passed. See the warning on json_object_iter_begin()
+ * for details.
*
* @return struct json_object* Pointer to the json-c value
* instance of the referenced name/value pair; the
#undef NDEBUG
#endif
#include "config.h"
+#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
\"boolean_false\": false,\n\
\"big_number\": 2147483649,\n\
\"a_null\": null,\n\
+ \"an_object\": { \"foo\": \"bar\" },\n\
}";
struct json_object *new_obj;
it = json_object_iter_begin(new_obj);
itEnd = json_object_iter_end(new_obj);
+ // If this changes size on any platform, it'd break the ABI
+ printf("sizeof(struct json_object_iterator)/sizeof(void *)=%zu\n", sizeof(struct json_object_iterator) / sizeof(void *));
+
while (!json_object_iter_equal(&it, &itEnd))
{
- printf("%s\n", json_object_iter_peek_name(&it));
- printf("%s\n", json_object_to_json_string(json_object_iter_peek_value(&it)));
+ const char *key = json_object_iter_peek_name(&it);
+ json_object *value = json_object_iter_peek_value(&it);
+ printf("key: %s\n", key);
+ printf("pre change: %s\n", json_object_to_json_string(value));
+ if (json_object_get_type(value) == json_type_object)
+ {
+ // Changing sub-objects is ok
+ assert(json_object_object_add(value, "foo", json_object_new_string("change foo")) == 0);
+ assert(json_object_object_add(value, "newkey", json_object_new_string("new value")) == 0);
+ }
+ else
+ {
+ // Changing the value of pairs is ok
+ assert(json_object_object_add(new_obj, key, json_object_new_string("switched")) == 0);
+ }
+
+ if (0) // DO NOT DO THIS
+ {
+ // Adding new keys is NOT ok, and invalidates the iterator
+ json_object_object_add(value, "somenewkey", json_object_new_string("foo"));
+
+ // Deleting any keys ALSO invalidates the iterator, even if
+ // the key is immediately re-added.
+ json_object_object_del(value, key);
+ json_object_object_add(value, key, json_object_new_string("switched"));
+ }
+
+ value = json_object_iter_peek_value(&it);
+ printf("post change: %s\n", json_object_to_json_string(value));
+
json_object_iter_next(&it);
}