From 853b4b5dee4ca26a58f0b71944fa725c4a45ff0a Mon Sep 17 00:00:00 2001 From: Eric Haszlakiewicz Date: Mon, 25 May 2020 03:14:06 +0000 Subject: [PATCH 01/19] Start splitting struct json_object into multiple sub-types, as descibed at https://github.com/json-c/json-c/wiki/Proposal:-struct-json_object-split The current changes split out _only_ json_type_object, and thus have a number of hacks to allow the code to continue to build and work. Originally mentioned in issue #535. When complete, this will probably invalidate #552. This is likely to cause notable conflicts in any other significant un-merged changes, such as PR#620. --- README.json_object-split.md | 15 ++ json_object.c | 384 +++++++++++++++++++++++++++++++----- json_object.h | 3 +- json_object_private.h | 53 ++++- tests/CMakeLists.txt | 3 +- 5 files changed, 406 insertions(+), 52 deletions(-) create mode 100644 README.json_object-split.md diff --git a/README.json_object-split.md b/README.json_object-split.md new file mode 100644 index 0000000..f0d8632 --- /dev/null +++ b/README.json_object-split.md @@ -0,0 +1,15 @@ + +This branch implements the changes briefly described at: + +https://github.com/json-c/json-c/wiki/Proposal:-struct-json_object-split + +These were originally mentioned in: +Issue #535 - short string optimization: excessive array length + +The changes are expected to impact and possibly invalidate: +Issue #552 - Some anlysis about memory allocator in json-c + +and will likely cause notable conflicts in any other significant un-merged +changes, such as PR#620 - Introduce json_object_new_string_{ext,noalloc}() + + diff --git a/json_object.c b/json_object.c index c2463c1..1219334 100644 --- a/json_object.c +++ b/json_object.c @@ -45,8 +45,64 @@ const char *json_number_chars = "0123456789.+-eE"; const char *json_hex_chars = "0123456789abcdefABCDEF"; static void json_object_generic_delete(struct json_object *jso); +static void Xjson_object_generic_delete(struct json_object_base *jso); static struct json_object *json_object_new(enum json_type o_type); +// XAX kill this once json_object_base is renamed back to json_object +static inline struct json_object *PUBLIC(struct json_object_base *jso) +{ + return (struct json_object *)jso; +} +static inline const struct json_object *PUBLIC_C(const struct json_object_base *jso) +{ + return (const struct json_object *)jso; +} + +/* + * Helper functions to more safely cast to a particular type of json_object + */ +static inline struct json_object_object *JC_OBJECT(struct json_object_base *jso) +{ + return (void *)jso; +} +static inline const struct json_object_object *JC_OBJECT_C(const struct json_object_base *jso) +{ + return (const void *)jso; +} +static inline struct json_object_array *JC_ARRAY(struct json_object_base *jso) +{ + return (void *)jso; +} +static inline struct json_object_boolean *JC_BOOL(struct json_object_base *jso) +{ + return (void *)jso; +} +static inline struct json_object_double *JC_DOUBLE(struct json_object_base *jso) +{ + return (void *)jso; +} +static inline struct json_object_int *JC_INT(struct json_object_base *jso) +{ + return (void *)jso; +} +static inline struct json_object_string *JC_STRING(struct json_object_base *jso) +{ + return (void *)jso; +} + +#define JC_CONCAT(a,b) a##b +#define JC_CONCAT3(a,b,c) a##b##c + +#define JSON_OBJECT_NEW(jtype, delete_fn) \ + Xjson_object_new(JC_CONCAT(json_type_,jtype), \ + sizeof(struct JC_CONCAT(json_object_,jtype)), \ + &JC_CONCAT3(json_object_,jtype,_to_json_string), \ + (void *)delete_fn) // XAX drop cast +static inline struct json_object_base *Xjson_object_new(enum json_type o_type, + size_t alloc_size, + json_object_to_json_string_fn *to_json_string, + json_object_private_delete_fn *delete_fn); + static json_object_to_json_string_fn json_object_object_to_json_string; static json_object_to_json_string_fn json_object_boolean_to_json_string; static json_object_to_json_string_fn json_object_double_to_json_string_default; @@ -111,10 +167,14 @@ static void json_object_fini(void) /* helper for accessing the optimized string data component in json_object */ +// XAX drop this function static const char *get_string_component(const struct json_object *jso) { + if (jso->newold) + return ((const struct json_object_string *)jso)->data; return (jso->o.c_string.len < LEN_DIRECT_STRING_DATA) ? jso->o.c_string.str.data - : jso->o.c_string.str.ptr; + : jso->o.c_string.str.ptr; + } /* string escaping */ @@ -204,10 +264,42 @@ struct json_object *json_object_get(struct json_object *jso) return jso; } +// XAX remove this Xjson_object_put function once conversion is done +static int Xjson_object_put(struct json_object_base *jso) +{ + if (!jso) + return 0; + + /* Avoid invalid free and crash explicitly instead of (silently) + * segfaulting. + */ + assert(jso->_ref_count > 0); + +#if defined(HAVE_ATOMIC_BUILTINS) && defined(ENABLE_THREADING) + /* Note: this only allow the refcount to remain correct + * when multiple threads are adjusting it. It is still an error + * for a thread to decrement the refcount if it doesn't "own" it, + * as that can result in the thread that loses the race to 0 + * operating on an already-freed object. + */ + if (__sync_sub_and_fetch(&jso->_ref_count, 1) > 0) + return 0; +#else + if (--jso->_ref_count > 0) + return 0; +#endif + + if (jso->_user_delete) + jso->_user_delete(PUBLIC(jso), jso->_userdata); + jso->_delete(PUBLIC(jso)); + return 1; +} int json_object_put(struct json_object *jso) { if (!jso) return 0; + if (jso->newold) + return Xjson_object_put((struct json_object_base *)jso); /* Avoid invalid free and crash explicitly instead of (silently) * segfaulting. @@ -234,9 +326,14 @@ int json_object_put(struct json_object *jso) return 1; } + /* generic object construction and destruction parts */ static void json_object_generic_delete(struct json_object *jso) +{ + Xjson_object_generic_delete((void *)jso); +} +static void Xjson_object_generic_delete(struct json_object_base *jso) { #ifdef REFCOUNT_DEBUG MC_DEBUG("json_object_delete_%s: %p\n", json_type_to_name(jso->o_type), jso); @@ -246,7 +343,8 @@ static void json_object_generic_delete(struct json_object *jso) free(jso); } -static struct json_object *json_object_new(enum json_type o_type) +// XAX remove this once all is using new api +static inline struct json_object *json_object_new(enum json_type o_type) { struct json_object *jso; @@ -256,6 +354,35 @@ static struct json_object *json_object_new(enum json_type o_type) jso->o_type = o_type; jso->_ref_count = 1; jso->_delete = &json_object_generic_delete; + +#ifdef REFCOUNT_DEBUG + lh_table_insert(json_object_table, jso, jso); + MC_DEBUG("json_object_new_%s: %p\n", json_type_to_name(jso->o_type), jso); +#endif /* REFCOUNT_DEBUG */ + return jso; +} + +static inline struct json_object_base *Xjson_object_new(enum json_type o_type, + size_t alloc_size, + json_object_to_json_string_fn *to_json_string, + json_object_private_delete_fn *delete_fn) +{ + struct json_object_base *jso; + + jso = (struct json_object_base *)malloc(alloc_size); + if (!jso) + return NULL; + + jso->newold = 1; // XAX cut this after conversion + jso->o_type = o_type; + jso->_ref_count = 1; + jso->_delete = delete_fn; + jso->_to_json_string = to_json_string; + jso->_pb = NULL; + jso->_user_delete = NULL; + jso->_userdata= NULL; + //jso->... // Type-specific fields must be set by caller + #ifdef REFCOUNT_DEBUG lh_table_insert(json_object_table, jso, jso); MC_DEBUG("json_object_new_%s: %p\n", json_type_to_name(jso->o_type), jso); @@ -267,24 +394,30 @@ static struct json_object *json_object_new(enum json_type o_type) int json_object_is_type(const struct json_object *jso, enum json_type type) { +#define jso ((const struct json_object_base *)jso) if (!jso) return (type == json_type_null); return (jso->o_type == type); +#undef jso } enum json_type json_object_get_type(const struct json_object *jso) { +#define jso ((const struct json_object_base *)jso) if (!jso) return json_type_null; return jso->o_type; +#undef jso } void *json_object_get_userdata(json_object *jso) { +#define jso ((const struct json_object_base *)jso) return jso ? jso->_userdata : NULL; +#undef jso } -void json_object_set_userdata(json_object *jso, void *userdata, json_object_delete_fn *user_delete) +static void Xjson_object_set_userdata(json_object *jso, void *userdata, json_object_delete_fn *user_delete) { // Can't return failure, so abort if we can't perform the operation. assert(jso != NULL); @@ -296,10 +429,30 @@ void json_object_set_userdata(json_object *jso, void *userdata, json_object_dele jso->_userdata = userdata; jso->_user_delete = user_delete; } +void json_object_set_userdata(json_object *jso, void *userdata, json_object_delete_fn *user_delete) +{ + // XAX call old code: + if (!jso->newold) + { + Xjson_object_set_userdata(jso, userdata, user_delete); + return; + } +#define jso ((struct json_object_base *)jso) + // Can't return failure, so abort if we can't perform the operation. + assert(jso != NULL); + + // First, clean up any previously existing user info + if (jso->_user_delete) + jso->_user_delete(PUBLIC(jso), jso->_userdata); + + jso->_userdata = userdata; + jso->_user_delete = user_delete; +#undef jso +} /* set a custom conversion to string */ -void json_object_set_serializer(json_object *jso, json_object_to_json_string_fn *to_string_func, +static void Xjson_object_set_serializer(json_object *jso, json_object_to_json_string_fn *to_string_func, void *userdata, json_object_delete_fn *user_delete) { json_object_set_userdata(jso, userdata, user_delete); @@ -333,10 +486,53 @@ void json_object_set_serializer(json_object *jso, json_object_to_json_string_fn jso->_to_json_string = to_string_func; } +void json_object_set_serializer(json_object *jso, json_object_to_json_string_fn *to_string_func, + void *userdata, json_object_delete_fn *user_delete) +{ + // XAX call old code, remove after conversion: + if (jso && !jso->newold) + { + Xjson_object_set_serializer(jso, to_string_func, userdata, user_delete); + return; + } +#define jso ((struct json_object_base *)jso) + json_object_set_userdata(PUBLIC(jso), userdata, user_delete); + + if (to_string_func == NULL) + { + // Reset to the standard serialization function + switch (jso->o_type) + { + case json_type_null: jso->_to_json_string = NULL; break; + case json_type_boolean: + jso->_to_json_string = &json_object_boolean_to_json_string; + break; + case json_type_double: + jso->_to_json_string = &json_object_double_to_json_string_default; + break; + case json_type_int: jso->_to_json_string = &json_object_int_to_json_string; break; + case json_type_object: + jso->_to_json_string = &json_object_object_to_json_string; + break; + case json_type_array: + jso->_to_json_string = &json_object_array_to_json_string; + break; + case json_type_string: + jso->_to_json_string = &json_object_string_to_json_string; + break; + } + return; + } + + jso->_to_json_string = to_string_func; +#undef jso +} + /* extended conversion to string */ const char *json_object_to_json_string_length(struct json_object *jso, int flags, size_t *length) { +#define jso ((struct json_object_base *)jso) const char *r = NULL; size_t s = 0; @@ -349,7 +545,7 @@ const char *json_object_to_json_string_length(struct json_object *jso, int flags { printbuf_reset(jso->_pb); - if (jso->_to_json_string(jso, jso->_pb, 0, flags) >= 0) + if (jso->_to_json_string(PUBLIC(jso), jso->_pb, 0, flags) >= 0) { s = (size_t)jso->_pb->bpos; r = jso->_pb->buf; @@ -359,6 +555,7 @@ const char *json_object_to_json_string_length(struct json_object *jso, int flags if (length) *length = s; return r; +#undef jso } const char *json_object_to_json_string_ext(struct json_object *jso, int flags) @@ -393,6 +590,7 @@ static void indent(struct printbuf *pb, int level, int flags) static int json_object_object_to_json_string(struct json_object *jso, struct printbuf *pb, int level, int flags) { +#define jso ((struct json_object_base *)jso) int had_children = 0; struct json_object_iter iter; @@ -432,6 +630,7 @@ static int json_object_object_to_json_string(struct json_object *jso, struct pri return printbuf_strappend(pb, /*{*/ " }"); else return printbuf_strappend(pb, /*{*/ "}"); +#undef jso } static void json_object_lh_entry_free(struct lh_entry *ent) @@ -441,57 +640,62 @@ static void json_object_lh_entry_free(struct lh_entry *ent) json_object_put((struct json_object *)lh_entry_v(ent)); } -static void json_object_object_delete(struct json_object *jso) +static void json_object_object_delete(struct json_object_base *jso_base) { - lh_table_free(jso->o.c_object); - json_object_generic_delete(jso); + struct json_object_object *jso = (struct json_object_object *)jso_base; + lh_table_free(jso->c_object); + Xjson_object_generic_delete(jso_base); } struct json_object *json_object_new_object(void) { - struct json_object *jso = json_object_new(json_type_object); - if (!jso) + struct json_object_base *jso_base; + jso_base = JSON_OBJECT_NEW(object, &json_object_object_delete); + if (!jso_base) return NULL; - jso->_delete = &json_object_object_delete; - jso->_to_json_string = &json_object_object_to_json_string; - jso->o.c_object = + struct json_object_object *jso = (struct json_object_object *)jso_base; + jso->c_object = lh_kchar_table_new(JSON_OBJECT_DEF_HASH_ENTRIES, &json_object_lh_entry_free); - if (!jso->o.c_object) + if (!jso->c_object) { - json_object_generic_delete(jso); + Xjson_object_generic_delete(jso_base); errno = ENOMEM; return NULL; } - return jso; + return PUBLIC(jso_base); } struct lh_table *json_object_get_object(const struct json_object *jso) { +#define jso ((const struct json_object_base *)jso) if (!jso) return NULL; switch (jso->o_type) { - case json_type_object: return jso->o.c_object; + case json_type_object: return JC_OBJECT_C(jso)->c_object; default: return NULL; } +#undef jso } int json_object_object_add_ex(struct json_object *jso, const char *const key, struct json_object *const val, const unsigned opts) { +#define jso ((struct json_object_base *)jso) +#define val ((struct json_object_base *)val) struct json_object *existing_value = NULL; struct lh_entry *existing_entry; unsigned long hash; - assert(json_object_get_type(jso) == json_type_object); + assert(json_object_get_type(PUBLIC(jso)) == json_type_object); // We lookup the entry and replace the value, rather than just deleting // and re-adding it, so the existing key remains valid. - hash = lh_get_hash(jso->o.c_object, (const void *)key); + hash = lh_get_hash(JC_OBJECT(jso)->c_object, (const void *)key); existing_entry = (opts & JSON_C_OBJECT_ADD_KEY_IS_NEW) ? NULL - : lh_table_lookup_entry_w_hash(jso->o.c_object, (const void *)key, hash); + : lh_table_lookup_entry_w_hash(JC_OBJECT(jso)->c_object, (const void *)key, hash); // The caller must avoid creating loops in the object tree, but do a // quick check anyway to make sure we're not creating a trivial loop. @@ -504,13 +708,15 @@ int json_object_object_add_ex(struct json_object *jso, const char *const key, (opts & JSON_C_OBJECT_KEY_IS_CONSTANT) ? (const void *)key : strdup(key); if (k == NULL) return -1; - return lh_table_insert_w_hash(jso->o.c_object, k, val, hash, opts); + return lh_table_insert_w_hash(JC_OBJECT(jso)->c_object, k, val, hash, opts); } existing_value = (json_object *)lh_entry_v(existing_entry); if (existing_value) json_object_put(existing_value); existing_entry->v = val; return 0; +#undef jso +#undef val } int json_object_object_add(struct json_object *jso, const char *key, struct json_object *val) @@ -520,10 +726,13 @@ int json_object_object_add(struct json_object *jso, const char *key, struct json int json_object_object_length(const struct json_object *jso) { - assert(json_object_get_type(jso) == json_type_object); - return lh_table_length(jso->o.c_object); +#define jso ((const struct json_object_base *)jso) + assert(json_object_get_type(PUBLIC_C(jso)) == json_type_object); + return lh_table_length(JC_OBJECT_C(jso)->c_object); +#undef jso } + size_t json_c_object_sizeof(void) { return sizeof(struct json_object); @@ -539,6 +748,7 @@ struct json_object *json_object_object_get(const struct json_object *jso, const json_bool json_object_object_get_ex(const struct json_object *jso, const char *key, struct json_object **value) { +#define jso ((const struct json_object_base *)jso) if (value != NULL) *value = NULL; @@ -548,20 +758,24 @@ json_bool json_object_object_get_ex(const struct json_object *jso, const char *k switch (jso->o_type) { case json_type_object: - return lh_table_lookup_ex(jso->o.c_object, (const void *)key, (void **)value); + return lh_table_lookup_ex(JC_OBJECT_C(jso)->c_object, (const void *)key, (void **)value); default: if (value != NULL) *value = NULL; return 0; } +#undef jso } void json_object_object_del(struct json_object *jso, const char *key) { - assert(json_object_get_type(jso) == json_type_object); - lh_table_delete(jso->o.c_object, key); +#define jso ((struct json_object_base *)jso) + assert(json_object_get_type(PUBLIC(jso)) == json_type_object); + lh_table_delete(JC_OBJECT(jso)->c_object, key); +#undef jso } +// XAX ------------------------------ start unconverted code: /* json_object_boolean */ static int json_object_boolean_to_json_string(struct json_object *jso, struct printbuf *pb, @@ -1398,17 +1612,18 @@ struct json_object *json_object_new_null(void) return NULL; } -static int json_object_all_values_equal(struct json_object *jso1, struct json_object *jso2) +static int json_object_all_values_equal(struct json_object_base *jso1, struct json_object_base *jso2) { struct json_object_iter iter; struct json_object *sub; - assert(json_object_get_type(jso1) == json_type_object); - assert(json_object_get_type(jso2) == json_type_object); + assert(json_object_get_type(PUBLIC(jso1)) == json_type_object); + assert(json_object_get_type(PUBLIC(jso2)) == json_type_object); /* Iterate over jso1 keys and see if they exist and are equal in jso2 */ json_object_object_foreachC(jso1, iter) { - if (!lh_table_lookup_ex(jso2->o.c_object, (void *)iter.key, (void **)(void *)&sub)) + struct json_object_object *jso2_object = (struct json_object_object *)jso2; + if (!lh_table_lookup_ex(jso2_object->c_object, (void *)iter.key, (void **)(void *)&sub)) return 0; if (!json_object_equal(iter.val, sub)) return 0; @@ -1417,14 +1632,15 @@ static int json_object_all_values_equal(struct json_object *jso1, struct json_ob /* Iterate over jso2 keys to see if any exist that are not in jso1 */ json_object_object_foreachC(jso2, iter) { - if (!lh_table_lookup_ex(jso1->o.c_object, (void *)iter.key, (void **)(void *)&sub)) + struct json_object_object *jso1_object = (struct json_object_object *)jso1; + if (!lh_table_lookup_ex(jso1_object->c_object, (void *)iter.key, (void **)(void *)&sub)) return 0; } return 1; } -int json_object_equal(struct json_object *jso1, struct json_object *jso2) +static int Xjson_object_equal(struct json_object *jso1, struct json_object *jso2) { if (jso1 == jso2) return 1; @@ -1463,7 +1679,7 @@ int json_object_equal(struct json_object *jso1, struct json_object *jso2) memcmp(get_string_component(jso1), get_string_component(jso2), jso1->o.c_string.len) == 0); - case json_type_object: return json_object_all_values_equal(jso1, jso2); + case json_type_object: assert(0); //return json_object_all_values_equal(jso1, jso2); case json_type_array: return json_array_equal(jso1, jso2); @@ -1472,6 +1688,70 @@ int json_object_equal(struct json_object *jso1, struct json_object *jso2) return 0; } +int json_object_equal(struct json_object *jso1, struct json_object *jso2) +{ + if (jso1 == jso2) + return 1; + + if (!jso1 || !jso2) + return 0; + + // XAX cut this after conversion + if (!jso1->newold && !jso2->newold) + return Xjson_object_equal(jso1, jso2); // call old code + +#define jso1 ((struct json_object_base *)jso1) +#define jso2 ((struct json_object_base *)jso2) + if (jso1->o_type != jso2->o_type) + return 0; + + switch (jso1->o_type) + { + case json_type_boolean: return (JC_BOOL(jso1)->c_boolean == JC_BOOL(jso2)->c_boolean); + + case json_type_double: return (JC_DOUBLE(jso1)->c_double == JC_DOUBLE(jso2)->c_double); + + case json_type_int: + { + struct json_object_int *int1 = JC_INT(jso1); + struct json_object_int *int2 = JC_INT(jso2); + if (int1->cint_type == json_object_int_type_int64) + { + if (int2->cint_type == json_object_int_type_int64) + return (int1->cint.c_int64 == int2->cint.c_int64); + if (int1->cint.c_int64 < 0) + return 0; + return ((uint64_t)int1->cint.c_int64 == + int2->cint.c_uint64); + } + // else jso1 is a uint64 + if (int2->cint_type == json_object_int_type_uint64) + return (int1->cint.c_uint64 == int2->cint.c_uint64); + if (int2->cint.c_int64 < 0) + return 0; + return (int1->cint.c_uint64 == (uint64_t)int2->cint.c_int64); + } + + case json_type_string: + { + struct json_object_string *str1 = JC_STRING(jso1); + struct json_object_string *str2 = JC_STRING(jso2); + return (str1->len == str2->len && + memcmp(str1->data, str2->data, str1->len) == 0); + } + + case json_type_object: return json_object_all_values_equal(jso1, jso2); + +// XAX not actually + case json_type_array: return json_array_equal(PUBLIC(jso1), PUBLIC(jso2)); + + case json_type_null: return 1; + }; + + return 0; +#undef jso1 +#undef jso2 +} static int json_object_copy_serializer_data(struct json_object *src, struct json_object *dst) { @@ -1550,16 +1830,16 @@ int json_c_shallow_copy_default(json_object *src, json_object *parent, const cha * * Note: caller is responsible for freeing *dst if this fails and returns -1. */ -static int json_object_deep_copy_recursive(struct json_object *src, struct json_object *parent, +static int json_object_deep_copy_recursive(struct json_object_base *src, struct json_object_base *parent, const char *key_in_parent, size_t index_in_parent, - struct json_object **dst, + struct json_object_base **dst, json_c_shallow_copy_fn *shallow_copy) { struct json_object_iter iter; size_t src_array_len, ii; int shallow_copy_rc = 0; - shallow_copy_rc = shallow_copy(src, parent, key_in_parent, index_in_parent, dst); + shallow_copy_rc = shallow_copy(PUBLIC(src), PUBLIC(parent), key_in_parent, index_in_parent, (struct json_object **)dst); // XAX remove cast too /* -1=error, 1=object created ok, 2=userdata set */ if (shallow_copy_rc < 1) { @@ -1573,44 +1853,44 @@ static int json_object_deep_copy_recursive(struct json_object *src, struct json_ case json_type_object: json_object_object_foreachC(src, iter) { - struct json_object *jso = NULL; + struct json_object_base *jso = NULL; /* This handles the `json_type_null` case */ if (!iter.val) jso = NULL; - else if (json_object_deep_copy_recursive(iter.val, src, iter.key, -1, &jso, + else if (json_object_deep_copy_recursive((struct json_object_base *)/*XAX removecast*/iter.val, src, iter.key, -1, &jso, shallow_copy) < 0) { - json_object_put(jso); + json_object_put(PUBLIC(jso)); return -1; } - if (json_object_object_add(*dst, iter.key, jso) < 0) + if (json_object_object_add(PUBLIC(*dst), iter.key, PUBLIC(jso)) < 0) { - json_object_put(jso); + json_object_put(PUBLIC(jso)); return -1; } } break; case json_type_array: - src_array_len = json_object_array_length(src); + src_array_len = json_object_array_length(PUBLIC(src)); for (ii = 0; ii < src_array_len; ii++) { - struct json_object *jso = NULL; - struct json_object *jso1 = json_object_array_get_idx(src, ii); + struct json_object_base *jso = NULL; + struct json_object_base *jso1 = (struct json_object_base *)/*XAXremovecast*/json_object_array_get_idx(PUBLIC(src), ii); /* This handles the `json_type_null` case */ if (!jso1) jso = NULL; else if (json_object_deep_copy_recursive(jso1, src, NULL, ii, &jso, shallow_copy) < 0) { - json_object_put(jso); + json_object_put(PUBLIC(jso)); return -1; } - if (json_object_array_add(*dst, jso) < 0) + if (json_object_array_add(PUBLIC(*dst), PUBLIC(jso)) < 0) { - json_object_put(jso); + json_object_put(PUBLIC(jso)); return -1; } } @@ -1622,7 +1902,7 @@ static int json_object_deep_copy_recursive(struct json_object *src, struct json_ } if (shallow_copy_rc != 2) - return json_object_copy_serializer_data(src, *dst); + return json_object_copy_serializer_data(PUBLIC(src), PUBLIC(*dst)); return 0; } @@ -1630,6 +1910,9 @@ static int json_object_deep_copy_recursive(struct json_object *src, struct json_ int json_object_deep_copy(struct json_object *src, struct json_object **dst, json_c_shallow_copy_fn *shallow_copy) { +#define src ((struct json_object_base *)src) +#define parent ((struct json_object_base *)parent) +#define dst ((struct json_object_base **)dst) int rc; /* Check if arguments are sane ; *dst must not point to a non-NULL object */ @@ -1645,11 +1928,14 @@ int json_object_deep_copy(struct json_object *src, struct json_object **dst, rc = json_object_deep_copy_recursive(src, NULL, NULL, -1, dst, shallow_copy); if (rc < 0) { - json_object_put(*dst); + json_object_put(PUBLIC(*dst)); *dst = NULL; } return rc; +#undef src +#undef parent +#undef dst } static void json_abort(const char *message) diff --git a/json_object.h b/json_object.h index 7c0d1f2..1805bda 100644 --- a/json_object.h +++ b/json_object.h @@ -490,8 +490,9 @@ JSON_EXPORT void json_object_object_del(struct json_object *obj, const char *key * @param obj the json_object instance * @param iter the object iterator, use type json_object_iter */ +// XAX temporary workaround during code conversion: #define json_object_object_foreachC(obj, iter) \ - for (iter.entry = json_object_get_object(obj)->head; \ + for (iter.entry = json_object_get_object(PUBLIC(obj))->head; \ (iter.entry ? (iter.key = (char *)lh_entry_k(iter.entry), \ iter.val = (struct json_object *)lh_entry_v(iter.entry), iter.entry) \ : 0); \ diff --git a/json_object_private.h b/json_object_private.h index 1c7737a..b6dfe0d 100644 --- a/json_object_private.h +++ b/json_object_private.h @@ -36,8 +36,60 @@ typedef enum json_object_int_type json_object_int_type_uint64 } json_object_int_type; +struct json_object_base // XAX rename to json_object after conversion +{ + int newold; // XAX temporary, remove after code conversion + enum json_type o_type; + uint32_t _ref_count; + json_object_private_delete_fn *_delete; + json_object_to_json_string_fn *_to_json_string; + struct printbuf *_pb; + json_object_delete_fn *_user_delete; + void *_userdata; + char data[1]; // Actually a struct json_object_${o_type} +}; + +struct json_object_object +{ + struct json_object_base base; + struct lh_table *c_object; +}; +struct json_object_array +{ + struct json_object_base base; + struct array_list *c_array; +}; + +struct json_object_boolean +{ + struct json_object_base base; + json_bool c_boolean; +}; +struct json_object_double +{ + struct json_object_base base; + json_bool c_double; +}; +struct json_object_int +{ + struct json_object_base base; + enum json_object_int_type cint_type; + union + { + int64_t c_int64; + uint64_t c_uint64; + } cint; +}; +struct json_object_string +{ + struct json_object_base base; + size_t len; + char data[1]; // Actually longer +}; + struct json_object { + int newold; enum json_type o_type; uint32_t _ref_count; json_object_private_delete_fn *_delete; @@ -56,7 +108,6 @@ struct json_object } cint; enum json_object_int_type cint_type; } c_int; - struct lh_table *c_object; struct array_list *c_array; struct { diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index a871573..5a8b2cc 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -20,7 +20,8 @@ foreach(TESTNAME test_cast test_charcase test_compare - test_deep_copy +# XAX temporarily comment this out, until at least json_type_array is split out +# test_deep_copy test_double_serializer test_float test_int_add From 02b687b9a6e535591a360f109d1825db9a5a6b52 Mon Sep 17 00:00:00 2001 From: Eric Haszlakiewicz Date: Mon, 25 May 2020 03:44:56 +0000 Subject: [PATCH 02/19] Kick json_type_array out of struct json_object; re-enable the test_deep_copy test. --- json_object.c | 109 +++++++++++++++++++++++++++++++----------- json_object_private.h | 1 - tests/CMakeLists.txt | 3 +- 3 files changed, 82 insertions(+), 31 deletions(-) diff --git a/json_object.c b/json_object.c index 1219334..6d80762 100644 --- a/json_object.c +++ b/json_object.c @@ -73,6 +73,10 @@ static inline struct json_object_array *JC_ARRAY(struct json_object_base *jso) { return (void *)jso; } +static inline const struct json_object_array *JC_ARRAY_C(const struct json_object_base *jso) +{ + return (const void *)jso; +} static inline struct json_object_boolean *JC_BOOL(struct json_object_base *jso) { return (void *)jso; @@ -412,6 +416,8 @@ enum json_type json_object_get_type(const struct json_object *jso) void *json_object_get_userdata(json_object *jso) { + if (!jso->newold) + return jso ? jso->_userdata : NULL; #define jso ((const struct json_object_base *)jso) return jso ? jso->_userdata : NULL; #undef jso @@ -1464,13 +1470,14 @@ int json_object_set_string_len(json_object *jso, const char *s, int len) static int json_object_array_to_json_string(struct json_object *jso, struct printbuf *pb, int level, int flags) { +#define jso ((struct json_object_base *)jso) int had_children = 0; size_t ii; printbuf_strappend(pb, "["); if (flags & JSON_C_TO_STRING_PRETTY) printbuf_strappend(pb, "\n"); - for (ii = 0; ii < json_object_array_length(jso); ii++) + for (ii = 0; ii < json_object_array_length(PUBLIC(jso)); ii++) { struct json_object *val; if (had_children) @@ -1483,7 +1490,7 @@ static int json_object_array_to_json_string(struct json_object *jso, struct prin if (flags & JSON_C_TO_STRING_SPACED && !(flags & JSON_C_TO_STRING_PRETTY)) printbuf_strappend(pb, " "); indent(pb, level + 1, flags); - val = json_object_array_get_idx(jso, ii); + val = json_object_array_get_idx(PUBLIC(jso), ii); if (val == NULL) printbuf_strappend(pb, "null"); else if (val->_to_json_string(val, pb, level + 1, flags) < 0) @@ -1499,6 +1506,7 @@ static int json_object_array_to_json_string(struct json_object *jso, struct prin if (flags & JSON_C_TO_STRING_SPACED && !(flags & JSON_C_TO_STRING_PRETTY)) return printbuf_strappend(pb, " ]"); return printbuf_strappend(pb, "]"); +#undef jso } static void json_object_array_entry_free(void *data) @@ -1508,86 +1516,104 @@ static void json_object_array_entry_free(void *data) static void json_object_array_delete(struct json_object *jso) { - array_list_free(jso->o.c_array); - json_object_generic_delete(jso); +#define jso ((struct json_object_base *)jso) + array_list_free(JC_ARRAY(jso)->c_array); + json_object_generic_delete(PUBLIC(jso)); +#undef jso } struct json_object *json_object_new_array(void) { - struct json_object *jso = json_object_new(json_type_array); - if (!jso) + struct json_object_base *jso_base; + jso_base = JSON_OBJECT_NEW(array, &json_object_array_delete); + if (!jso_base) return NULL; - jso->_delete = &json_object_array_delete; - jso->_to_json_string = &json_object_array_to_json_string; - jso->o.c_array = array_list_new(&json_object_array_entry_free); - if (jso->o.c_array == NULL) + struct json_object_array *jso = (struct json_object_array *)jso_base; + jso->c_array = array_list_new(&json_object_array_entry_free); + if (jso->c_array == NULL) { free(jso); return NULL; } - return jso; + return PUBLIC(jso_base); } struct array_list *json_object_get_array(const struct json_object *jso) { +#define jso ((const struct json_object_base *)jso) if (!jso) return NULL; switch (jso->o_type) { - case json_type_array: return jso->o.c_array; + case json_type_array: return JC_ARRAY_C(jso)->c_array; default: return NULL; } +#undef jso } void json_object_array_sort(struct json_object *jso, int (*sort_fn)(const void *, const void *)) { - assert(json_object_get_type(jso) == json_type_array); - array_list_sort(jso->o.c_array, sort_fn); +#define jso ((struct json_object_base *)jso) + assert(json_object_get_type(PUBLIC(jso)) == json_type_array); + array_list_sort(JC_ARRAY(jso)->c_array, sort_fn); +#undef jso } struct json_object *json_object_array_bsearch(const struct json_object *key, const struct json_object *jso, int (*sort_fn)(const void *, const void *)) { +#define jso ((const struct json_object_base *)jso) struct json_object **result; - assert(json_object_get_type(jso) == json_type_array); + assert(json_object_get_type(PUBLIC_C(jso)) == json_type_array); result = (struct json_object **)array_list_bsearch((const void **)(void *)&key, - jso->o.c_array, sort_fn); + JC_ARRAY_C(jso)->c_array, sort_fn); if (!result) return NULL; return *result; +#undef jso } size_t json_object_array_length(const struct json_object *jso) { - assert(json_object_get_type(jso) == json_type_array); - return array_list_length(jso->o.c_array); +#define jso ((const struct json_object_base *)jso) + assert(json_object_get_type(PUBLIC_C(jso)) == json_type_array); + return array_list_length(JC_ARRAY_C(jso)->c_array); +#undef jso } int json_object_array_add(struct json_object *jso, struct json_object *val) { - assert(json_object_get_type(jso) == json_type_array); - return array_list_add(jso->o.c_array, val); +#define jso ((struct json_object_base *)jso) + assert(json_object_get_type(PUBLIC_C(jso)) == json_type_array); + return array_list_add(JC_ARRAY(jso)->c_array, val); +#undef jso } int json_object_array_put_idx(struct json_object *jso, size_t idx, struct json_object *val) { - assert(json_object_get_type(jso) == json_type_array); - return array_list_put_idx(jso->o.c_array, idx, val); +#define jso ((struct json_object_base *)jso) + assert(json_object_get_type(PUBLIC_C(jso)) == json_type_array); + return array_list_put_idx(JC_ARRAY(jso)->c_array, idx, val); +#undef jso } int json_object_array_del_idx(struct json_object *jso, size_t idx, size_t count) { - assert(json_object_get_type(jso) == json_type_array); - return array_list_del_idx(jso->o.c_array, idx, count); +#define jso ((struct json_object_base *)jso) + assert(json_object_get_type(PUBLIC_C(jso)) == json_type_array); + return array_list_del_idx(JC_ARRAY(jso)->c_array, idx, count); +#undef jso } struct json_object *json_object_array_get_idx(const struct json_object *jso, size_t idx) { - assert(json_object_get_type(jso) == json_type_array); - return (struct json_object *)array_list_get_idx(jso->o.c_array, idx); +#define jso ((const struct json_object_base *)jso) + assert(json_object_get_type(PUBLIC_C(jso)) == json_type_array); + return (struct json_object *)array_list_get_idx(JC_ARRAY_C(jso)->c_array, idx); +#undef jso } static int json_array_equal(struct json_object *jso1, struct json_object *jso2) @@ -1681,7 +1707,7 @@ static int Xjson_object_equal(struct json_object *jso1, struct json_object *jso2 case json_type_object: assert(0); //return json_object_all_values_equal(jso1, jso2); - case json_type_array: return json_array_equal(jso1, jso2); + case json_type_array: assert(0); //return json_array_equal(jso1, jso2); case json_type_null: return 1; }; @@ -1742,7 +1768,6 @@ int json_object_equal(struct json_object *jso1, struct json_object *jso2) case json_type_object: return json_object_all_values_equal(jso1, jso2); -// XAX not actually case json_type_array: return json_array_equal(PUBLIC(jso1), PUBLIC(jso2)); case json_type_null: return 1; @@ -1753,8 +1778,34 @@ int json_object_equal(struct json_object *jso1, struct json_object *jso2) #undef jso2 } +// XAX remove this function after code conversion +static int Xjson_object_copy_serializer_data(struct json_object *src, struct json_object *dst) +{ + if (!src->_userdata && !src->_user_delete) + return 0; + + if (dst->_to_json_string == json_object_userdata_to_json_string || + dst->_to_json_string == _json_object_userdata_to_json_string) + { + dst->_userdata = strdup(src->_userdata); + } + // else if ... other supported serializers ... + else + { + _json_c_set_last_err( + "json_object_deep_copy: unable to copy unknown serializer data: %p\n", + dst->_to_json_string); + return -1; + } + dst->_user_delete = src->_user_delete; + return 0; +} static int json_object_copy_serializer_data(struct json_object *src, struct json_object *dst) { + if (!src->newold) + return Xjson_object_copy_serializer_data(src, dst); +#define src ((struct json_object_base *)src) +#define dst ((struct json_object_base *)dst) if (!src->_userdata && !src->_user_delete) return 0; @@ -1773,6 +1824,8 @@ static int json_object_copy_serializer_data(struct json_object *src, struct json } dst->_user_delete = src->_user_delete; return 0; +#undef src +#undef dst } /** diff --git a/json_object_private.h b/json_object_private.h index b6dfe0d..45e7bc6 100644 --- a/json_object_private.h +++ b/json_object_private.h @@ -108,7 +108,6 @@ struct json_object } cint; enum json_object_int_type cint_type; } c_int; - struct array_list *c_array; struct { union diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 5a8b2cc..a871573 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -20,8 +20,7 @@ foreach(TESTNAME test_cast test_charcase test_compare -# XAX temporarily comment this out, until at least json_type_array is split out -# test_deep_copy + test_deep_copy test_double_serializer test_float test_int_add From 5d89fc8a9d1c926ab341f49f41be1c38c7049161 Mon Sep 17 00:00:00 2001 From: Eric Haszlakiewicz Date: Mon, 25 May 2020 03:52:36 +0000 Subject: [PATCH 03/19] Add some backwards compat for Visual Studio 2013. --- json_object.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/json_object.c b/json_object.c index 6d80762..9b4df33 100644 --- a/json_object.c +++ b/json_object.c @@ -48,6 +48,11 @@ static void json_object_generic_delete(struct json_object *jso); static void Xjson_object_generic_delete(struct json_object_base *jso); static struct json_object *json_object_new(enum json_type o_type); +#if defined(_MSC_VER) && (_MSC_VER <= 1800) +/* VS2013 doesn't know about "inline" */ +#define inline __inline +#endif + // XAX kill this once json_object_base is renamed back to json_object static inline struct json_object *PUBLIC(struct json_object_base *jso) { From d1f83bf5eab331e3014f04e856bcb3662da1199f Mon Sep 17 00:00:00 2001 From: Eric Haszlakiewicz Date: Mon, 25 May 2020 04:04:02 +0000 Subject: [PATCH 04/19] Kick json_type_boolean out of struct json_object. --- json_object.c | 51 ++++++++++++++++++++++++++++++------------- json_object_private.h | 1 - 2 files changed, 36 insertions(+), 16 deletions(-) diff --git a/json_object.c b/json_object.c index 9b4df33..b2d8d18 100644 --- a/json_object.c +++ b/json_object.c @@ -86,6 +86,10 @@ static inline struct json_object_boolean *JC_BOOL(struct json_object_base *jso) { return (void *)jso; } +static inline const struct json_object_boolean *JC_BOOL_C(const struct json_object_base *jso) +{ + return (const void *)jso; +} static inline struct json_object_double *JC_DOUBLE(struct json_object_base *jso) { return (void *)jso; @@ -786,25 +790,27 @@ void json_object_object_del(struct json_object *jso, const char *key) #undef jso } -// XAX ------------------------------ start unconverted code: /* json_object_boolean */ static int json_object_boolean_to_json_string(struct json_object *jso, struct printbuf *pb, int level, int flags) { - if (jso->o.c_boolean) +#define jso ((struct json_object_base *)jso) + if (JC_BOOL(jso)->c_boolean) return printbuf_strappend(pb, "true"); return printbuf_strappend(pb, "false"); +#undef jso } struct json_object *json_object_new_boolean(json_bool b) { - struct json_object *jso = json_object_new(json_type_boolean); - if (!jso) + struct json_object_base *jso_base; + jso_base = JSON_OBJECT_NEW(boolean, &json_object_generic_delete); + if (!jso_base) return NULL; - jso->_to_json_string = &json_object_boolean_to_json_string; - jso->o.c_boolean = b; - return jso; + struct json_object_boolean *jso = (struct json_object_boolean *)jso_base; + jso->c_boolean = b; + return PUBLIC(jso_base); } json_bool json_object_get_boolean(const struct json_object *jso) @@ -813,7 +819,9 @@ json_bool json_object_get_boolean(const struct json_object *jso) return 0; switch (jso->o_type) { - case json_type_boolean: return jso->o.c_boolean; +#define jso ((const struct json_object_base *)jso) + case json_type_boolean: return JC_BOOL_C(jso)->c_boolean; +#undef jso case json_type_int: switch (jso->o.c_int.cint_type) { @@ -829,12 +837,15 @@ json_bool json_object_get_boolean(const struct json_object *jso) int json_object_set_boolean(struct json_object *jso, json_bool new_value) { +#define jso ((struct json_object_base *)jso) if (!jso || jso->o_type != json_type_boolean) return 0; - jso->o.c_boolean = new_value; + JC_BOOL(jso)->c_boolean = new_value; return 1; +#undef jso } +// XAX ------------------------------ start unconverted code: /* json_object_int */ static int json_object_int_to_json_string(struct json_object *jso, struct printbuf *pb, int level, @@ -907,7 +918,9 @@ int32_t json_object_get_int(const struct json_object *jso) if (jso->o.c_double >= INT32_MAX) return INT32_MAX; return (int32_t)jso->o.c_double; - case json_type_boolean: return jso->o.c_boolean; +#define jso ((const struct json_object_base *)jso) + case json_type_boolean: return JC_BOOL_C(jso)->c_boolean; +#undef jso default: return 0; } } @@ -965,7 +978,9 @@ int64_t json_object_get_int64(const struct json_object *jso) if (jso->o.c_double <= INT64_MIN) return INT64_MIN; return (int64_t)jso->o.c_double; - case json_type_boolean: return jso->o.c_boolean; +#define jso ((const struct json_object_base *)jso) + case json_type_boolean: return JC_BOOL_C(jso)->c_boolean; +#undef jso case json_type_string: if (json_parse_int64(get_string_component(jso), &cint) == 0) return cint; @@ -1000,7 +1015,9 @@ uint64_t json_object_get_uint64(const struct json_object *jso) if (jso->o.c_double < 0) return 0; return (uint64_t)jso->o.c_double; - case json_type_boolean: return jso->o.c_boolean; +#define jso ((const struct json_object_base *)jso) + case json_type_boolean: return JC_BOOL_C(jso)->c_boolean; +#undef jso case json_type_string: if (json_parse_uint64(get_string_component(jso), &cuint) == 0) return cuint; @@ -1294,7 +1311,9 @@ double json_object_get_double(const struct json_object *jso) case json_object_int_type_uint64: return jso->o.c_int.cint.c_uint64; default: json_abort("invalid cint_type"); } - case json_type_boolean: return jso->o.c_boolean; +#define jso ((const struct json_object_base *)jso) + case json_type_boolean: return JC_BOOL_C(jso)->c_boolean; +#undef jso case json_type_string: errno = 0; cdouble = strtod(get_string_component(jso), &errPtr); @@ -1684,7 +1703,7 @@ static int Xjson_object_equal(struct json_object *jso1, struct json_object *jso2 switch (jso1->o_type) { - case json_type_boolean: return (jso1->o.c_boolean == jso2->o.c_boolean); + case json_type_boolean: assert(0); //return (jso1->o.c_boolean == jso2->o.c_boolean); case json_type_double: return (jso1->o.c_double == jso2->o.c_double); @@ -1846,7 +1865,9 @@ int json_c_shallow_copy_default(json_object *src, json_object *parent, const cha { switch (src->o_type) { - case json_type_boolean: *dst = json_object_new_boolean(src->o.c_boolean); break; +#define src ((struct json_object_base *)src) + case json_type_boolean: *dst = json_object_new_boolean(JC_BOOL(src)->c_boolean); break; +#undef src case json_type_double: *dst = json_object_new_double(src->o.c_double); break; diff --git a/json_object_private.h b/json_object_private.h index 45e7bc6..0f6a4f8 100644 --- a/json_object_private.h +++ b/json_object_private.h @@ -97,7 +97,6 @@ struct json_object struct printbuf *_pb; union data { - json_bool c_boolean; double c_double; struct { From 0351bb55c85ab8db545327af3d872fb63e2838b1 Mon Sep 17 00:00:00 2001 From: Eric Haszlakiewicz Date: Mon, 25 May 2020 04:10:11 +0000 Subject: [PATCH 05/19] Declare variables earlier, to appease Visual Studio 2010. --- json_object.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/json_object.c b/json_object.c index b2d8d18..f648c5c 100644 --- a/json_object.c +++ b/json_object.c @@ -665,10 +665,11 @@ static void json_object_object_delete(struct json_object_base *jso_base) struct json_object *json_object_new_object(void) { struct json_object_base *jso_base; + struct json_object_object *jso; jso_base = JSON_OBJECT_NEW(object, &json_object_object_delete); if (!jso_base) return NULL; - struct json_object_object *jso = (struct json_object_object *)jso_base; + jso = (struct json_object_object *)jso_base; jso->c_object = lh_kchar_table_new(JSON_OBJECT_DEF_HASH_ENTRIES, &json_object_lh_entry_free); if (!jso->c_object) @@ -805,10 +806,11 @@ static int json_object_boolean_to_json_string(struct json_object *jso, struct pr struct json_object *json_object_new_boolean(json_bool b) { struct json_object_base *jso_base; + struct json_object_boolean *jso; jso_base = JSON_OBJECT_NEW(boolean, &json_object_generic_delete); if (!jso_base) return NULL; - struct json_object_boolean *jso = (struct json_object_boolean *)jso_base; + jso = (struct json_object_boolean *)jso_base; jso->c_boolean = b; return PUBLIC(jso_base); } @@ -1549,10 +1551,11 @@ static void json_object_array_delete(struct json_object *jso) struct json_object *json_object_new_array(void) { struct json_object_base *jso_base; + struct json_object_array *jso; jso_base = JSON_OBJECT_NEW(array, &json_object_array_delete); if (!jso_base) return NULL; - struct json_object_array *jso = (struct json_object_array *)jso_base; + jso = (struct json_object_array *)jso_base; jso->c_array = array_list_new(&json_object_array_entry_free); if (jso->c_array == NULL) { From 9ecb1222bd18801f0da2acbe9021f04ed74f0dfa Mon Sep 17 00:00:00 2001 From: Eric Haszlakiewicz Date: Tue, 26 May 2020 02:31:35 +0000 Subject: [PATCH 06/19] Kick json_type_int and json_type_double out of struct json_object. Clean up the code in json_object_new_* a bit by dropping unnecesary json_object_base variables. --- json_object.c | 305 ++++++++++++++++++--------------- json_object_private.h | 12 +- tests/test_double_serializer.c | 2 +- 3 files changed, 172 insertions(+), 147 deletions(-) diff --git a/json_object.c b/json_object.c index f648c5c..5300448 100644 --- a/json_object.c +++ b/json_object.c @@ -94,20 +94,32 @@ static inline struct json_object_double *JC_DOUBLE(struct json_object_base *jso) { return (void *)jso; } +static inline const struct json_object_double *JC_DOUBLE_C(const struct json_object_base *jso) +{ + return (const void *)jso; +} static inline struct json_object_int *JC_INT(struct json_object_base *jso) { return (void *)jso; } +static inline const struct json_object_int *JC_INT_C(const struct json_object_base *jso) +{ + return (const void *)jso; +} static inline struct json_object_string *JC_STRING(struct json_object_base *jso) { return (void *)jso; } +static inline const struct json_object_string *JC_STRING_C(const struct json_object_base *jso) +{ + return (const void *)jso; +} #define JC_CONCAT(a,b) a##b #define JC_CONCAT3(a,b,c) a##b##c #define JSON_OBJECT_NEW(jtype, delete_fn) \ - Xjson_object_new(JC_CONCAT(json_type_,jtype), \ + (struct JC_CONCAT(json_object_,jtype) *)Xjson_object_new(JC_CONCAT(json_type_,jtype), \ sizeof(struct JC_CONCAT(json_object_,jtype)), \ &JC_CONCAT3(json_object_,jtype,_to_json_string), \ (void *)delete_fn) // XAX drop cast @@ -657,28 +669,24 @@ static void json_object_lh_entry_free(struct lh_entry *ent) static void json_object_object_delete(struct json_object_base *jso_base) { - struct json_object_object *jso = (struct json_object_object *)jso_base; - lh_table_free(jso->c_object); + lh_table_free(JC_OBJECT(jso_base)->c_object); Xjson_object_generic_delete(jso_base); } struct json_object *json_object_new_object(void) { - struct json_object_base *jso_base; - struct json_object_object *jso; - jso_base = JSON_OBJECT_NEW(object, &json_object_object_delete); - if (!jso_base) + struct json_object_object *jso = JSON_OBJECT_NEW(object, &json_object_object_delete); + if (!jso) return NULL; - jso = (struct json_object_object *)jso_base; jso->c_object = lh_kchar_table_new(JSON_OBJECT_DEF_HASH_ENTRIES, &json_object_lh_entry_free); if (!jso->c_object) { - Xjson_object_generic_delete(jso_base); + Xjson_object_generic_delete(&jso->base); errno = ENOMEM; return NULL; } - return PUBLIC(jso_base); + return PUBLIC(&jso->base); } struct lh_table *json_object_get_object(const struct json_object *jso) @@ -805,14 +813,11 @@ static int json_object_boolean_to_json_string(struct json_object *jso, struct pr struct json_object *json_object_new_boolean(json_bool b) { - struct json_object_base *jso_base; - struct json_object_boolean *jso; - jso_base = JSON_OBJECT_NEW(boolean, &json_object_generic_delete); - if (!jso_base) + struct json_object_boolean *jso = JSON_OBJECT_NEW(boolean, &json_object_generic_delete); + if (!jso) return NULL; - jso = (struct json_object_boolean *)jso_base; jso->c_boolean = b; - return PUBLIC(jso_base); + return PUBLIC(&jso->base); } json_bool json_object_get_boolean(const struct json_object *jso) @@ -823,15 +828,15 @@ json_bool json_object_get_boolean(const struct json_object *jso) { #define jso ((const struct json_object_base *)jso) case json_type_boolean: return JC_BOOL_C(jso)->c_boolean; -#undef jso case json_type_int: - switch (jso->o.c_int.cint_type) + switch (JC_INT_C(jso)->cint_type) { - case json_object_int_type_int64: return (jso->o.c_int.cint.c_int64 != 0); - case json_object_int_type_uint64: return (jso->o.c_int.cint.c_uint64 != 0); + case json_object_int_type_int64: return (JC_INT_C(jso)->cint.c_int64 != 0); + case json_object_int_type_uint64: return (JC_INT_C(jso)->cint.c_uint64 != 0); default: json_abort("invalid cint_type"); } - case json_type_double: return (jso->o.c_double != 0); + case json_type_double: return (JC_DOUBLE_C(jso)->c_double != 0); +#undef jso case json_type_string: return (jso->o.c_string.len != 0); default: return 0; } @@ -847,60 +852,60 @@ int json_object_set_boolean(struct json_object *jso, json_bool new_value) #undef jso } -// XAX ------------------------------ start unconverted code: /* json_object_int */ static int json_object_int_to_json_string(struct json_object *jso, struct printbuf *pb, int level, int flags) { +#define jso ((struct json_object_base *)jso) /* room for 19 digits, the sign char, and a null term */ char sbuf[21]; - if (jso->o.c_int.cint_type == json_object_int_type_int64) - snprintf(sbuf, sizeof(sbuf), "%" PRId64, jso->o.c_int.cint.c_int64); + if (JC_INT(jso)->cint_type == json_object_int_type_int64) + snprintf(sbuf, sizeof(sbuf), "%" PRId64, JC_INT(jso)->cint.c_int64); else - snprintf(sbuf, sizeof(sbuf), "%" PRIu64, jso->o.c_int.cint.c_uint64); + snprintf(sbuf, sizeof(sbuf), "%" PRIu64, JC_INT(jso)->cint.c_uint64); return printbuf_memappend(pb, sbuf, strlen(sbuf)); +#undef jso } struct json_object *json_object_new_int(int32_t i) { - struct json_object *jso = json_object_new(json_type_int); - if (!jso) - return NULL; - jso->_to_json_string = &json_object_int_to_json_string; - jso->o.c_int.cint.c_int64 = i; - jso->o.c_int.cint_type = json_object_int_type_int64; - return jso; + return json_object_new_int64(i); } int32_t json_object_get_int(const struct json_object *jso) { +#define jso ((const struct json_object_base *)jso) int64_t cint64; + double cdouble; enum json_type o_type; if (!jso) return 0; o_type = jso->o_type; - if (jso->o.c_int.cint_type == json_object_int_type_int64) + if (o_type == json_type_int) { - cint64 = jso->o.c_int.cint.c_int64; - } - else - { - if (jso->o.c_int.cint.c_uint64 >= INT64_MAX) - cint64 = INT64_MAX; + const struct json_object_int *jsoint = JC_INT_C(jso); + if (jsoint->cint_type == json_object_int_type_int64) + { + cint64 = jsoint->cint.c_int64; + } else - cint64 = (int64_t)jso->o.c_int.cint.c_uint64; + { + if (jsoint->cint.c_uint64 >= INT64_MAX) + cint64 = INT64_MAX; + else + cint64 = (int64_t)jsoint->cint.c_uint64; + } } - - if (o_type == json_type_string) + else if (o_type == json_type_string) { /* * Parse strings into 64-bit numbers, then use the * 64-to-32-bit number handling below. */ - if (json_parse_int64(get_string_component(jso), &cint64) != 0) + if (json_parse_int64(get_string_component(PUBLIC_C(jso)), &cint64) != 0) return 0; /* whoops, it didn't work. */ o_type = json_type_int; } @@ -915,16 +920,16 @@ int32_t json_object_get_int(const struct json_object *jso) return INT32_MAX; return (int32_t)cint64; case json_type_double: - if (jso->o.c_double <= INT32_MIN) + cdouble = JC_DOUBLE_C(jso)->c_double; + if (cdouble <= INT32_MIN) return INT32_MIN; - if (jso->o.c_double >= INT32_MAX) + if (cdouble >= INT32_MAX) return INT32_MAX; - return (int32_t)jso->o.c_double; -#define jso ((const struct json_object_base *)jso) + return (int32_t)cdouble; case json_type_boolean: return JC_BOOL_C(jso)->c_boolean; -#undef jso default: return 0; } +#undef jso } int json_object_set_int(struct json_object *jso, int new_value) @@ -934,28 +939,27 @@ int json_object_set_int(struct json_object *jso, int new_value) struct json_object *json_object_new_int64(int64_t i) { - struct json_object *jso = json_object_new(json_type_int); + struct json_object_int *jso = JSON_OBJECT_NEW(int, &json_object_generic_delete); if (!jso) return NULL; - jso->_to_json_string = &json_object_int_to_json_string; - jso->o.c_int.cint.c_int64 = i; - jso->o.c_int.cint_type = json_object_int_type_int64; - return jso; + jso->cint.c_int64 = i; + jso->cint_type = json_object_int_type_int64; + return PUBLIC(&jso->base); } struct json_object *json_object_new_uint64(uint64_t i) { - struct json_object *jso = json_object_new(json_type_int); + struct json_object_int *jso = JSON_OBJECT_NEW(int, &json_object_generic_delete); if (!jso) return NULL; - jso->_to_json_string = &json_object_int_to_json_string; - jso->o.c_int.cint.c_uint64 = i; - jso->o.c_int.cint_type = json_object_int_type_uint64; - return jso; + jso->cint.c_uint64 = i; + jso->cint_type = json_object_int_type_uint64; + return PUBLIC(&jso->base); } int64_t json_object_get_int64(const struct json_object *jso) { +#define jso ((const struct json_object_base *)jso) int64_t cint; if (!jso) @@ -963,36 +967,39 @@ int64_t json_object_get_int64(const struct json_object *jso) switch (jso->o_type) { case json_type_int: - switch (jso->o.c_int.cint_type) + { + const struct json_object_int *jsoint = JC_INT_C(jso); + switch (jsoint->cint_type) { - case json_object_int_type_int64: return jso->o.c_int.cint.c_int64; + case json_object_int_type_int64: return jsoint->cint.c_int64; case json_object_int_type_uint64: - if (jso->o.c_int.cint.c_uint64 >= INT64_MAX) + if (jsoint->cint.c_uint64 >= INT64_MAX) return INT64_MAX; - return (int64_t)jso->o.c_int.cint.c_uint64; + return (int64_t)jsoint->cint.c_uint64; default: json_abort("invalid cint_type"); } + } case json_type_double: // INT64_MAX can't be exactly represented as a double // so cast to tell the compiler it's ok to round up. - if (jso->o.c_double >= (double)INT64_MAX) + if (JC_DOUBLE_C(jso)->c_double >= (double)INT64_MAX) return INT64_MAX; - if (jso->o.c_double <= INT64_MIN) + if (JC_DOUBLE_C(jso)->c_double <= INT64_MIN) return INT64_MIN; - return (int64_t)jso->o.c_double; -#define jso ((const struct json_object_base *)jso) + return (int64_t)JC_DOUBLE_C(jso)->c_double; case json_type_boolean: return JC_BOOL_C(jso)->c_boolean; -#undef jso case json_type_string: - if (json_parse_int64(get_string_component(jso), &cint) == 0) + if (json_parse_int64(get_string_component(PUBLIC_C(jso)), &cint) == 0) return cint; /* FALLTHRU */ default: return 0; } +#undef jso } uint64_t json_object_get_uint64(const struct json_object *jso) { +#define jso ((const struct json_object_base *)jso) uint64_t cuint; if (!jso) @@ -1000,95 +1007,105 @@ uint64_t json_object_get_uint64(const struct json_object *jso) switch (jso->o_type) { case json_type_int: - switch (jso->o.c_int.cint_type) + { + const struct json_object_int *jsoint = JC_INT_C(jso); + switch (jsoint->cint_type) { case json_object_int_type_int64: - if (jso->o.c_int.cint.c_int64 < 0) + if (jsoint->cint.c_int64 < 0) return 0; - return (uint64_t)jso->o.c_int.cint.c_int64; - case json_object_int_type_uint64: return jso->o.c_int.cint.c_uint64; + return (uint64_t)jsoint->cint.c_int64; + case json_object_int_type_uint64: return jsoint->cint.c_uint64; default: json_abort("invalid cint_type"); } + } case json_type_double: // UINT64_MAX can't be exactly represented as a double // so cast to tell the compiler it's ok to round up. - if (jso->o.c_double >= (double)UINT64_MAX) + if (JC_DOUBLE_C(jso)->c_double >= (double)UINT64_MAX) return UINT64_MAX; - if (jso->o.c_double < 0) + if (JC_DOUBLE_C(jso)->c_double < 0) return 0; - return (uint64_t)jso->o.c_double; -#define jso ((const struct json_object_base *)jso) + return (uint64_t)JC_DOUBLE_C(jso)->c_double; case json_type_boolean: return JC_BOOL_C(jso)->c_boolean; -#undef jso case json_type_string: - if (json_parse_uint64(get_string_component(jso), &cuint) == 0) + if (json_parse_uint64(get_string_component(PUBLIC_C(jso)), &cuint) == 0) return cuint; /* FALLTHRU */ default: return 0; } +#undef jso } int json_object_set_int64(struct json_object *jso, int64_t new_value) { +#define jso ((struct json_object_base *)jso) if (!jso || jso->o_type != json_type_int) return 0; - jso->o.c_int.cint.c_int64 = new_value; - jso->o.c_int.cint_type = json_object_int_type_int64; + JC_INT(jso)->cint.c_int64 = new_value; + JC_INT(jso)->cint_type = json_object_int_type_int64; return 1; +#undef jso } int json_object_set_uint64(struct json_object *jso, uint64_t new_value) { +#define jso ((struct json_object_base *)jso) if (!jso || jso->o_type != json_type_int) return 0; - jso->o.c_int.cint.c_uint64 = new_value; - jso->o.c_int.cint_type = json_object_int_type_uint64; + JC_INT(jso)->cint.c_uint64 = new_value; + JC_INT(jso)->cint_type = json_object_int_type_uint64; return 1; +#undef jso } int json_object_int_inc(struct json_object *jso, int64_t val) { +#define jso ((struct json_object_base *)jso) + struct json_object_int *jsoint; if (!jso || jso->o_type != json_type_int) return 0; - switch (jso->o.c_int.cint_type) + jsoint = JC_INT(jso); + switch (jsoint->cint_type) { case json_object_int_type_int64: - if (val > 0 && jso->o.c_int.cint.c_int64 > INT64_MAX - val) + if (val > 0 && jsoint->cint.c_int64 > INT64_MAX - val) { - jso->o.c_int.cint.c_uint64 = - (uint64_t)jso->o.c_int.cint.c_int64 + (uint64_t)val; - jso->o.c_int.cint_type = json_object_int_type_uint64; + jsoint->cint.c_uint64 = + (uint64_t)jsoint->cint.c_int64 + (uint64_t)val; + jsoint->cint_type = json_object_int_type_uint64; } - else if (val < 0 && jso->o.c_int.cint.c_int64 < INT64_MIN - val) + else if (val < 0 && jsoint->cint.c_int64 < INT64_MIN - val) { - jso->o.c_int.cint.c_int64 = INT64_MIN; + jsoint->cint.c_int64 = INT64_MIN; } else { - jso->o.c_int.cint.c_int64 += val; + jsoint->cint.c_int64 += val; } return 1; case json_object_int_type_uint64: - if (val > 0 && jso->o.c_int.cint.c_uint64 > UINT64_MAX - (uint64_t)val) + if (val > 0 && jsoint->cint.c_uint64 > UINT64_MAX - (uint64_t)val) { - jso->o.c_int.cint.c_uint64 = UINT64_MAX; + jsoint->cint.c_uint64 = UINT64_MAX; } - else if (val < 0 && jso->o.c_int.cint.c_uint64 < (uint64_t)(-val)) + else if (val < 0 && jsoint->cint.c_uint64 < (uint64_t)(-val)) { - jso->o.c_int.cint.c_int64 = (int64_t)jso->o.c_int.cint.c_uint64 + val; - jso->o.c_int.cint_type = json_object_int_type_int64; + jsoint->cint.c_int64 = (int64_t)jsoint->cint.c_uint64 + val; + jsoint->cint_type = json_object_int_type_int64; } - else if (val < 0 && jso->o.c_int.cint.c_uint64 >= (uint64_t)(-val)) + else if (val < 0 && jsoint->cint.c_uint64 >= (uint64_t)(-val)) { - jso->o.c_int.cint.c_uint64 -= (uint64_t)(-val); + jsoint->cint.c_uint64 -= (uint64_t)(-val); } else { - jso->o.c_int.cint.c_uint64 += val; + jsoint->cint.c_uint64 += val; } return 1; default: json_abort("invalid cint_type"); } +#undef jso } /* json_object_double */ @@ -1140,6 +1157,8 @@ int json_c_set_serialization_double_format(const char *double_format, int global static int json_object_double_to_json_string_format(struct json_object *jso, struct printbuf *pb, int level, int flags, const char *format) { +#define jso ((struct json_object_base *)jso) + struct json_object_double *jsodbl = JC_DOUBLE(jso); char buf[128], *p, *q; int size; /* Although JSON RFC does not support @@ -1147,13 +1166,13 @@ static int json_object_double_to_json_string_format(struct json_object *jso, str * ECMA 262 section 9.8.1 defines * how to handle these cases as strings */ - if (isnan(jso->o.c_double)) + if (isnan(jsodbl->c_double)) { size = snprintf(buf, sizeof(buf), "NaN"); } - else if (isinf(jso->o.c_double)) + else if (isinf(jsodbl->c_double)) { - if (jso->o.c_double > 0) + if (jsodbl->c_double > 0) size = snprintf(buf, sizeof(buf), "Infinity"); else size = snprintf(buf, sizeof(buf), "-Infinity"); @@ -1176,7 +1195,7 @@ static int json_object_double_to_json_string_format(struct json_object *jso, str else format = std_format; } - size = snprintf(buf, sizeof(buf), format, jso->o.c_double); + size = snprintf(buf, sizeof(buf), format, jsodbl->c_double); if (size < 0) return -1; @@ -1228,29 +1247,34 @@ static int json_object_double_to_json_string_format(struct json_object *jso, str size = sizeof(buf) - 1; printbuf_memappend(pb, buf, size); return size; +#undef jso } static int json_object_double_to_json_string_default(struct json_object *jso, struct printbuf *pb, int level, int flags) { - return json_object_double_to_json_string_format(jso, pb, level, flags, NULL); +#define jso ((struct json_object_base *)jso) + return json_object_double_to_json_string_format(PUBLIC(jso), pb, level, flags, NULL); +#undef jso } int json_object_double_to_json_string(struct json_object *jso, struct printbuf *pb, int level, int flags) { - return json_object_double_to_json_string_format(jso, pb, level, flags, +#define jso ((struct json_object_base *)jso) + return json_object_double_to_json_string_format(PUBLIC(jso), pb, level, flags, (const char *)jso->_userdata); +#undef jso } struct json_object *json_object_new_double(double d) { - struct json_object *jso = json_object_new(json_type_double); + struct json_object_double *jso = JSON_OBJECT_NEW(double, &json_object_generic_delete); if (!jso) return NULL; - jso->_to_json_string = &json_object_double_to_json_string_default; - jso->o.c_double = d; - return jso; + jso->base._to_json_string = &json_object_double_to_json_string_default; + jso->c_double = d; + return PUBLIC(&jso->base); } struct json_object *json_object_new_double_s(double d, const char *ds) @@ -1286,9 +1310,21 @@ static int _json_object_userdata_to_json_string(struct json_object *jso, struct int json_object_userdata_to_json_string(struct json_object *jso, struct printbuf *pb, int level, int flags) { + // XAX old code compat, remove this + if (!jso->newold) + { + int userdata_len = strlen((const char *)jso->_userdata); + printbuf_memappend(pb, (const char *)jso->_userdata, userdata_len); + return userdata_len; + } + else + { +#define jso ((const struct json_object_base *)jso) int userdata_len = strlen((const char *)jso->_userdata); printbuf_memappend(pb, (const char *)jso->_userdata, userdata_len); return userdata_len; +#undef jso + } } void json_object_free_userdata(struct json_object *jso, void *userdata) @@ -1298,6 +1334,7 @@ void json_object_free_userdata(struct json_object *jso, void *userdata) double json_object_get_double(const struct json_object *jso) { +#define jso ((const struct json_object_base *)jso) double cdouble; char *errPtr = NULL; @@ -1305,23 +1342,21 @@ double json_object_get_double(const struct json_object *jso) return 0.0; switch (jso->o_type) { - case json_type_double: return jso->o.c_double; + case json_type_double: return JC_DOUBLE_C(jso)->c_double; case json_type_int: - switch (jso->o.c_int.cint_type) + switch (JC_INT_C(jso)->cint_type) { - case json_object_int_type_int64: return jso->o.c_int.cint.c_int64; - case json_object_int_type_uint64: return jso->o.c_int.cint.c_uint64; + case json_object_int_type_int64: return JC_INT_C(jso)->cint.c_int64; + case json_object_int_type_uint64: return JC_INT_C(jso)->cint.c_uint64; default: json_abort("invalid cint_type"); } -#define jso ((const struct json_object_base *)jso) case json_type_boolean: return JC_BOOL_C(jso)->c_boolean; -#undef jso case json_type_string: errno = 0; - cdouble = strtod(get_string_component(jso), &errPtr); + cdouble = strtod(get_string_component(PUBLIC_C(jso)), &errPtr); /* if conversion stopped at the first character, return 0.0 */ - if (errPtr == get_string_component(jso)) + if (errPtr == get_string_component(PUBLIC_C(jso))) { errno = EINVAL; return 0.0; @@ -1354,16 +1389,19 @@ double json_object_get_double(const struct json_object *jso) return cdouble; default: errno = EINVAL; return 0.0; } +#undef jso } int json_object_set_double(struct json_object *jso, double new_value) { +#define jso ((struct json_object_base *)jso) if (!jso || jso->o_type != json_type_double) return 0; - jso->o.c_double = new_value; + JC_DOUBLE(jso)->c_double = new_value; if (jso->_to_json_string == &_json_object_userdata_to_json_string) - json_object_set_serializer(jso, NULL, NULL, NULL); + json_object_set_serializer(PUBLIC(jso), NULL, NULL, NULL); return 1; +#undef jso } /* json_object_string */ @@ -1550,19 +1588,16 @@ static void json_object_array_delete(struct json_object *jso) struct json_object *json_object_new_array(void) { - struct json_object_base *jso_base; - struct json_object_array *jso; - jso_base = JSON_OBJECT_NEW(array, &json_object_array_delete); - if (!jso_base) + struct json_object_array *jso = JSON_OBJECT_NEW(array, &json_object_array_delete); + if (!jso) return NULL; - jso = (struct json_object_array *)jso_base; jso->c_array = array_list_new(&json_object_array_entry_free); if (jso->c_array == NULL) { free(jso); return NULL; } - return PUBLIC(jso_base); + return PUBLIC(&jso->base); } struct array_list *json_object_get_array(const struct json_object *jso) @@ -1675,8 +1710,7 @@ static int json_object_all_values_equal(struct json_object_base *jso1, struct js /* Iterate over jso1 keys and see if they exist and are equal in jso2 */ json_object_object_foreachC(jso1, iter) { - struct json_object_object *jso2_object = (struct json_object_object *)jso2; - if (!lh_table_lookup_ex(jso2_object->c_object, (void *)iter.key, (void **)(void *)&sub)) + if (!lh_table_lookup_ex(JC_OBJECT(jso2)->c_object, (void *)iter.key, (void **)(void *)&sub)) return 0; if (!json_object_equal(iter.val, sub)) return 0; @@ -1685,8 +1719,7 @@ static int json_object_all_values_equal(struct json_object_base *jso1, struct js /* Iterate over jso2 keys to see if any exist that are not in jso1 */ json_object_object_foreachC(jso2, iter) { - struct json_object_object *jso1_object = (struct json_object_object *)jso1; - if (!lh_table_lookup_ex(jso1_object->c_object, (void *)iter.key, (void **)(void *)&sub)) + if (!lh_table_lookup_ex(JC_OBJECT(jso1)->c_object, (void *)iter.key, (void **)(void *)&sub)) return 0; } @@ -1708,9 +1741,10 @@ static int Xjson_object_equal(struct json_object *jso1, struct json_object *jso2 { case json_type_boolean: assert(0); //return (jso1->o.c_boolean == jso2->o.c_boolean); - case json_type_double: return (jso1->o.c_double == jso2->o.c_double); + case json_type_double: assert(0); // return (jso1->o.c_double == jso2->o.c_double); - case json_type_int: + case json_type_int: assert(0); + /* if (jso1->o.c_int.cint_type == json_object_int_type_int64) { if (jso2->o.c_int.cint_type == json_object_int_type_int64) @@ -1726,6 +1760,7 @@ static int Xjson_object_equal(struct json_object *jso1, struct json_object *jso2 if (jso2->o.c_int.cint.c_int64 < 0) return 0; return (jso1->o.c_int.cint.c_uint64 == (uint64_t)jso2->o.c_int.cint.c_int64); + */ case json_type_string: return (jso1->o.c_string.len == jso2->o.c_string.len && @@ -1870,22 +1905,22 @@ int json_c_shallow_copy_default(json_object *src, json_object *parent, const cha { #define src ((struct json_object_base *)src) case json_type_boolean: *dst = json_object_new_boolean(JC_BOOL(src)->c_boolean); break; -#undef src - case json_type_double: *dst = json_object_new_double(src->o.c_double); break; + case json_type_double: *dst = json_object_new_double(JC_DOUBLE(src)->c_double); break; case json_type_int: - switch (src->o.c_int.cint_type) + switch (JC_INT(src)->cint_type) { case json_object_int_type_int64: - *dst = json_object_new_int64(src->o.c_int.cint.c_int64); + *dst = json_object_new_int64(JC_INT(src)->cint.c_int64); break; case json_object_int_type_uint64: - *dst = json_object_new_uint64(src->o.c_int.cint.c_uint64); + *dst = json_object_new_uint64(JC_INT(src)->cint.c_uint64); break; default: json_abort("invalid cint_type"); } break; +#undef src case json_type_string: *dst = json_object_new_string(get_string_component(src)); break; diff --git a/json_object_private.h b/json_object_private.h index 0f6a4f8..5ea865c 100644 --- a/json_object_private.h +++ b/json_object_private.h @@ -68,7 +68,7 @@ struct json_object_boolean struct json_object_double { struct json_object_base base; - json_bool c_double; + double c_double; }; struct json_object_int { @@ -97,16 +97,6 @@ struct json_object struct printbuf *_pb; union data { - double c_double; - struct - { - union - { - int64_t c_int64; - uint64_t c_uint64; - } cint; - enum json_object_int_type cint_type; - } c_int; struct { union diff --git a/tests/test_double_serializer.c b/tests/test_double_serializer.c index 8b2487a..98f6dd9 100644 --- a/tests/test_double_serializer.c +++ b/tests/test_double_serializer.c @@ -20,7 +20,7 @@ int main() printf("obj.to_string(standard)=%s\n", json_object_to_json_string(obj)); printf("Test default serializer with custom userdata:\n"); - obj->_userdata = udata; + ((struct json_object_base *)obj)->_userdata = udata; printf("obj.to_string(userdata)=%s\n", json_object_to_json_string(obj)); printf("Test explicit serializer with custom userdata:\n"); From 0fc9d91277c24e7a9b8e2b0eeb4df16c2132ac2d Mon Sep 17 00:00:00 2001 From: Eric Haszlakiewicz Date: Sun, 7 Jun 2020 02:42:58 +0000 Subject: [PATCH 07/19] Kick json_type_string out of struct json_object. The default is now that string data is stored inline at the end of json_object, though to allow for json_object_set_string() to set a _longer_ string, we still need to allow for the possibility of a separate char * pointer. All json types have been split out now, next step it cleanup. --- CMakeLists.txt | 1 + cmake/config.h.in | 3 + json_object.c | 233 +++++++++++++++++++++++++---------------- json_object_private.h | 30 +++--- tests/test_set_value.c | 4 + 5 files changed, 162 insertions(+), 109 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 333513c..16d1336 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -205,6 +205,7 @@ check_type_size(int64_t SIZEOF_INT64_T) check_type_size(long SIZEOF_LONG) check_type_size("long long" SIZEOF_LONG_LONG) check_type_size("size_t" SIZEOF_SIZE_T) +check_type_size("ssize_t" SIZEOF_SSIZE_T) check_c_source_compiles( [=[ diff --git a/cmake/config.h.in b/cmake/config.h.in index 456c26a..8b31164 100644 --- a/cmake/config.h.in +++ b/cmake/config.h.in @@ -194,6 +194,9 @@ /* The number of bytes in type size_t */ #cmakedefine SIZEOF_SIZE_T @SIZEOF_SIZE_T@ +/* The number of bytes in type ssize_t */ +#cmakedefine SIZEOF_SSIZE_T @SIZEOF_SSIZE_T@ + /* Specifier for __thread */ #cmakedefine SPEC___THREAD @SPEC___THREAD@ diff --git a/json_object.c b/json_object.c index 5300448..7069f5d 100644 --- a/json_object.c +++ b/json_object.c @@ -16,6 +16,9 @@ #include #include +#ifdef HAVE_LIMITS_H +#include +#endif #include #include #include @@ -38,6 +41,18 @@ #error "The long long type isn't 64-bits" #endif +#ifndef SSIZE_T_MAX +#if SIZEOF_SSIZE_T == SIZEOF_INT +#define SSIZE_T_MAX UINT_MAX +#elif SIZEOF_SSIZE_T == SIZEOF_LONG +#define SSIZE_T_MAX ULONG_MAX +#elif SIZEOF_SSIZE_T == SIZEOF_LONG_LONG +#define SSIZE_T_MAX ULLONG_MAX +#else +#error Unable to determine size of ssize_t +#endif +#endif + // Don't define this. It's not thread-safe. /* #define REFCOUNT_DEBUG 1 */ @@ -51,6 +66,8 @@ static struct json_object *json_object_new(enum json_type o_type); #if defined(_MSC_VER) && (_MSC_VER <= 1800) /* VS2013 doesn't know about "inline" */ #define inline __inline +#elif defined(AIX_CC) +#define inline #endif // XAX kill this once json_object_base is renamed back to json_object @@ -192,19 +209,23 @@ static void json_object_fini(void) /* helper for accessing the optimized string data component in json_object */ -// XAX drop this function -static const char *get_string_component(const struct json_object *jso) +static inline char *get_string_component_mutable(struct json_object_base *jso) { - if (jso->newold) - return ((const struct json_object_string *)jso)->data; - return (jso->o.c_string.len < LEN_DIRECT_STRING_DATA) ? jso->o.c_string.str.data - : jso->o.c_string.str.ptr; - + if (JC_STRING_C(jso)->len < 0) + { + /* Due to json_object_str_string(), we might have a pointer */ + return JC_STRING(jso)->c_string.pdata; + } + return JC_STRING(jso)->c_string.idata; +} +static inline const char *get_string_component(const struct json_object_base *jso) +{ + return get_string_component_mutable((void *)(uintptr_t)(const void *)jso); } /* string escaping */ -static int json_escape_str(struct printbuf *pb, const char *str, int len, int flags) +static int json_escape_str(struct printbuf *pb, const char *str, size_t len, int flags) { int pos = 0, start_offset = 0; unsigned char c; @@ -836,10 +857,10 @@ json_bool json_object_get_boolean(const struct json_object *jso) default: json_abort("invalid cint_type"); } case json_type_double: return (JC_DOUBLE_C(jso)->c_double != 0); -#undef jso - case json_type_string: return (jso->o.c_string.len != 0); + case json_type_string: return (JC_STRING_C(jso)->len != 0); default: return 0; } +#undef jso } int json_object_set_boolean(struct json_object *jso, json_bool new_value) @@ -905,7 +926,7 @@ int32_t json_object_get_int(const struct json_object *jso) * Parse strings into 64-bit numbers, then use the * 64-to-32-bit number handling below. */ - if (json_parse_int64(get_string_component(PUBLIC_C(jso)), &cint64) != 0) + if (json_parse_int64(get_string_component(jso), &cint64) != 0) return 0; /* whoops, it didn't work. */ o_type = json_type_int; } @@ -989,7 +1010,7 @@ int64_t json_object_get_int64(const struct json_object *jso) return (int64_t)JC_DOUBLE_C(jso)->c_double; case json_type_boolean: return JC_BOOL_C(jso)->c_boolean; case json_type_string: - if (json_parse_int64(get_string_component(PUBLIC_C(jso)), &cint) == 0) + if (json_parse_int64(get_string_component(jso), &cint) == 0) return cint; /* FALLTHRU */ default: return 0; @@ -1029,7 +1050,7 @@ uint64_t json_object_get_uint64(const struct json_object *jso) return (uint64_t)JC_DOUBLE_C(jso)->c_double; case json_type_boolean: return JC_BOOL_C(jso)->c_boolean; case json_type_string: - if (json_parse_uint64(get_string_component(PUBLIC_C(jso)), &cuint) == 0) + if (json_parse_uint64(get_string_component(jso), &cuint) == 0) return cuint; /* FALLTHRU */ default: return 0; @@ -1353,10 +1374,10 @@ double json_object_get_double(const struct json_object *jso) case json_type_boolean: return JC_BOOL_C(jso)->c_boolean; case json_type_string: errno = 0; - cdouble = strtod(get_string_component(PUBLIC_C(jso)), &errPtr); + cdouble = strtod(get_string_component(jso), &errPtr); /* if conversion stopped at the first character, return 0.0 */ - if (errPtr == get_string_component(PUBLIC_C(jso))) + if (errPtr == get_string_component(jso)) { errno = EINVAL; return 0.0; @@ -1409,124 +1430,154 @@ int json_object_set_double(struct json_object *jso, double new_value) static int json_object_string_to_json_string(struct json_object *jso, struct printbuf *pb, int level, int flags) { +#define jso ((struct json_object_base *)jso) printbuf_strappend(pb, "\""); - json_escape_str(pb, get_string_component(jso), jso->o.c_string.len, flags); + ssize_t len = JC_STRING(jso)->len; + json_escape_str(pb, get_string_component(jso), len < 0 ? -len : len, flags); printbuf_strappend(pb, "\""); return 0; +#undef jso } static void json_object_string_delete(struct json_object *jso) { - if (jso->o.c_string.len >= LEN_DIRECT_STRING_DATA) - free(jso->o.c_string.str.ptr); - json_object_generic_delete(jso); +#define jso ((struct json_object_base *)jso) + if (JC_STRING(jso)->len < 0) + free(JC_STRING(jso)->c_string.pdata); + Xjson_object_generic_delete(jso); +#undef jso } -struct json_object *json_object_new_string(const char *s) +static struct json_object *_json_object_new_string(const char *s, const size_t len) { - struct json_object *jso = json_object_new(json_type_string); + size_t objsize; + struct json_object_string *jso; + + /* + * Structures Actual memory layout + * ------------------- -------------------- + * [json_object_string [json_object_string + * [json_object_base] [json_object_base] + * ...other fields... ...other fields... + * c_string] len + * bytes + * of + * string + * data + * \0] + */ + if (len > (SSIZE_T_MAX - (sizeof(*jso) - sizeof(jso->c_string)) - 1)) + return NULL; + objsize = (sizeof(*jso) - sizeof(jso->c_string)) + len + 1; + if (len < sizeof(void *)) + // We need a minimum size to support json_object_set_string() mutability + // so we can stuff a pointer into pdata :( + objsize += sizeof(void *) - len; + + jso = (struct json_object_string *)Xjson_object_new(json_type_string, objsize, + &json_object_string_to_json_string, &json_object_string_delete); + if (!jso) return NULL; - jso->_delete = &json_object_string_delete; - jso->_to_json_string = &json_object_string_to_json_string; - jso->o.c_string.len = strlen(s); - if (jso->o.c_string.len < LEN_DIRECT_STRING_DATA) - { - memcpy(jso->o.c_string.str.data, s, jso->o.c_string.len); - } - else - { - jso->o.c_string.str.ptr = strdup(s); - if (!jso->o.c_string.str.ptr) - { - json_object_generic_delete(jso); - errno = ENOMEM; - return NULL; - } - } - return jso; + jso->len = len; + memcpy(jso->c_string.idata, s, len); + jso->c_string.idata[len] = '\0'; + return PUBLIC(&jso->base); +} + +struct json_object *json_object_new_string(const char *s) +{ + return _json_object_new_string(s, strlen(s)); } struct json_object *json_object_new_string_len(const char *s, const int len) { - char *dstbuf; - struct json_object *jso = json_object_new(json_type_string); - if (!jso) - return NULL; - jso->_delete = &json_object_string_delete; - jso->_to_json_string = &json_object_string_to_json_string; - if (len < LEN_DIRECT_STRING_DATA) - { - dstbuf = jso->o.c_string.str.data; - } - else - { - jso->o.c_string.str.ptr = (char *)malloc(len + 1); - if (!jso->o.c_string.str.ptr) - { - json_object_generic_delete(jso); - errno = ENOMEM; - return NULL; - } - dstbuf = jso->o.c_string.str.ptr; - } - memcpy(dstbuf, (const void *)s, len); - dstbuf[len] = '\0'; - jso->o.c_string.len = len; - return jso; + return _json_object_new_string(s, len); } const char *json_object_get_string(struct json_object *jso) { +#define jso ((struct json_object_base *)jso) if (!jso) return NULL; switch (jso->o_type) { case json_type_string: return get_string_component(jso); - default: return json_object_to_json_string(jso); + default: return json_object_to_json_string(PUBLIC(jso)); } +#undef jso } - int json_object_get_string_len(const struct json_object *jso) { +#define jso ((const struct json_object_base *)jso) + ssize_t len; if (!jso) return 0; switch (jso->o_type) { - case json_type_string: return jso->o.c_string.len; + case json_type_string: + len = JC_STRING_C(jso)->len; + return (len < 0) ? -len : len; default: return 0; } +#undef jso } -int json_object_set_string(json_object *jso, const char *s) -{ - return json_object_set_string_len(jso, s, (int)(strlen(s))); -} - -int json_object_set_string_len(json_object *jso, const char *s, int len) +static int _json_object_set_string_len(json_object *jso, const char *s, size_t len) { +#define jso ((struct json_object_base *)jso) char *dstbuf; + ssize_t curlen; + ssize_t newlen; if (jso == NULL || jso->o_type != json_type_string) return 0; - if (len < LEN_DIRECT_STRING_DATA) - { - dstbuf = jso->o.c_string.str.data; - if (jso->o.c_string.len >= LEN_DIRECT_STRING_DATA) - free(jso->o.c_string.str.ptr); - } - else + + if (len >= SSIZE_T_MAX - 1) + // jso->len is a signed ssize_t, so it can't hold the + // full size_t range. + return 0; + + dstbuf = get_string_component_mutable(jso); + curlen = JC_STRING(jso)->len; + if (curlen < 0) + curlen = -curlen; + newlen = len; + + if ((ssize_t)len > curlen) { + // We have no way to return the new ptr from realloc(jso, newlen) + // and we have no way of knowing whether there's extra room available + // so we need to stuff a pointer in to pdata :( dstbuf = (char *)malloc(len + 1); if (dstbuf == NULL) return 0; - if (jso->o.c_string.len >= LEN_DIRECT_STRING_DATA) - free(jso->o.c_string.str.ptr); - jso->o.c_string.str.ptr = dstbuf; + if (JC_STRING(jso)->len < 0) + free(JC_STRING(jso)->c_string.pdata); + JC_STRING(jso)->c_string.pdata = dstbuf; + newlen = -len; + } + else if (JC_STRING(jso)->len < 0) + { + // We've got enough room in the separate allocated buffer, + // so use it as-is and continue to indicate that pdata is used. + newlen = -len; } - jso->o.c_string.len = len; + memcpy(dstbuf, (const void *)s, len); dstbuf[len] = '\0'; + JC_STRING(jso)->len = newlen; return 1; +#undef jso +} + +int json_object_set_string(json_object *jso, const char *s) +{ + return _json_object_set_string_len(jso, s, strlen(s)); +} + +int json_object_set_string_len(json_object *jso, const char *s, int len) +{ + return _json_object_set_string_len(jso, s, len); } /* json_object_array */ @@ -1582,7 +1633,7 @@ static void json_object_array_delete(struct json_object *jso) { #define jso ((struct json_object_base *)jso) array_list_free(JC_ARRAY(jso)->c_array); - json_object_generic_delete(PUBLIC(jso)); + Xjson_object_generic_delete(jso); #undef jso } @@ -1762,10 +1813,12 @@ static int Xjson_object_equal(struct json_object *jso1, struct json_object *jso2 return (jso1->o.c_int.cint.c_uint64 == (uint64_t)jso2->o.c_int.cint.c_int64); */ - case json_type_string: + case json_type_string: assert(0); + /* return (jso1->o.c_string.len == jso2->o.c_string.len && memcmp(get_string_component(jso1), get_string_component(jso2), jso1->o.c_string.len) == 0); + */ case json_type_object: assert(0); //return json_object_all_values_equal(jso1, jso2); @@ -1822,10 +1875,8 @@ int json_object_equal(struct json_object *jso1, struct json_object *jso2) case json_type_string: { - struct json_object_string *str1 = JC_STRING(jso1); - struct json_object_string *str2 = JC_STRING(jso2); - return (str1->len == str2->len && - memcmp(str1->data, str2->data, str1->len) == 0); + return (json_object_get_string_len(PUBLIC(jso1)) == json_object_get_string_len(PUBLIC(jso2)) && + memcmp(get_string_component(jso1), get_string_component(jso2), json_object_get_string_len(PUBLIC(jso1))) == 0); } case json_type_object: return json_object_all_values_equal(jso1, jso2); @@ -1920,7 +1971,6 @@ int json_c_shallow_copy_default(json_object *src, json_object *parent, const cha default: json_abort("invalid cint_type"); } break; -#undef src case json_type_string: *dst = json_object_new_string(get_string_component(src)); break; @@ -1939,6 +1989,7 @@ int json_c_shallow_copy_default(json_object *src, json_object *parent, const cha (*dst)->_to_json_string = src->_to_json_string; // _userdata and _user_delete are copied later return 1; +#undef src } /* diff --git a/json_object_private.h b/json_object_private.h index 5ea865c..bfe2b1c 100644 --- a/json_object_private.h +++ b/json_object_private.h @@ -46,7 +46,7 @@ struct json_object_base // XAX rename to json_object after conversion struct printbuf *_pb; json_object_delete_fn *_user_delete; void *_userdata; - char data[1]; // Actually a struct json_object_${o_type} + char data[1]; // Actually the rest of a struct json_object_${o_type} }; struct json_object_object @@ -83,8 +83,14 @@ struct json_object_int struct json_object_string { struct json_object_base base; - size_t len; - char data[1]; // Actually longer + ssize_t len; // Signed b/c negative lengths indicate data is a pointer + // Consider adding an "alloc" field here, if json_object_set_string calls + // to expand the length of a string are common operations to perform. + union + { + char idata[1]; // Immediate data. Actually longer + char *pdata; // Only when len < 0 + } c_string; }; struct json_object @@ -95,21 +101,9 @@ struct json_object json_object_private_delete_fn *_delete; json_object_to_json_string_fn *_to_json_string; struct printbuf *_pb; - union data - { - struct - { - union - { - /* optimize: if we have small strings, we can store them - * directly. This saves considerable CPU cycles AND memory. - */ - char *ptr; - char data[LEN_DIRECT_STRING_DATA]; - } str; - int len; - } c_string; - } o; + int dummyval; // XAX temp spacer to catch casting errors + int du1mmyval; // XAX spacer + int d2ummyval; // XAX spacer json_object_delete_fn *_user_delete; void *_userdata; }; diff --git a/tests/test_set_value.c b/tests/test_set_value.c index d6f1a33..eb0fe8b 100644 --- a/tests/test_set_value.c +++ b/tests/test_set_value.c @@ -58,12 +58,16 @@ int main(int argc, char **argv) #define HUGE "A string longer than 32 chars as to check non local buf codepath" tmp = json_object_new_string(SHORT); assert(strcmp(json_object_get_string(tmp), SHORT) == 0); + assert(strcmp(json_object_to_json_string(tmp), "\"" SHORT "\"") == 0); json_object_set_string(tmp, MID); assert(strcmp(json_object_get_string(tmp), MID) == 0); + assert(strcmp(json_object_to_json_string(tmp), "\"" MID "\"") == 0); json_object_set_string(tmp, HUGE); assert(strcmp(json_object_get_string(tmp), HUGE) == 0); + assert(strcmp(json_object_to_json_string(tmp), "\"" HUGE "\"") == 0); json_object_set_string(tmp, SHORT); assert(strcmp(json_object_get_string(tmp), SHORT) == 0); + assert(strcmp(json_object_to_json_string(tmp), "\"" SHORT "\"") == 0); json_object_put(tmp); printf("STRING PASSED\n"); From b0466b626be8075280ac69b6d63fe747955357e0 Mon Sep 17 00:00:00 2001 From: Eric Haszlakiewicz Date: Sun, 7 Jun 2020 03:27:13 +0000 Subject: [PATCH 08/19] On MSVC, add a ssize_t typedef using SSIZE_T from BaseTsd.h --- json_inttypes.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/json_inttypes.h b/json_inttypes.h index e047d4f..e51da74 100644 --- a/json_inttypes.h +++ b/json_inttypes.h @@ -21,4 +21,9 @@ #endif +#ifdef _MSC_VER +#include +typedef SSIZE_T ssize_t; +#endif + #endif From eab1375123d0ae1344dcfbfa80c6913b72803a13 Mon Sep 17 00:00:00 2001 From: Eric Haszlakiewicz Date: Sun, 7 Jun 2020 03:36:59 +0000 Subject: [PATCH 09/19] Change CMakeLists.txt to look for SSIZE_T on MSVC too. --- CMakeLists.txt | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 16d1336..1c0dd85 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -205,7 +205,12 @@ check_type_size(int64_t SIZEOF_INT64_T) check_type_size(long SIZEOF_LONG) check_type_size("long long" SIZEOF_LONG_LONG) check_type_size("size_t" SIZEOF_SIZE_T) +if ("${CMAKE_C_COMPILER_ID}" STREQUAL "MSVC") +list(APPEND CMAKE_EXTRA_INCLUDE_FILES BaseTsd.h) +check_type_size("SSIZE_T" SIZEOF_SIZE_T) +else() check_type_size("ssize_t" SIZEOF_SSIZE_T) +endif() check_c_source_compiles( [=[ From 0a16b23adf7de1222c91ba10277fdbd2e889b144 Mon Sep 17 00:00:00 2001 From: Eric Haszlakiewicz Date: Sun, 7 Jun 2020 15:19:29 +0000 Subject: [PATCH 10/19] Fix typo in previous commit to check for SSIZE_T on MSVC. --- CMakeLists.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 1c0dd85..50a6770 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -205,9 +205,9 @@ check_type_size(int64_t SIZEOF_INT64_T) check_type_size(long SIZEOF_LONG) check_type_size("long long" SIZEOF_LONG_LONG) check_type_size("size_t" SIZEOF_SIZE_T) -if ("${CMAKE_C_COMPILER_ID}" STREQUAL "MSVC") +if (MSVC) list(APPEND CMAKE_EXTRA_INCLUDE_FILES BaseTsd.h) -check_type_size("SSIZE_T" SIZEOF_SIZE_T) +check_type_size("SSIZE_T" SIZEOF_SSIZE_T) else() check_type_size("ssize_t" SIZEOF_SSIZE_T) endif() From c4cc6730715bd75d9776c6fe800e64bfacec510f Mon Sep 17 00:00:00 2001 From: Eric Haszlakiewicz Date: Sun, 7 Jun 2020 15:25:59 +0000 Subject: [PATCH 11/19] More fixes for old MSVC builds. --- json_object.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/json_object.c b/json_object.c index 7069f5d..dfe7bb2 100644 --- a/json_object.c +++ b/json_object.c @@ -1431,9 +1431,9 @@ static int json_object_string_to_json_string(struct json_object *jso, struct pri int level, int flags) { #define jso ((struct json_object_base *)jso) - printbuf_strappend(pb, "\""); ssize_t len = JC_STRING(jso)->len; - json_escape_str(pb, get_string_component(jso), len < 0 ? -len : len, flags); + printbuf_strappend(pb, "\""); + json_escape_str(pb, get_string_component(jso), len < 0 ? -(ssize_t)len : len, flags); printbuf_strappend(pb, "\""); return 0; #undef jso @@ -1517,7 +1517,7 @@ int json_object_get_string_len(const struct json_object *jso) { case json_type_string: len = JC_STRING_C(jso)->len; - return (len < 0) ? -len : len; + return (len < 0) ? -(ssize_t)len : len; default: return 0; } #undef jso @@ -1554,13 +1554,13 @@ static int _json_object_set_string_len(json_object *jso, const char *s, size_t l if (JC_STRING(jso)->len < 0) free(JC_STRING(jso)->c_string.pdata); JC_STRING(jso)->c_string.pdata = dstbuf; - newlen = -len; + newlen = -(ssize_t)len; } else if (JC_STRING(jso)->len < 0) { // We've got enough room in the separate allocated buffer, // so use it as-is and continue to indicate that pdata is used. - newlen = -len; + newlen = -(ssize_t)len; } memcpy(dstbuf, (const void *)s, len); From 66d91fdf86bb650201da37e704c29c197a1dadd9 Mon Sep 17 00:00:00 2001 From: Eric Haszlakiewicz Date: Sun, 7 Jun 2020 03:30:39 +0000 Subject: [PATCH 12/19] The split of json_object into type-specific sub-structures is now functionally complete. Remove all of the temporary defines, structures, old compat fuctions, extra fields, etc... that were needed during the conversion to a split set of json_object_* structures. --- json_object.c | 474 ++++++--------------------------- json_object.h | 3 +- json_object_private.h | 35 +-- tests/test_double_serializer.c | 2 +- tests/test_set_value.c | 8 +- 5 files changed, 89 insertions(+), 433 deletions(-) diff --git a/json_object.c b/json_object.c index dfe7bb2..bed97cd 100644 --- a/json_object.c +++ b/json_object.c @@ -1,6 +1,4 @@ /* - * $Id: json_object.c,v 1.17 2006/07/25 03:24:50 mclark Exp $ - * * Copyright (c) 2004, 2005 Metaparadigm Pte. Ltd. * Michael Clark * Copyright (c) 2009 Hewlett-Packard Development Company, L.P. @@ -60,8 +58,6 @@ const char *json_number_chars = "0123456789.+-eE"; const char *json_hex_chars = "0123456789abcdefABCDEF"; static void json_object_generic_delete(struct json_object *jso); -static void Xjson_object_generic_delete(struct json_object_base *jso); -static struct json_object *json_object_new(enum json_type o_type); #if defined(_MSC_VER) && (_MSC_VER <= 1800) /* VS2013 doesn't know about "inline" */ @@ -70,64 +66,54 @@ static struct json_object *json_object_new(enum json_type o_type); #define inline #endif -// XAX kill this once json_object_base is renamed back to json_object -static inline struct json_object *PUBLIC(struct json_object_base *jso) -{ - return (struct json_object *)jso; -} -static inline const struct json_object *PUBLIC_C(const struct json_object_base *jso) -{ - return (const struct json_object *)jso; -} - /* * Helper functions to more safely cast to a particular type of json_object */ -static inline struct json_object_object *JC_OBJECT(struct json_object_base *jso) +static inline struct json_object_object *JC_OBJECT(struct json_object *jso) { return (void *)jso; } -static inline const struct json_object_object *JC_OBJECT_C(const struct json_object_base *jso) +static inline const struct json_object_object *JC_OBJECT_C(const struct json_object *jso) { return (const void *)jso; } -static inline struct json_object_array *JC_ARRAY(struct json_object_base *jso) +static inline struct json_object_array *JC_ARRAY(struct json_object *jso) { return (void *)jso; } -static inline const struct json_object_array *JC_ARRAY_C(const struct json_object_base *jso) +static inline const struct json_object_array *JC_ARRAY_C(const struct json_object *jso) { return (const void *)jso; } -static inline struct json_object_boolean *JC_BOOL(struct json_object_base *jso) +static inline struct json_object_boolean *JC_BOOL(struct json_object *jso) { return (void *)jso; } -static inline const struct json_object_boolean *JC_BOOL_C(const struct json_object_base *jso) +static inline const struct json_object_boolean *JC_BOOL_C(const struct json_object *jso) { return (const void *)jso; } -static inline struct json_object_double *JC_DOUBLE(struct json_object_base *jso) +static inline struct json_object_double *JC_DOUBLE(struct json_object *jso) { return (void *)jso; } -static inline const struct json_object_double *JC_DOUBLE_C(const struct json_object_base *jso) +static inline const struct json_object_double *JC_DOUBLE_C(const struct json_object *jso) { return (const void *)jso; } -static inline struct json_object_int *JC_INT(struct json_object_base *jso) +static inline struct json_object_int *JC_INT(struct json_object *jso) { return (void *)jso; } -static inline const struct json_object_int *JC_INT_C(const struct json_object_base *jso) +static inline const struct json_object_int *JC_INT_C(const struct json_object *jso) { return (const void *)jso; } -static inline struct json_object_string *JC_STRING(struct json_object_base *jso) +static inline struct json_object_string *JC_STRING(struct json_object *jso) { return (void *)jso; } -static inline const struct json_object_string *JC_STRING_C(const struct json_object_base *jso) +static inline const struct json_object_string *JC_STRING_C(const struct json_object *jso) { return (const void *)jso; } @@ -136,11 +122,11 @@ static inline const struct json_object_string *JC_STRING_C(const struct json_obj #define JC_CONCAT3(a,b,c) a##b##c #define JSON_OBJECT_NEW(jtype, delete_fn) \ - (struct JC_CONCAT(json_object_,jtype) *)Xjson_object_new(JC_CONCAT(json_type_,jtype), \ + (struct JC_CONCAT(json_object_,jtype) *)json_object_new(JC_CONCAT(json_type_,jtype), \ sizeof(struct JC_CONCAT(json_object_,jtype)), \ &JC_CONCAT3(json_object_,jtype,_to_json_string), \ - (void *)delete_fn) // XAX drop cast -static inline struct json_object_base *Xjson_object_new(enum json_type o_type, + delete_fn) +static inline struct json_object *json_object_new(enum json_type o_type, size_t alloc_size, json_object_to_json_string_fn *to_json_string, json_object_private_delete_fn *delete_fn); @@ -209,7 +195,7 @@ static void json_object_fini(void) /* helper for accessing the optimized string data component in json_object */ -static inline char *get_string_component_mutable(struct json_object_base *jso) +static inline char *get_string_component_mutable(struct json_object *jso) { if (JC_STRING_C(jso)->len < 0) { @@ -218,7 +204,7 @@ static inline char *get_string_component_mutable(struct json_object_base *jso) } return JC_STRING(jso)->c_string.idata; } -static inline const char *get_string_component(const struct json_object_base *jso) +static inline const char *get_string_component(const struct json_object *jso) { return get_string_component_mutable((void *)(uintptr_t)(const void *)jso); } @@ -310,42 +296,10 @@ struct json_object *json_object_get(struct json_object *jso) return jso; } -// XAX remove this Xjson_object_put function once conversion is done -static int Xjson_object_put(struct json_object_base *jso) -{ - if (!jso) - return 0; - - /* Avoid invalid free and crash explicitly instead of (silently) - * segfaulting. - */ - assert(jso->_ref_count > 0); - -#if defined(HAVE_ATOMIC_BUILTINS) && defined(ENABLE_THREADING) - /* Note: this only allow the refcount to remain correct - * when multiple threads are adjusting it. It is still an error - * for a thread to decrement the refcount if it doesn't "own" it, - * as that can result in the thread that loses the race to 0 - * operating on an already-freed object. - */ - if (__sync_sub_and_fetch(&jso->_ref_count, 1) > 0) - return 0; -#else - if (--jso->_ref_count > 0) - return 0; -#endif - - if (jso->_user_delete) - jso->_user_delete(PUBLIC(jso), jso->_userdata); - jso->_delete(PUBLIC(jso)); - return 1; -} int json_object_put(struct json_object *jso) { if (!jso) return 0; - if (jso->newold) - return Xjson_object_put((struct json_object_base *)jso); /* Avoid invalid free and crash explicitly instead of (silently) * segfaulting. @@ -376,10 +330,6 @@ int json_object_put(struct json_object *jso) /* generic object construction and destruction parts */ static void json_object_generic_delete(struct json_object *jso) -{ - Xjson_object_generic_delete((void *)jso); -} -static void Xjson_object_generic_delete(struct json_object_base *jso) { #ifdef REFCOUNT_DEBUG MC_DEBUG("json_object_delete_%s: %p\n", json_type_to_name(jso->o_type), jso); @@ -389,37 +339,17 @@ static void Xjson_object_generic_delete(struct json_object_base *jso) free(jso); } -// XAX remove this once all is using new api -static inline struct json_object *json_object_new(enum json_type o_type) -{ - struct json_object *jso; - - jso = (struct json_object *)calloc(1, sizeof(struct json_object)); - if (!jso) - return NULL; - jso->o_type = o_type; - jso->_ref_count = 1; - jso->_delete = &json_object_generic_delete; - -#ifdef REFCOUNT_DEBUG - lh_table_insert(json_object_table, jso, jso); - MC_DEBUG("json_object_new_%s: %p\n", json_type_to_name(jso->o_type), jso); -#endif /* REFCOUNT_DEBUG */ - return jso; -} - -static inline struct json_object_base *Xjson_object_new(enum json_type o_type, +static inline struct json_object *json_object_new(enum json_type o_type, size_t alloc_size, json_object_to_json_string_fn *to_json_string, json_object_private_delete_fn *delete_fn) { - struct json_object_base *jso; + struct json_object *jso; - jso = (struct json_object_base *)malloc(alloc_size); + jso = (struct json_object *)malloc(alloc_size); if (!jso) return NULL; - jso->newold = 1; // XAX cut this after conversion jso->o_type = o_type; jso->_ref_count = 1; jso->_delete = delete_fn; @@ -440,111 +370,42 @@ static inline struct json_object_base *Xjson_object_new(enum json_type o_type, int json_object_is_type(const struct json_object *jso, enum json_type type) { -#define jso ((const struct json_object_base *)jso) if (!jso) return (type == json_type_null); return (jso->o_type == type); -#undef jso } enum json_type json_object_get_type(const struct json_object *jso) { -#define jso ((const struct json_object_base *)jso) if (!jso) return json_type_null; return jso->o_type; -#undef jso } void *json_object_get_userdata(json_object *jso) { - if (!jso->newold) - return jso ? jso->_userdata : NULL; -#define jso ((const struct json_object_base *)jso) return jso ? jso->_userdata : NULL; -#undef jso } -static void Xjson_object_set_userdata(json_object *jso, void *userdata, json_object_delete_fn *user_delete) -{ - // Can't return failure, so abort if we can't perform the operation. - assert(jso != NULL); - - // First, clean up any previously existing user info - if (jso->_user_delete) - jso->_user_delete(jso, jso->_userdata); - - jso->_userdata = userdata; - jso->_user_delete = user_delete; -} void json_object_set_userdata(json_object *jso, void *userdata, json_object_delete_fn *user_delete) { - // XAX call old code: - if (!jso->newold) - { - Xjson_object_set_userdata(jso, userdata, user_delete); - return; - } -#define jso ((struct json_object_base *)jso) // Can't return failure, so abort if we can't perform the operation. assert(jso != NULL); // First, clean up any previously existing user info if (jso->_user_delete) - jso->_user_delete(PUBLIC(jso), jso->_userdata); + jso->_user_delete(jso, jso->_userdata); jso->_userdata = userdata; jso->_user_delete = user_delete; -#undef jso } /* set a custom conversion to string */ -static void Xjson_object_set_serializer(json_object *jso, json_object_to_json_string_fn *to_string_func, - void *userdata, json_object_delete_fn *user_delete) -{ - json_object_set_userdata(jso, userdata, user_delete); - - if (to_string_func == NULL) - { - // Reset to the standard serialization function - switch (jso->o_type) - { - case json_type_null: jso->_to_json_string = NULL; break; - case json_type_boolean: - jso->_to_json_string = &json_object_boolean_to_json_string; - break; - case json_type_double: - jso->_to_json_string = &json_object_double_to_json_string_default; - break; - case json_type_int: jso->_to_json_string = &json_object_int_to_json_string; break; - case json_type_object: - jso->_to_json_string = &json_object_object_to_json_string; - break; - case json_type_array: - jso->_to_json_string = &json_object_array_to_json_string; - break; - case json_type_string: - jso->_to_json_string = &json_object_string_to_json_string; - break; - } - return; - } - - jso->_to_json_string = to_string_func; -} - void json_object_set_serializer(json_object *jso, json_object_to_json_string_fn *to_string_func, void *userdata, json_object_delete_fn *user_delete) { - // XAX call old code, remove after conversion: - if (jso && !jso->newold) - { - Xjson_object_set_serializer(jso, to_string_func, userdata, user_delete); - return; - } -#define jso ((struct json_object_base *)jso) - json_object_set_userdata(PUBLIC(jso), userdata, user_delete); + json_object_set_userdata(jso, userdata, user_delete); if (to_string_func == NULL) { @@ -573,14 +434,12 @@ void json_object_set_serializer(json_object *jso, json_object_to_json_string_fn } jso->_to_json_string = to_string_func; -#undef jso } /* extended conversion to string */ const char *json_object_to_json_string_length(struct json_object *jso, int flags, size_t *length) { -#define jso ((struct json_object_base *)jso) const char *r = NULL; size_t s = 0; @@ -593,7 +452,7 @@ const char *json_object_to_json_string_length(struct json_object *jso, int flags { printbuf_reset(jso->_pb); - if (jso->_to_json_string(PUBLIC(jso), jso->_pb, 0, flags) >= 0) + if (jso->_to_json_string(jso, jso->_pb, 0, flags) >= 0) { s = (size_t)jso->_pb->bpos; r = jso->_pb->buf; @@ -603,7 +462,6 @@ const char *json_object_to_json_string_length(struct json_object *jso, int flags if (length) *length = s; return r; -#undef jso } const char *json_object_to_json_string_ext(struct json_object *jso, int flags) @@ -638,7 +496,6 @@ static void indent(struct printbuf *pb, int level, int flags) static int json_object_object_to_json_string(struct json_object *jso, struct printbuf *pb, int level, int flags) { -#define jso ((struct json_object_base *)jso) int had_children = 0; struct json_object_iter iter; @@ -678,7 +535,6 @@ static int json_object_object_to_json_string(struct json_object *jso, struct pri return printbuf_strappend(pb, /*{*/ " }"); else return printbuf_strappend(pb, /*{*/ "}"); -#undef jso } static void json_object_lh_entry_free(struct lh_entry *ent) @@ -688,10 +544,10 @@ static void json_object_lh_entry_free(struct lh_entry *ent) json_object_put((struct json_object *)lh_entry_v(ent)); } -static void json_object_object_delete(struct json_object_base *jso_base) +static void json_object_object_delete(struct json_object *jso_base) { lh_table_free(JC_OBJECT(jso_base)->c_object); - Xjson_object_generic_delete(jso_base); + json_object_generic_delete(jso_base); } struct json_object *json_object_new_object(void) @@ -703,16 +559,15 @@ struct json_object *json_object_new_object(void) lh_kchar_table_new(JSON_OBJECT_DEF_HASH_ENTRIES, &json_object_lh_entry_free); if (!jso->c_object) { - Xjson_object_generic_delete(&jso->base); + json_object_generic_delete(&jso->base); errno = ENOMEM; return NULL; } - return PUBLIC(&jso->base); + return &jso->base; } struct lh_table *json_object_get_object(const struct json_object *jso) { -#define jso ((const struct json_object_base *)jso) if (!jso) return NULL; switch (jso->o_type) @@ -720,19 +575,16 @@ struct lh_table *json_object_get_object(const struct json_object *jso) case json_type_object: return JC_OBJECT_C(jso)->c_object; default: return NULL; } -#undef jso } int json_object_object_add_ex(struct json_object *jso, const char *const key, struct json_object *const val, const unsigned opts) { -#define jso ((struct json_object_base *)jso) -#define val ((struct json_object_base *)val) struct json_object *existing_value = NULL; struct lh_entry *existing_entry; unsigned long hash; - assert(json_object_get_type(PUBLIC(jso)) == json_type_object); + assert(json_object_get_type(jso) == json_type_object); // We lookup the entry and replace the value, rather than just deleting // and re-adding it, so the existing key remains valid. @@ -760,8 +612,6 @@ int json_object_object_add_ex(struct json_object *jso, const char *const key, json_object_put(existing_value); existing_entry->v = val; return 0; -#undef jso -#undef val } int json_object_object_add(struct json_object *jso, const char *key, struct json_object *val) @@ -771,10 +621,8 @@ int json_object_object_add(struct json_object *jso, const char *key, struct json int json_object_object_length(const struct json_object *jso) { -#define jso ((const struct json_object_base *)jso) - assert(json_object_get_type(PUBLIC_C(jso)) == json_type_object); + assert(json_object_get_type(jso) == json_type_object); return lh_table_length(JC_OBJECT_C(jso)->c_object); -#undef jso } @@ -793,7 +641,6 @@ struct json_object *json_object_object_get(const struct json_object *jso, const json_bool json_object_object_get_ex(const struct json_object *jso, const char *key, struct json_object **value) { -#define jso ((const struct json_object_base *)jso) if (value != NULL) *value = NULL; @@ -809,15 +656,12 @@ json_bool json_object_object_get_ex(const struct json_object *jso, const char *k *value = NULL; return 0; } -#undef jso } void json_object_object_del(struct json_object *jso, const char *key) { -#define jso ((struct json_object_base *)jso) - assert(json_object_get_type(PUBLIC(jso)) == json_type_object); + assert(json_object_get_type(jso) == json_type_object); lh_table_delete(JC_OBJECT(jso)->c_object, key); -#undef jso } /* json_object_boolean */ @@ -825,11 +669,9 @@ void json_object_object_del(struct json_object *jso, const char *key) static int json_object_boolean_to_json_string(struct json_object *jso, struct printbuf *pb, int level, int flags) { -#define jso ((struct json_object_base *)jso) if (JC_BOOL(jso)->c_boolean) return printbuf_strappend(pb, "true"); return printbuf_strappend(pb, "false"); -#undef jso } struct json_object *json_object_new_boolean(json_bool b) @@ -838,7 +680,7 @@ struct json_object *json_object_new_boolean(json_bool b) if (!jso) return NULL; jso->c_boolean = b; - return PUBLIC(&jso->base); + return &jso->base; } json_bool json_object_get_boolean(const struct json_object *jso) @@ -847,7 +689,6 @@ json_bool json_object_get_boolean(const struct json_object *jso) return 0; switch (jso->o_type) { -#define jso ((const struct json_object_base *)jso) case json_type_boolean: return JC_BOOL_C(jso)->c_boolean; case json_type_int: switch (JC_INT_C(jso)->cint_type) @@ -860,17 +701,14 @@ json_bool json_object_get_boolean(const struct json_object *jso) case json_type_string: return (JC_STRING_C(jso)->len != 0); default: return 0; } -#undef jso } int json_object_set_boolean(struct json_object *jso, json_bool new_value) { -#define jso ((struct json_object_base *)jso) if (!jso || jso->o_type != json_type_boolean) return 0; JC_BOOL(jso)->c_boolean = new_value; return 1; -#undef jso } /* json_object_int */ @@ -878,7 +716,6 @@ int json_object_set_boolean(struct json_object *jso, json_bool new_value) static int json_object_int_to_json_string(struct json_object *jso, struct printbuf *pb, int level, int flags) { -#define jso ((struct json_object_base *)jso) /* room for 19 digits, the sign char, and a null term */ char sbuf[21]; if (JC_INT(jso)->cint_type == json_object_int_type_int64) @@ -886,7 +723,6 @@ static int json_object_int_to_json_string(struct json_object *jso, struct printb else snprintf(sbuf, sizeof(sbuf), "%" PRIu64, JC_INT(jso)->cint.c_uint64); return printbuf_memappend(pb, sbuf, strlen(sbuf)); -#undef jso } struct json_object *json_object_new_int(int32_t i) @@ -896,7 +732,6 @@ struct json_object *json_object_new_int(int32_t i) int32_t json_object_get_int(const struct json_object *jso) { -#define jso ((const struct json_object_base *)jso) int64_t cint64; double cdouble; enum json_type o_type; @@ -950,7 +785,6 @@ int32_t json_object_get_int(const struct json_object *jso) case json_type_boolean: return JC_BOOL_C(jso)->c_boolean; default: return 0; } -#undef jso } int json_object_set_int(struct json_object *jso, int new_value) @@ -965,7 +799,7 @@ struct json_object *json_object_new_int64(int64_t i) return NULL; jso->cint.c_int64 = i; jso->cint_type = json_object_int_type_int64; - return PUBLIC(&jso->base); + return &jso->base; } struct json_object *json_object_new_uint64(uint64_t i) @@ -975,12 +809,11 @@ struct json_object *json_object_new_uint64(uint64_t i) return NULL; jso->cint.c_uint64 = i; jso->cint_type = json_object_int_type_uint64; - return PUBLIC(&jso->base); + return &jso->base; } int64_t json_object_get_int64(const struct json_object *jso) { -#define jso ((const struct json_object_base *)jso) int64_t cint; if (!jso) @@ -1015,12 +848,10 @@ int64_t json_object_get_int64(const struct json_object *jso) /* FALLTHRU */ default: return 0; } -#undef jso } uint64_t json_object_get_uint64(const struct json_object *jso) { -#define jso ((const struct json_object_base *)jso) uint64_t cuint; if (!jso) @@ -1055,34 +886,28 @@ uint64_t json_object_get_uint64(const struct json_object *jso) /* FALLTHRU */ default: return 0; } -#undef jso } int json_object_set_int64(struct json_object *jso, int64_t new_value) { -#define jso ((struct json_object_base *)jso) if (!jso || jso->o_type != json_type_int) return 0; JC_INT(jso)->cint.c_int64 = new_value; JC_INT(jso)->cint_type = json_object_int_type_int64; return 1; -#undef jso } int json_object_set_uint64(struct json_object *jso, uint64_t new_value) { -#define jso ((struct json_object_base *)jso) if (!jso || jso->o_type != json_type_int) return 0; JC_INT(jso)->cint.c_uint64 = new_value; JC_INT(jso)->cint_type = json_object_int_type_uint64; return 1; -#undef jso } int json_object_int_inc(struct json_object *jso, int64_t val) { -#define jso ((struct json_object_base *)jso) struct json_object_int *jsoint; if (!jso || jso->o_type != json_type_int) return 0; @@ -1126,7 +951,6 @@ int json_object_int_inc(struct json_object *jso, int64_t val) return 1; default: json_abort("invalid cint_type"); } -#undef jso } /* json_object_double */ @@ -1178,7 +1002,6 @@ int json_c_set_serialization_double_format(const char *double_format, int global static int json_object_double_to_json_string_format(struct json_object *jso, struct printbuf *pb, int level, int flags, const char *format) { -#define jso ((struct json_object_base *)jso) struct json_object_double *jsodbl = JC_DOUBLE(jso); char buf[128], *p, *q; int size; @@ -1268,24 +1091,19 @@ static int json_object_double_to_json_string_format(struct json_object *jso, str size = sizeof(buf) - 1; printbuf_memappend(pb, buf, size); return size; -#undef jso } static int json_object_double_to_json_string_default(struct json_object *jso, struct printbuf *pb, int level, int flags) { -#define jso ((struct json_object_base *)jso) - return json_object_double_to_json_string_format(PUBLIC(jso), pb, level, flags, NULL); -#undef jso + return json_object_double_to_json_string_format(jso, pb, level, flags, NULL); } int json_object_double_to_json_string(struct json_object *jso, struct printbuf *pb, int level, int flags) { -#define jso ((struct json_object_base *)jso) - return json_object_double_to_json_string_format(PUBLIC(jso), pb, level, flags, + return json_object_double_to_json_string_format(jso, pb, level, flags, (const char *)jso->_userdata); -#undef jso } struct json_object *json_object_new_double(double d) @@ -1295,7 +1113,7 @@ struct json_object *json_object_new_double(double d) return NULL; jso->base._to_json_string = &json_object_double_to_json_string_default; jso->c_double = d; - return PUBLIC(&jso->base); + return &jso->base; } struct json_object *json_object_new_double_s(double d, const char *ds) @@ -1331,21 +1149,9 @@ static int _json_object_userdata_to_json_string(struct json_object *jso, struct int json_object_userdata_to_json_string(struct json_object *jso, struct printbuf *pb, int level, int flags) { - // XAX old code compat, remove this - if (!jso->newold) - { - int userdata_len = strlen((const char *)jso->_userdata); - printbuf_memappend(pb, (const char *)jso->_userdata, userdata_len); - return userdata_len; - } - else - { -#define jso ((const struct json_object_base *)jso) int userdata_len = strlen((const char *)jso->_userdata); printbuf_memappend(pb, (const char *)jso->_userdata, userdata_len); return userdata_len; -#undef jso - } } void json_object_free_userdata(struct json_object *jso, void *userdata) @@ -1355,7 +1161,6 @@ void json_object_free_userdata(struct json_object *jso, void *userdata) double json_object_get_double(const struct json_object *jso) { -#define jso ((const struct json_object_base *)jso) double cdouble; char *errPtr = NULL; @@ -1410,19 +1215,16 @@ double json_object_get_double(const struct json_object *jso) return cdouble; default: errno = EINVAL; return 0.0; } -#undef jso } int json_object_set_double(struct json_object *jso, double new_value) { -#define jso ((struct json_object_base *)jso) if (!jso || jso->o_type != json_type_double) return 0; JC_DOUBLE(jso)->c_double = new_value; if (jso->_to_json_string == &_json_object_userdata_to_json_string) - json_object_set_serializer(PUBLIC(jso), NULL, NULL, NULL); + json_object_set_serializer(jso, NULL, NULL, NULL); return 1; -#undef jso } /* json_object_string */ @@ -1430,22 +1232,18 @@ int json_object_set_double(struct json_object *jso, double new_value) static int json_object_string_to_json_string(struct json_object *jso, struct printbuf *pb, int level, int flags) { -#define jso ((struct json_object_base *)jso) ssize_t len = JC_STRING(jso)->len; printbuf_strappend(pb, "\""); json_escape_str(pb, get_string_component(jso), len < 0 ? -(ssize_t)len : len, flags); printbuf_strappend(pb, "\""); return 0; -#undef jso } static void json_object_string_delete(struct json_object *jso) { -#define jso ((struct json_object_base *)jso) if (JC_STRING(jso)->len < 0) free(JC_STRING(jso)->c_string.pdata); - Xjson_object_generic_delete(jso); -#undef jso + json_object_generic_delete(jso); } static struct json_object *_json_object_new_string(const char *s, const size_t len) @@ -1457,7 +1255,7 @@ static struct json_object *_json_object_new_string(const char *s, const size_t l * Structures Actual memory layout * ------------------- -------------------- * [json_object_string [json_object_string - * [json_object_base] [json_object_base] + * [json_object] [json_object] * ...other fields... ...other fields... * c_string] len * bytes @@ -1474,7 +1272,7 @@ static struct json_object *_json_object_new_string(const char *s, const size_t l // so we can stuff a pointer into pdata :( objsize += sizeof(void *) - len; - jso = (struct json_object_string *)Xjson_object_new(json_type_string, objsize, + jso = (struct json_object_string *)json_object_new(json_type_string, objsize, &json_object_string_to_json_string, &json_object_string_delete); if (!jso) @@ -1482,7 +1280,7 @@ static struct json_object *_json_object_new_string(const char *s, const size_t l jso->len = len; memcpy(jso->c_string.idata, s, len); jso->c_string.idata[len] = '\0'; - return PUBLIC(&jso->base); + return &jso->base; } struct json_object *json_object_new_string(const char *s) @@ -1497,19 +1295,16 @@ struct json_object *json_object_new_string_len(const char *s, const int len) const char *json_object_get_string(struct json_object *jso) { -#define jso ((struct json_object_base *)jso) if (!jso) return NULL; switch (jso->o_type) { case json_type_string: return get_string_component(jso); - default: return json_object_to_json_string(PUBLIC(jso)); + default: return json_object_to_json_string(jso); } -#undef jso } int json_object_get_string_len(const struct json_object *jso) { -#define jso ((const struct json_object_base *)jso) ssize_t len; if (!jso) return 0; @@ -1520,12 +1315,10 @@ int json_object_get_string_len(const struct json_object *jso) return (len < 0) ? -(ssize_t)len : len; default: return 0; } -#undef jso } static int _json_object_set_string_len(json_object *jso, const char *s, size_t len) { -#define jso ((struct json_object_base *)jso) char *dstbuf; ssize_t curlen; ssize_t newlen; @@ -1567,7 +1360,6 @@ static int _json_object_set_string_len(json_object *jso, const char *s, size_t l dstbuf[len] = '\0'; JC_STRING(jso)->len = newlen; return 1; -#undef jso } int json_object_set_string(json_object *jso, const char *s) @@ -1585,14 +1377,13 @@ int json_object_set_string_len(json_object *jso, const char *s, int len) static int json_object_array_to_json_string(struct json_object *jso, struct printbuf *pb, int level, int flags) { -#define jso ((struct json_object_base *)jso) int had_children = 0; size_t ii; printbuf_strappend(pb, "["); if (flags & JSON_C_TO_STRING_PRETTY) printbuf_strappend(pb, "\n"); - for (ii = 0; ii < json_object_array_length(PUBLIC(jso)); ii++) + for (ii = 0; ii < json_object_array_length(jso); ii++) { struct json_object *val; if (had_children) @@ -1605,7 +1396,7 @@ static int json_object_array_to_json_string(struct json_object *jso, struct prin if (flags & JSON_C_TO_STRING_SPACED && !(flags & JSON_C_TO_STRING_PRETTY)) printbuf_strappend(pb, " "); indent(pb, level + 1, flags); - val = json_object_array_get_idx(PUBLIC(jso), ii); + val = json_object_array_get_idx(jso, ii); if (val == NULL) printbuf_strappend(pb, "null"); else if (val->_to_json_string(val, pb, level + 1, flags) < 0) @@ -1621,7 +1412,6 @@ static int json_object_array_to_json_string(struct json_object *jso, struct prin if (flags & JSON_C_TO_STRING_SPACED && !(flags & JSON_C_TO_STRING_PRETTY)) return printbuf_strappend(pb, " ]"); return printbuf_strappend(pb, "]"); -#undef jso } static void json_object_array_entry_free(void *data) @@ -1631,10 +1421,8 @@ static void json_object_array_entry_free(void *data) static void json_object_array_delete(struct json_object *jso) { -#define jso ((struct json_object_base *)jso) array_list_free(JC_ARRAY(jso)->c_array); - Xjson_object_generic_delete(jso); -#undef jso + json_object_generic_delete(jso); } struct json_object *json_object_new_array(void) @@ -1648,12 +1436,11 @@ struct json_object *json_object_new_array(void) free(jso); return NULL; } - return PUBLIC(&jso->base); + return &jso->base; } struct array_list *json_object_get_array(const struct json_object *jso) { -#define jso ((const struct json_object_base *)jso) if (!jso) return NULL; switch (jso->o_type) @@ -1661,72 +1448,57 @@ struct array_list *json_object_get_array(const struct json_object *jso) case json_type_array: return JC_ARRAY_C(jso)->c_array; default: return NULL; } -#undef jso } void json_object_array_sort(struct json_object *jso, int (*sort_fn)(const void *, const void *)) { -#define jso ((struct json_object_base *)jso) - assert(json_object_get_type(PUBLIC(jso)) == json_type_array); + assert(json_object_get_type(jso) == json_type_array); array_list_sort(JC_ARRAY(jso)->c_array, sort_fn); -#undef jso } struct json_object *json_object_array_bsearch(const struct json_object *key, const struct json_object *jso, int (*sort_fn)(const void *, const void *)) { -#define jso ((const struct json_object_base *)jso) struct json_object **result; - assert(json_object_get_type(PUBLIC_C(jso)) == json_type_array); + assert(json_object_get_type(jso) == json_type_array); result = (struct json_object **)array_list_bsearch((const void **)(void *)&key, JC_ARRAY_C(jso)->c_array, sort_fn); if (!result) return NULL; return *result; -#undef jso } size_t json_object_array_length(const struct json_object *jso) { -#define jso ((const struct json_object_base *)jso) - assert(json_object_get_type(PUBLIC_C(jso)) == json_type_array); + assert(json_object_get_type(jso) == json_type_array); return array_list_length(JC_ARRAY_C(jso)->c_array); -#undef jso } int json_object_array_add(struct json_object *jso, struct json_object *val) { -#define jso ((struct json_object_base *)jso) - assert(json_object_get_type(PUBLIC_C(jso)) == json_type_array); + assert(json_object_get_type(jso) == json_type_array); return array_list_add(JC_ARRAY(jso)->c_array, val); -#undef jso } int json_object_array_put_idx(struct json_object *jso, size_t idx, struct json_object *val) { -#define jso ((struct json_object_base *)jso) - assert(json_object_get_type(PUBLIC_C(jso)) == json_type_array); + assert(json_object_get_type(jso) == json_type_array); return array_list_put_idx(JC_ARRAY(jso)->c_array, idx, val); -#undef jso } int json_object_array_del_idx(struct json_object *jso, size_t idx, size_t count) { -#define jso ((struct json_object_base *)jso) - assert(json_object_get_type(PUBLIC_C(jso)) == json_type_array); + assert(json_object_get_type(jso) == json_type_array); return array_list_del_idx(JC_ARRAY(jso)->c_array, idx, count); -#undef jso } struct json_object *json_object_array_get_idx(const struct json_object *jso, size_t idx) { -#define jso ((const struct json_object_base *)jso) - assert(json_object_get_type(PUBLIC_C(jso)) == json_type_array); + assert(json_object_get_type(jso) == json_type_array); return (struct json_object *)array_list_get_idx(JC_ARRAY_C(jso)->c_array, idx); -#undef jso } static int json_array_equal(struct json_object *jso1, struct json_object *jso2) @@ -1751,13 +1523,13 @@ struct json_object *json_object_new_null(void) return NULL; } -static int json_object_all_values_equal(struct json_object_base *jso1, struct json_object_base *jso2) +static int json_object_all_values_equal(struct json_object *jso1, struct json_object *jso2) { struct json_object_iter iter; struct json_object *sub; - assert(json_object_get_type(PUBLIC(jso1)) == json_type_object); - assert(json_object_get_type(PUBLIC(jso2)) == json_type_object); + assert(json_object_get_type(jso1) == json_type_object); + assert(json_object_get_type(jso2) == json_type_object); /* Iterate over jso1 keys and see if they exist and are equal in jso2 */ json_object_object_foreachC(jso1, iter) { @@ -1777,58 +1549,6 @@ static int json_object_all_values_equal(struct json_object_base *jso1, struct js return 1; } -static int Xjson_object_equal(struct json_object *jso1, struct json_object *jso2) -{ - if (jso1 == jso2) - return 1; - - if (!jso1 || !jso2) - return 0; - - if (jso1->o_type != jso2->o_type) - return 0; - - switch (jso1->o_type) - { - case json_type_boolean: assert(0); //return (jso1->o.c_boolean == jso2->o.c_boolean); - - case json_type_double: assert(0); // return (jso1->o.c_double == jso2->o.c_double); - - case json_type_int: assert(0); - /* - if (jso1->o.c_int.cint_type == json_object_int_type_int64) - { - if (jso2->o.c_int.cint_type == json_object_int_type_int64) - return (jso1->o.c_int.cint.c_int64 == jso2->o.c_int.cint.c_int64); - if (jso1->o.c_int.cint.c_int64 < 0) - return 0; - return ((uint64_t)jso1->o.c_int.cint.c_int64 == - jso2->o.c_int.cint.c_uint64); - } - // else jso1 is a uint64 - if (jso2->o.c_int.cint_type == json_object_int_type_uint64) - return (jso1->o.c_int.cint.c_uint64 == jso2->o.c_int.cint.c_uint64); - if (jso2->o.c_int.cint.c_int64 < 0) - return 0; - return (jso1->o.c_int.cint.c_uint64 == (uint64_t)jso2->o.c_int.cint.c_int64); - */ - - case json_type_string: assert(0); - /* - return (jso1->o.c_string.len == jso2->o.c_string.len && - memcmp(get_string_component(jso1), get_string_component(jso2), - jso1->o.c_string.len) == 0); - */ - - case json_type_object: assert(0); //return json_object_all_values_equal(jso1, jso2); - - case json_type_array: assert(0); //return json_array_equal(jso1, jso2); - - case json_type_null: return 1; - }; - - return 0; -} int json_object_equal(struct json_object *jso1, struct json_object *jso2) { if (jso1 == jso2) @@ -1837,12 +1557,6 @@ int json_object_equal(struct json_object *jso1, struct json_object *jso2) if (!jso1 || !jso2) return 0; - // XAX cut this after conversion - if (!jso1->newold && !jso2->newold) - return Xjson_object_equal(jso1, jso2); // call old code - -#define jso1 ((struct json_object_base *)jso1) -#define jso2 ((struct json_object_base *)jso2) if (jso1->o_type != jso2->o_type) return 0; @@ -1875,50 +1589,22 @@ int json_object_equal(struct json_object *jso1, struct json_object *jso2) case json_type_string: { - return (json_object_get_string_len(PUBLIC(jso1)) == json_object_get_string_len(PUBLIC(jso2)) && - memcmp(get_string_component(jso1), get_string_component(jso2), json_object_get_string_len(PUBLIC(jso1))) == 0); + return (json_object_get_string_len(jso1) == json_object_get_string_len(jso2) && + memcmp(get_string_component(jso1), get_string_component(jso2), json_object_get_string_len(jso1)) == 0); } case json_type_object: return json_object_all_values_equal(jso1, jso2); - case json_type_array: return json_array_equal(PUBLIC(jso1), PUBLIC(jso2)); + case json_type_array: return json_array_equal(jso1, jso2); case json_type_null: return 1; }; return 0; -#undef jso1 -#undef jso2 } -// XAX remove this function after code conversion -static int Xjson_object_copy_serializer_data(struct json_object *src, struct json_object *dst) -{ - if (!src->_userdata && !src->_user_delete) - return 0; - - if (dst->_to_json_string == json_object_userdata_to_json_string || - dst->_to_json_string == _json_object_userdata_to_json_string) - { - dst->_userdata = strdup(src->_userdata); - } - // else if ... other supported serializers ... - else - { - _json_c_set_last_err( - "json_object_deep_copy: unable to copy unknown serializer data: %p\n", - dst->_to_json_string); - return -1; - } - dst->_user_delete = src->_user_delete; - return 0; -} static int json_object_copy_serializer_data(struct json_object *src, struct json_object *dst) { - if (!src->newold) - return Xjson_object_copy_serializer_data(src, dst); -#define src ((struct json_object_base *)src) -#define dst ((struct json_object_base *)dst) if (!src->_userdata && !src->_user_delete) return 0; @@ -1937,8 +1623,6 @@ static int json_object_copy_serializer_data(struct json_object *src, struct json } dst->_user_delete = src->_user_delete; return 0; -#undef src -#undef dst } /** @@ -1954,7 +1638,6 @@ int json_c_shallow_copy_default(json_object *src, json_object *parent, const cha { switch (src->o_type) { -#define src ((struct json_object_base *)src) case json_type_boolean: *dst = json_object_new_boolean(JC_BOOL(src)->c_boolean); break; case json_type_double: *dst = json_object_new_double(JC_DOUBLE(src)->c_double); break; @@ -1989,7 +1672,6 @@ int json_c_shallow_copy_default(json_object *src, json_object *parent, const cha (*dst)->_to_json_string = src->_to_json_string; // _userdata and _user_delete are copied later return 1; -#undef src } /* @@ -1998,16 +1680,16 @@ int json_c_shallow_copy_default(json_object *src, json_object *parent, const cha * * Note: caller is responsible for freeing *dst if this fails and returns -1. */ -static int json_object_deep_copy_recursive(struct json_object_base *src, struct json_object_base *parent, +static int json_object_deep_copy_recursive(struct json_object *src, struct json_object *parent, const char *key_in_parent, size_t index_in_parent, - struct json_object_base **dst, + struct json_object **dst, json_c_shallow_copy_fn *shallow_copy) { struct json_object_iter iter; size_t src_array_len, ii; int shallow_copy_rc = 0; - shallow_copy_rc = shallow_copy(PUBLIC(src), PUBLIC(parent), key_in_parent, index_in_parent, (struct json_object **)dst); // XAX remove cast too + shallow_copy_rc = shallow_copy(src, parent, key_in_parent, index_in_parent, dst); /* -1=error, 1=object created ok, 2=userdata set */ if (shallow_copy_rc < 1) { @@ -2021,44 +1703,44 @@ static int json_object_deep_copy_recursive(struct json_object_base *src, struct case json_type_object: json_object_object_foreachC(src, iter) { - struct json_object_base *jso = NULL; + struct json_object *jso = NULL; /* This handles the `json_type_null` case */ if (!iter.val) jso = NULL; - else if (json_object_deep_copy_recursive((struct json_object_base *)/*XAX removecast*/iter.val, src, iter.key, -1, &jso, + else if (json_object_deep_copy_recursive(iter.val, src, iter.key, -1, &jso, shallow_copy) < 0) { - json_object_put(PUBLIC(jso)); + json_object_put(jso); return -1; } - if (json_object_object_add(PUBLIC(*dst), iter.key, PUBLIC(jso)) < 0) + if (json_object_object_add(*dst, iter.key, jso) < 0) { - json_object_put(PUBLIC(jso)); + json_object_put(jso); return -1; } } break; case json_type_array: - src_array_len = json_object_array_length(PUBLIC(src)); + src_array_len = json_object_array_length(src); for (ii = 0; ii < src_array_len; ii++) { - struct json_object_base *jso = NULL; - struct json_object_base *jso1 = (struct json_object_base *)/*XAXremovecast*/json_object_array_get_idx(PUBLIC(src), ii); + struct json_object *jso = NULL; + struct json_object *jso1 = json_object_array_get_idx(src, ii); /* This handles the `json_type_null` case */ if (!jso1) jso = NULL; else if (json_object_deep_copy_recursive(jso1, src, NULL, ii, &jso, shallow_copy) < 0) { - json_object_put(PUBLIC(jso)); + json_object_put(jso); return -1; } - if (json_object_array_add(PUBLIC(*dst), PUBLIC(jso)) < 0) + if (json_object_array_add(*dst, jso) < 0) { - json_object_put(PUBLIC(jso)); + json_object_put(jso); return -1; } } @@ -2070,7 +1752,7 @@ static int json_object_deep_copy_recursive(struct json_object_base *src, struct } if (shallow_copy_rc != 2) - return json_object_copy_serializer_data(PUBLIC(src), PUBLIC(*dst)); + return json_object_copy_serializer_data(src, *dst); return 0; } @@ -2078,9 +1760,6 @@ static int json_object_deep_copy_recursive(struct json_object_base *src, struct int json_object_deep_copy(struct json_object *src, struct json_object **dst, json_c_shallow_copy_fn *shallow_copy) { -#define src ((struct json_object_base *)src) -#define parent ((struct json_object_base *)parent) -#define dst ((struct json_object_base **)dst) int rc; /* Check if arguments are sane ; *dst must not point to a non-NULL object */ @@ -2096,14 +1775,11 @@ int json_object_deep_copy(struct json_object *src, struct json_object **dst, rc = json_object_deep_copy_recursive(src, NULL, NULL, -1, dst, shallow_copy); if (rc < 0) { - json_object_put(PUBLIC(*dst)); + json_object_put(*dst); *dst = NULL; } return rc; -#undef src -#undef parent -#undef dst } static void json_abort(const char *message) diff --git a/json_object.h b/json_object.h index 1805bda..7c0d1f2 100644 --- a/json_object.h +++ b/json_object.h @@ -490,9 +490,8 @@ JSON_EXPORT void json_object_object_del(struct json_object *obj, const char *key * @param obj the json_object instance * @param iter the object iterator, use type json_object_iter */ -// XAX temporary workaround during code conversion: #define json_object_object_foreachC(obj, iter) \ - for (iter.entry = json_object_get_object(PUBLIC(obj))->head; \ + for (iter.entry = json_object_get_object(obj)->head; \ (iter.entry ? (iter.key = (char *)lh_entry_k(iter.entry), \ iter.val = (struct json_object *)lh_entry_v(iter.entry), iter.entry) \ : 0); \ diff --git a/json_object_private.h b/json_object_private.h index bfe2b1c..c7b4d1f 100644 --- a/json_object_private.h +++ b/json_object_private.h @@ -20,14 +20,11 @@ extern "C" { #endif -/**< how many bytes are directly stored in json_object for strings? */ -#define LEN_DIRECT_STRING_DATA 32 - struct json_object; #include "json_inttypes.h" #include "json_types.h" -typedef void(json_object_private_delete_fn)(struct json_object *o); +typedef void (json_object_private_delete_fn)(struct json_object *o); /* json object int type, support extension*/ typedef enum json_object_int_type @@ -36,9 +33,8 @@ typedef enum json_object_int_type json_object_int_type_uint64 } json_object_int_type; -struct json_object_base // XAX rename to json_object after conversion +struct json_object { - int newold; // XAX temporary, remove after code conversion enum json_type o_type; uint32_t _ref_count; json_object_private_delete_fn *_delete; @@ -51,28 +47,28 @@ struct json_object_base // XAX rename to json_object after conversion struct json_object_object { - struct json_object_base base; + struct json_object base; struct lh_table *c_object; }; struct json_object_array { - struct json_object_base base; + struct json_object base; struct array_list *c_array; }; struct json_object_boolean { - struct json_object_base base; + struct json_object base; json_bool c_boolean; }; struct json_object_double { - struct json_object_base base; + struct json_object base; double c_double; }; struct json_object_int { - struct json_object_base base; + struct json_object base; enum json_object_int_type cint_type; union { @@ -82,7 +78,7 @@ struct json_object_int }; struct json_object_string { - struct json_object_base base; + struct json_object base; ssize_t len; // Signed b/c negative lengths indicate data is a pointer // Consider adding an "alloc" field here, if json_object_set_string calls // to expand the length of a string are common operations to perform. @@ -93,21 +89,6 @@ struct json_object_string } c_string; }; -struct json_object -{ - int newold; - enum json_type o_type; - uint32_t _ref_count; - json_object_private_delete_fn *_delete; - json_object_to_json_string_fn *_to_json_string; - struct printbuf *_pb; - int dummyval; // XAX temp spacer to catch casting errors - int du1mmyval; // XAX spacer - int d2ummyval; // XAX spacer - json_object_delete_fn *_user_delete; - void *_userdata; -}; - void _json_c_set_last_err(const char *err_fmt, ...); extern const char *json_number_chars; diff --git a/tests/test_double_serializer.c b/tests/test_double_serializer.c index 98f6dd9..38de6b5 100644 --- a/tests/test_double_serializer.c +++ b/tests/test_double_serializer.c @@ -20,7 +20,7 @@ int main() printf("obj.to_string(standard)=%s\n", json_object_to_json_string(obj)); printf("Test default serializer with custom userdata:\n"); - ((struct json_object_base *)obj)->_userdata = udata; + ((struct json_object *)obj)->_userdata = udata; printf("obj.to_string(userdata)=%s\n", json_object_to_json_string(obj)); printf("Test explicit serializer with custom userdata:\n"); diff --git a/tests/test_set_value.c b/tests/test_set_value.c index eb0fe8b..157e64f 100644 --- a/tests/test_set_value.c +++ b/tests/test_set_value.c @@ -56,12 +56,12 @@ int main(int argc, char **argv) #define MID "A MID STRING" // 12345678901234567890123456789012.... #define HUGE "A string longer than 32 chars as to check non local buf codepath" - tmp = json_object_new_string(SHORT); - assert(strcmp(json_object_get_string(tmp), SHORT) == 0); - assert(strcmp(json_object_to_json_string(tmp), "\"" SHORT "\"") == 0); - json_object_set_string(tmp, MID); + tmp = json_object_new_string(MID); assert(strcmp(json_object_get_string(tmp), MID) == 0); assert(strcmp(json_object_to_json_string(tmp), "\"" MID "\"") == 0); + json_object_set_string(tmp, SHORT); + assert(strcmp(json_object_get_string(tmp), SHORT) == 0); + assert(strcmp(json_object_to_json_string(tmp), "\"" SHORT "\"") == 0); json_object_set_string(tmp, HUGE); assert(strcmp(json_object_get_string(tmp), HUGE) == 0); assert(strcmp(json_object_to_json_string(tmp), "\"" HUGE "\"") == 0); From ecdfeb18cf8df1bf519785f3353d1e4ab87c3a9c Mon Sep 17 00:00:00 2001 From: Eric Haszlakiewicz Date: Sun, 7 Jun 2020 18:29:56 +0000 Subject: [PATCH 13/19] Move the ssize_t typedef from json_inttypes.h to json_object_private.h so as not to affect publically exposed symbols. --- json_inttypes.h | 5 ----- json_object_private.h | 5 +++++ 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/json_inttypes.h b/json_inttypes.h index e51da74..e047d4f 100644 --- a/json_inttypes.h +++ b/json_inttypes.h @@ -21,9 +21,4 @@ #endif -#ifdef _MSC_VER -#include -typedef SSIZE_T ssize_t; -#endif - #endif diff --git a/json_object_private.h b/json_object_private.h index c7b4d1f..8132a33 100644 --- a/json_object_private.h +++ b/json_object_private.h @@ -24,6 +24,11 @@ struct json_object; #include "json_inttypes.h" #include "json_types.h" +#ifdef _MSC_VER +#include +typedef SSIZE_T ssize_t; +#endif + typedef void (json_object_private_delete_fn)(struct json_object *o); /* json object int type, support extension*/ From 02fe2e0ccd77dfed8ae02e4abd8d41c5379364f7 Mon Sep 17 00:00:00 2001 From: Eric Haszlakiewicz Date: Sun, 7 Jun 2020 18:45:17 +0000 Subject: [PATCH 14/19] Summarize the changes from the json_object-split branch in the ChangeLog. --- ChangeLog | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/ChangeLog b/ChangeLog index 8a58d19..afb5155 100644 --- a/ChangeLog +++ b/ChangeLog @@ -12,6 +12,13 @@ Other changes * Issue #471: always create directories with mode 0755, regardless of umask. * Added a JSON_TOKENER_ALLOW_TRAILING_CHARS flag to allow multiple objects to be parsed even when JSON_TOKENER_STRICT is set. +* Split the internal json_object structure into several sub-types, one for + each json_type (json_object_object, json_object_string, etc...). + This improves memory usage and speed, with the benchmark under + bench/ report 5.8% faster test time and 6%(max RSS)-12%(peak heap) + less memory usage. + Memory used just for json_object structures decreased 27%, so use cases + with fewer arrays and/or strings would benefit more. *** From 85c244f04807689621fca58075ab4946fad5e996 Mon Sep 17 00:00:00 2001 From: Eric Haszlakiewicz Date: Sun, 7 Jun 2020 18:50:10 +0000 Subject: [PATCH 15/19] Eliminate unnecessary cast that was added to test_double_serializer. --- tests/test_double_serializer.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_double_serializer.c b/tests/test_double_serializer.c index 38de6b5..8b2487a 100644 --- a/tests/test_double_serializer.c +++ b/tests/test_double_serializer.c @@ -20,7 +20,7 @@ int main() printf("obj.to_string(standard)=%s\n", json_object_to_json_string(obj)); printf("Test default serializer with custom userdata:\n"); - ((struct json_object *)obj)->_userdata = udata; + obj->_userdata = udata; printf("obj.to_string(userdata)=%s\n", json_object_to_json_string(obj)); printf("Test explicit serializer with custom userdata:\n"); From 4c10712114a79d1abf0d98ac165648a6aa36d45a Mon Sep 17 00:00:00 2001 From: Eric Haszlakiewicz Date: Sat, 13 Jun 2020 18:25:32 +0000 Subject: [PATCH 16/19] Drop the useless "char data[1]" from struct json_object. Fix a typo in a comment. --- json_object.c | 2 +- json_object_private.h | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/json_object.c b/json_object.c index bed97cd..8615ff5 100644 --- a/json_object.c +++ b/json_object.c @@ -199,7 +199,7 @@ static inline char *get_string_component_mutable(struct json_object *jso) { if (JC_STRING_C(jso)->len < 0) { - /* Due to json_object_str_string(), we might have a pointer */ + /* Due to json_object_set_string(), we might have a pointer */ return JC_STRING(jso)->c_string.pdata; } return JC_STRING(jso)->c_string.idata; diff --git a/json_object_private.h b/json_object_private.h index 8132a33..7cd90c2 100644 --- a/json_object_private.h +++ b/json_object_private.h @@ -47,7 +47,8 @@ struct json_object struct printbuf *_pb; json_object_delete_fn *_user_delete; void *_userdata; - char data[1]; // Actually the rest of a struct json_object_${o_type} + // Actually longer, always malloc'd as some more-specific type. + // The rest of a struct json_object_${o_type} follows }; struct json_object_object From 5ebfeaedc5413452aff7fa733abfabe97df100e8 Mon Sep 17 00:00:00 2001 From: Eric Haszlakiewicz Date: Sat, 13 Jun 2020 18:34:35 +0000 Subject: [PATCH 17/19] Drop the _delete field from struct json_object and call the type-specific delete functions directly from json_object_put. (Thanks @dota17 for the suggestion in PR #632!) --- json_object.c | 46 ++++++++++++++++++++++++++++--------------- json_object_private.h | 3 --- 2 files changed, 30 insertions(+), 19 deletions(-) diff --git a/json_object.c b/json_object.c index 8615ff5..42d4efd 100644 --- a/json_object.c +++ b/json_object.c @@ -121,15 +121,17 @@ static inline const struct json_object_string *JC_STRING_C(const struct json_obj #define JC_CONCAT(a,b) a##b #define JC_CONCAT3(a,b,c) a##b##c -#define JSON_OBJECT_NEW(jtype, delete_fn) \ +#define JSON_OBJECT_NEW(jtype) \ (struct JC_CONCAT(json_object_,jtype) *)json_object_new(JC_CONCAT(json_type_,jtype), \ sizeof(struct JC_CONCAT(json_object_,jtype)), \ - &JC_CONCAT3(json_object_,jtype,_to_json_string), \ - delete_fn) + &JC_CONCAT3(json_object_,jtype,_to_json_string)) static inline struct json_object *json_object_new(enum json_type o_type, size_t alloc_size, - json_object_to_json_string_fn *to_json_string, - json_object_private_delete_fn *delete_fn); + json_object_to_json_string_fn *to_json_string); + +static void json_object_object_delete(struct json_object *jso_base); +static void json_object_string_delete(struct json_object *jso); +static void json_object_array_delete(struct json_object *jso); static json_object_to_json_string_fn json_object_object_to_json_string; static json_object_to_json_string_fn json_object_boolean_to_json_string; @@ -322,7 +324,21 @@ int json_object_put(struct json_object *jso) if (jso->_user_delete) jso->_user_delete(jso, jso->_userdata); - jso->_delete(jso); + switch(jso->o_type) + { + case json_type_object: + json_object_object_delete(jso); + break; + case json_type_array: + json_object_array_delete(jso); + break; + case json_type_string: + json_object_string_delete(jso); + break; + default: + json_object_generic_delete(jso); + break; + } return 1; } @@ -341,8 +357,7 @@ static void json_object_generic_delete(struct json_object *jso) static inline struct json_object *json_object_new(enum json_type o_type, size_t alloc_size, - json_object_to_json_string_fn *to_json_string, - json_object_private_delete_fn *delete_fn) + json_object_to_json_string_fn *to_json_string) { struct json_object *jso; @@ -352,7 +367,6 @@ static inline struct json_object *json_object_new(enum json_type o_type, jso->o_type = o_type; jso->_ref_count = 1; - jso->_delete = delete_fn; jso->_to_json_string = to_json_string; jso->_pb = NULL; jso->_user_delete = NULL; @@ -552,7 +566,7 @@ static void json_object_object_delete(struct json_object *jso_base) struct json_object *json_object_new_object(void) { - struct json_object_object *jso = JSON_OBJECT_NEW(object, &json_object_object_delete); + struct json_object_object *jso = JSON_OBJECT_NEW(object); if (!jso) return NULL; jso->c_object = @@ -676,7 +690,7 @@ static int json_object_boolean_to_json_string(struct json_object *jso, struct pr struct json_object *json_object_new_boolean(json_bool b) { - struct json_object_boolean *jso = JSON_OBJECT_NEW(boolean, &json_object_generic_delete); + struct json_object_boolean *jso = JSON_OBJECT_NEW(boolean); if (!jso) return NULL; jso->c_boolean = b; @@ -794,7 +808,7 @@ int json_object_set_int(struct json_object *jso, int new_value) struct json_object *json_object_new_int64(int64_t i) { - struct json_object_int *jso = JSON_OBJECT_NEW(int, &json_object_generic_delete); + struct json_object_int *jso = JSON_OBJECT_NEW(int); if (!jso) return NULL; jso->cint.c_int64 = i; @@ -804,7 +818,7 @@ struct json_object *json_object_new_int64(int64_t i) struct json_object *json_object_new_uint64(uint64_t i) { - struct json_object_int *jso = JSON_OBJECT_NEW(int, &json_object_generic_delete); + struct json_object_int *jso = JSON_OBJECT_NEW(int); if (!jso) return NULL; jso->cint.c_uint64 = i; @@ -1108,7 +1122,7 @@ int json_object_double_to_json_string(struct json_object *jso, struct printbuf * struct json_object *json_object_new_double(double d) { - struct json_object_double *jso = JSON_OBJECT_NEW(double, &json_object_generic_delete); + struct json_object_double *jso = JSON_OBJECT_NEW(double); if (!jso) return NULL; jso->base._to_json_string = &json_object_double_to_json_string_default; @@ -1273,7 +1287,7 @@ static struct json_object *_json_object_new_string(const char *s, const size_t l objsize += sizeof(void *) - len; jso = (struct json_object_string *)json_object_new(json_type_string, objsize, - &json_object_string_to_json_string, &json_object_string_delete); + &json_object_string_to_json_string); if (!jso) return NULL; @@ -1427,7 +1441,7 @@ static void json_object_array_delete(struct json_object *jso) struct json_object *json_object_new_array(void) { - struct json_object_array *jso = JSON_OBJECT_NEW(array, &json_object_array_delete); + struct json_object_array *jso = JSON_OBJECT_NEW(array); if (!jso) return NULL; jso->c_array = array_list_new(&json_object_array_entry_free); diff --git a/json_object_private.h b/json_object_private.h index 7cd90c2..4413955 100644 --- a/json_object_private.h +++ b/json_object_private.h @@ -29,8 +29,6 @@ struct json_object; typedef SSIZE_T ssize_t; #endif -typedef void (json_object_private_delete_fn)(struct json_object *o); - /* json object int type, support extension*/ typedef enum json_object_int_type { @@ -42,7 +40,6 @@ struct json_object { enum json_type o_type; uint32_t _ref_count; - json_object_private_delete_fn *_delete; json_object_to_json_string_fn *_to_json_string; struct printbuf *_pb; json_object_delete_fn *_user_delete; From 9128ec49b126ad996468ab4df290916241e2864d Mon Sep 17 00:00:00 2001 From: Eric Haszlakiewicz Date: Sun, 14 Jun 2020 03:11:44 +0000 Subject: [PATCH 18/19] Include unistd.h to fix the build on OSX --- json_object_iterator.c | 1 + json_object_private.h | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/json_object_iterator.c b/json_object_iterator.c index 796015e..1c2b3f2 100644 --- a/json_object_iterator.c +++ b/json_object_iterator.c @@ -9,6 +9,7 @@ * ******************************************************************************* */ +#include "config.h" #include diff --git a/json_object_private.h b/json_object_private.h index 4413955..d8dacd2 100644 --- a/json_object_private.h +++ b/json_object_private.h @@ -24,6 +24,10 @@ struct json_object; #include "json_inttypes.h" #include "json_types.h" +#ifdef HAVE_UNISTD_H +#include +#endif /* HAVE_UNISTD_H */ + #ifdef _MSC_VER #include typedef SSIZE_T ssize_t; From 0710c835a1558f13e143da449fdd8c44956733e6 Mon Sep 17 00:00:00 2001 From: Eric Haszlakiewicz Date: Tue, 16 Jun 2020 13:17:58 +0000 Subject: [PATCH 19/19] Reformat the json_object-split branch with clang-format --- json_object.c | 69 +++++++++++++++++++------------------------ json_object_private.h | 2 +- 2 files changed, 32 insertions(+), 39 deletions(-) diff --git a/json_object.c b/json_object.c index 42d4efd..be84cb0 100644 --- a/json_object.c +++ b/json_object.c @@ -118,16 +118,16 @@ static inline const struct json_object_string *JC_STRING_C(const struct json_obj return (const void *)jso; } -#define JC_CONCAT(a,b) a##b -#define JC_CONCAT3(a,b,c) a##b##c +#define JC_CONCAT(a, b) a##b +#define JC_CONCAT3(a, b, c) a##b##c -#define JSON_OBJECT_NEW(jtype) \ - (struct JC_CONCAT(json_object_,jtype) *)json_object_new(JC_CONCAT(json_type_,jtype), \ - sizeof(struct JC_CONCAT(json_object_,jtype)), \ - &JC_CONCAT3(json_object_,jtype,_to_json_string)) -static inline struct json_object *json_object_new(enum json_type o_type, - size_t alloc_size, - json_object_to_json_string_fn *to_json_string); +#define JSON_OBJECT_NEW(jtype) \ + (struct JC_CONCAT(json_object_, jtype) *)json_object_new( \ + JC_CONCAT(json_type_, jtype), sizeof(struct JC_CONCAT(json_object_, jtype)), \ + &JC_CONCAT3(json_object_, jtype, _to_json_string)) + +static inline struct json_object *json_object_new(enum json_type o_type, size_t alloc_size, + json_object_to_json_string_fn *to_json_string); static void json_object_object_delete(struct json_object *jso_base); static void json_object_string_delete(struct json_object *jso); @@ -324,25 +324,16 @@ int json_object_put(struct json_object *jso) if (jso->_user_delete) jso->_user_delete(jso, jso->_userdata); - switch(jso->o_type) + switch (jso->o_type) { - case json_type_object: - json_object_object_delete(jso); - break; - case json_type_array: - json_object_array_delete(jso); - break; - case json_type_string: - json_object_string_delete(jso); - break; - default: - json_object_generic_delete(jso); - break; + case json_type_object: json_object_object_delete(jso); break; + case json_type_array: json_object_array_delete(jso); break; + case json_type_string: json_object_string_delete(jso); break; + default: json_object_generic_delete(jso); break; } return 1; } - /* generic object construction and destruction parts */ static void json_object_generic_delete(struct json_object *jso) @@ -355,9 +346,8 @@ static void json_object_generic_delete(struct json_object *jso) free(jso); } -static inline struct json_object *json_object_new(enum json_type o_type, - size_t alloc_size, - json_object_to_json_string_fn *to_json_string) +static inline struct json_object *json_object_new(enum json_type o_type, size_t alloc_size, + json_object_to_json_string_fn *to_json_string) { struct json_object *jso; @@ -370,7 +360,7 @@ static inline struct json_object *json_object_new(enum json_type o_type, jso->_to_json_string = to_json_string; jso->_pb = NULL; jso->_user_delete = NULL; - jso->_userdata= NULL; + jso->_userdata = NULL; //jso->... // Type-specific fields must be set by caller #ifdef REFCOUNT_DEBUG @@ -639,7 +629,6 @@ int json_object_object_length(const struct json_object *jso) return lh_table_length(JC_OBJECT_C(jso)->c_object); } - size_t json_c_object_sizeof(void) { return sizeof(struct json_object); @@ -664,7 +653,8 @@ json_bool json_object_object_get_ex(const struct json_object *jso, const char *k switch (jso->o_type) { case json_type_object: - return lh_table_lookup_ex(JC_OBJECT_C(jso)->c_object, (const void *)key, (void **)value); + return lh_table_lookup_ex(JC_OBJECT_C(jso)->c_object, (const void *)key, + (void **)value); default: if (value != NULL) *value = NULL; @@ -931,8 +921,7 @@ int json_object_int_inc(struct json_object *jso, int64_t val) case json_object_int_type_int64: if (val > 0 && jsoint->cint.c_int64 > INT64_MAX - val) { - jsoint->cint.c_uint64 = - (uint64_t)jsoint->cint.c_int64 + (uint64_t)val; + jsoint->cint.c_uint64 = (uint64_t)jsoint->cint.c_int64 + (uint64_t)val; jsoint->cint_type = json_object_int_type_uint64; } else if (val < 0 && jsoint->cint.c_int64 < INT64_MIN - val) @@ -1286,8 +1275,8 @@ static struct json_object *_json_object_new_string(const char *s, const size_t l // so we can stuff a pointer into pdata :( objsize += sizeof(void *) - len; - jso = (struct json_object_string *)json_object_new(json_type_string, objsize, - &json_object_string_to_json_string); + jso = (struct json_object_string *)json_object_new(json_type_string, objsize, + &json_object_string_to_json_string); if (!jso) return NULL; @@ -1325,8 +1314,10 @@ int json_object_get_string_len(const struct json_object *jso) switch (jso->o_type) { case json_type_string: + { len = JC_STRING_C(jso)->len; return (len < 0) ? -(ssize_t)len : len; + } default: return 0; } } @@ -1547,7 +1538,8 @@ static int json_object_all_values_equal(struct json_object *jso1, struct json_ob /* Iterate over jso1 keys and see if they exist and are equal in jso2 */ json_object_object_foreachC(jso1, iter) { - if (!lh_table_lookup_ex(JC_OBJECT(jso2)->c_object, (void *)iter.key, (void **)(void *)&sub)) + if (!lh_table_lookup_ex(JC_OBJECT(jso2)->c_object, (void *)iter.key, + (void **)(void *)&sub)) return 0; if (!json_object_equal(iter.val, sub)) return 0; @@ -1556,7 +1548,8 @@ static int json_object_all_values_equal(struct json_object *jso1, struct json_ob /* Iterate over jso2 keys to see if any exist that are not in jso1 */ json_object_object_foreachC(jso2, iter) { - if (!lh_table_lookup_ex(JC_OBJECT(jso1)->c_object, (void *)iter.key, (void **)(void *)&sub)) + if (!lh_table_lookup_ex(JC_OBJECT(jso1)->c_object, (void *)iter.key, + (void **)(void *)&sub)) return 0; } @@ -1590,8 +1583,7 @@ int json_object_equal(struct json_object *jso1, struct json_object *jso2) return (int1->cint.c_int64 == int2->cint.c_int64); if (int1->cint.c_int64 < 0) return 0; - return ((uint64_t)int1->cint.c_int64 == - int2->cint.c_uint64); + return ((uint64_t)int1->cint.c_int64 == int2->cint.c_uint64); } // else jso1 is a uint64 if (int2->cint_type == json_object_int_type_uint64) @@ -1604,7 +1596,8 @@ int json_object_equal(struct json_object *jso1, struct json_object *jso2) case json_type_string: { return (json_object_get_string_len(jso1) == json_object_get_string_len(jso2) && - memcmp(get_string_component(jso1), get_string_component(jso2), json_object_get_string_len(jso1)) == 0); + memcmp(get_string_component(jso1), get_string_component(jso2), + json_object_get_string_len(jso1)) == 0); } case json_type_object: return json_object_all_values_equal(jso1, jso2); diff --git a/json_object_private.h b/json_object_private.h index d8dacd2..d1d782e 100644 --- a/json_object_private.h +++ b/json_object_private.h @@ -86,7 +86,7 @@ struct json_object_int struct json_object_string { struct json_object base; - ssize_t len; // Signed b/c negative lengths indicate data is a pointer + ssize_t len; // Signed b/c negative lengths indicate data is a pointer // Consider adding an "alloc" field here, if json_object_set_string calls // to expand the length of a string are common operations to perform. union