From 6988f53fcb05c13d99dd846494d79ea3bb3b1d4c Mon Sep 17 00:00:00 2001 From: Eric Haszlakiewicz Date: Tue, 24 Jul 2012 23:27:41 -0500 Subject: [PATCH] Rewrite json_object_object_add to replace just the value if the key already exists so keys remain valid. This is particularly useful when replacing values in a loop, since it allows the key used by json_object_object_foreach to continue to be used. --- json_object.c | 16 +++++++-- tests/Makefile.am | 5 ++- tests/testReplaceExisting.c | 56 ++++++++++++++++++++++++++++++ tests/testReplaceExisting.expected | 9 +++++ tests/testReplaceExisting.test | 12 +++++++ 5 files changed, 95 insertions(+), 3 deletions(-) create mode 100644 tests/testReplaceExisting.c create mode 100644 tests/testReplaceExisting.expected create mode 100755 tests/testReplaceExisting.test diff --git a/json_object.c b/json_object.c index 2258c02..8dd13b0 100644 --- a/json_object.c +++ b/json_object.c @@ -306,8 +306,20 @@ struct lh_table* json_object_get_object(struct json_object *jso) void json_object_object_add(struct json_object* jso, const char *key, struct json_object *val) { - lh_table_delete(jso->o.c_object, key); - lh_table_insert(jso->o.c_object, strdup(key), val); + // We lookup the entry and replace the value, rather than just deleting + // and re-adding it, so the existing key remains valid. + json_object *existing_value = NULL; + struct lh_entry *existing_entry; + existing_entry = lh_table_lookup_entry(jso->o.c_object, (void*)key); + if (!existing_entry) + { + lh_table_insert(jso->o.c_object, strdup(key), val); + return; + } + existing_value = (void *)existing_entry->v; + if (existing_value) + json_object_put(existing_value); + existing_entry->v = val; } struct json_object* json_object_object_get(struct json_object* jso, const char *key) diff --git a/tests/Makefile.am b/tests/Makefile.am index e2854dd..635ce55 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -6,6 +6,7 @@ LIBJSON_LA=$(top_builddir)/libjson.la check_PROGRAMS = test1 test1Formatted check_PROGRAMS += test2 test2Formatted check_PROGRAMS += test4 +check_PROGRAMS += testReplaceExisting check_PROGRAMS += test_parse_int64 check_PROGRAMS += test_null check_PROGRAMS += test_cast @@ -25,6 +26,8 @@ test2Formatted_CPPFLAGS = -DTEST_FORMATTED test4_LDADD = $(LIBJSON_LA) +testReplaceExisting_LDADD = $(LIBJSON_LA) + test_parse_int64_LDADD = $(LIBJSON_LA) test_null_LDADD = $(LIBJSON_LA) @@ -33,7 +36,7 @@ test_cast_LDADD = $(LIBJSON_LA) test_parse_LDADD = $(LIBJSON_LA) -TESTS = test1.test test2.test test4.test parse_int64.test test_null.test test_cast.test test_parse.test +TESTS = test1.test test2.test test4.test testReplaceExisting.test parse_int64.test test_null.test test_cast.test test_parse.test TESTS+= test_printbuf.test check_PROGRAMS+=test_printbuf diff --git a/tests/testReplaceExisting.c b/tests/testReplaceExisting.c new file mode 100644 index 0000000..8c8c4b2 --- /dev/null +++ b/tests/testReplaceExisting.c @@ -0,0 +1,56 @@ +#include +#include +#include +#include + +#include "json.h" + +int main(int argc, char **argv) +{ + MC_SET_DEBUG(1); + + /* + * Check that replacing an existing object keeps the key valid, + * and that it keeps the order the same. + */ + json_object *my_object = json_object_new_object(); + json_object_object_add(my_object, "foo1", json_object_new_string("bar1")); + json_object_object_add(my_object, "foo2", json_object_new_string("bar2")); + json_object_object_add(my_object, "foo3", json_object_new_string("bar3")); + const char *original_key = NULL; + int orig_count = 0; + json_object_object_foreach(my_object, key, val) + { + printf("Key at index %d is [%s]\n", orig_count, key); + orig_count++; + if (strcmp(key, "foo2") != 0) + continue; + printf("replacing value for key [%s]\n", key); + original_key = key; + json_object_object_add(my_object, key, json_object_new_string("zzz")); + } + + printf("==== second loop starting ====\n"); + + int new_count = 0; + int retval = 0; + json_object_object_foreach(my_object, key2, val2) + { + printf("Key at index %d is [%s]\n", new_count, key2); + new_count++; + if (strcmp(key2, "foo2") != 0) + continue; + printf("pointer for key [%s] does %smatch\n", key2, + (key2 == original_key) ? "" : "NOT "); + if (key2 != original_key) + retval = 1; + } + if (new_count != orig_count) + { + printf("mismatch between original count (%d) and new count (%d)\n", + orig_count, new_count); + retval = 1; + } + + return 0; +} diff --git a/tests/testReplaceExisting.expected b/tests/testReplaceExisting.expected new file mode 100644 index 0000000..4d1c509 --- /dev/null +++ b/tests/testReplaceExisting.expected @@ -0,0 +1,9 @@ +Key at index 0 is [foo1] +Key at index 1 is [foo2] +replacing value for key [foo2] +Key at index 2 is [foo3] +==== second loop starting ==== +Key at index 0 is [foo1] +Key at index 1 is [foo2] +pointer for key [foo2] does match +Key at index 2 is [foo3] diff --git a/tests/testReplaceExisting.test b/tests/testReplaceExisting.test new file mode 100755 index 0000000..ec5cbf1 --- /dev/null +++ b/tests/testReplaceExisting.test @@ -0,0 +1,12 @@ +#!/bin/sh + +# Common definitions +if test -z "$srcdir"; then + srcdir="${0%/*}" + test "$srcdir" = "$0" && srcdir=. + test -z "$srcdir" && srcdir=. +fi +. "$srcdir/test-defs.sh" + +run_output_test testReplaceExisting +exit $? -- 2.49.0