From 0758caaac02826fbda6179ce072cd37d343dc1cf Mon Sep 17 00:00:00 2001 From: Maxim Zhukov Date: Thu, 6 Aug 2020 20:33:54 +0300 Subject: reuse key len from loop check for better performance Signed-off-by: Maxim Zhukov --- src/dump.c | 53 +++++++++++++++++++++++++++++++++++---------------- src/jansson_private.h | 4 ++-- src/load.c | 4 ++-- src/value.c | 34 ++++++++++++++++++++------------- 4 files changed, 62 insertions(+), 33 deletions(-) diff --git a/src/dump.c b/src/dump.c index 7e14db4..c0fb06e 100644 --- a/src/dump.c +++ b/src/dump.c @@ -195,8 +195,21 @@ static int dump_string(const char *str, size_t len, json_dump_callback_t dump, v return dump("\"", 1, data); } +struct key_len { + const char *key; + int len; +}; + static int compare_keys(const void *key1, const void *key2) { - return strcmp(*(const char **)key1, *(const char **)key2); + const struct key_len *k1 = key1; + const struct key_len *k2 = key2; + const size_t min_size = k1->len < k2->len ? k1->len : k2->len; + int res = memcmp(k1->key, k2->key, min_size); + + if (res) + return res; + + return k1->len - k2->len; } static int do_dump(const json_t *json, size_t flags, int depth, hashtable_t *parents, @@ -253,9 +266,10 @@ static int do_dump(const json_t *json, size_t flags, int depth, hashtable_t *par /* Space for "0x", double the sizeof a pointer for the hex and a * terminator. */ char key[2 + (sizeof(json) * 2) + 1]; + size_t key_len; /* detect circular references */ - if (jsonp_loop_check(parents, json, key, sizeof(key))) + if (jsonp_loop_check(parents, json, key, sizeof(key), &key_len)) return -1; n = json_array_size(json); @@ -263,7 +277,7 @@ static int do_dump(const json_t *json, size_t flags, int depth, hashtable_t *par if (!embed && dump("[", 1, data)) return -1; if (n == 0) { - hashtable_del(parents, key, strlen(key)); + hashtable_del(parents, key, key_len); return embed ? 0 : dump("]", 1, data); } if (dump_indent(flags, depth + 1, 0, dump, data)) @@ -284,7 +298,7 @@ static int do_dump(const json_t *json, size_t flags, int depth, hashtable_t *par } } - hashtable_del(parents, key, strlen(key)); + hashtable_del(parents, key, key_len); return embed ? 0 : dump("]", 1, data); } @@ -293,6 +307,7 @@ static int do_dump(const json_t *json, size_t flags, int depth, hashtable_t *par const char *separator; int separator_length; char loop_key[LOOP_KEY_LEN]; + size_t loop_key_len; if (flags & JSON_COMPACT) { separator = ":"; @@ -303,7 +318,8 @@ static int do_dump(const json_t *json, size_t flags, int depth, hashtable_t *par } /* detect circular references */ - if (jsonp_loop_check(parents, json, loop_key, sizeof(loop_key))) + if (jsonp_loop_check(parents, json, loop_key, sizeof(loop_key), + &loop_key_len)) return -1; iter = json_object_iter((json_t *)json); @@ -311,40 +327,44 @@ static int do_dump(const json_t *json, size_t flags, int depth, hashtable_t *par if (!embed && dump("{", 1, data)) return -1; if (!iter) { - hashtable_del(parents, loop_key, strlen(loop_key)); + hashtable_del(parents, loop_key, loop_key_len); return embed ? 0 : dump("}", 1, data); } if (dump_indent(flags, depth + 1, 0, dump, data)) return -1; if (flags & JSON_SORT_KEYS) { - const char **keys; + struct key_len *keys; size_t size, i; size = json_object_size(json); - keys = jsonp_malloc(size * sizeof(const char *)); + keys = jsonp_malloc(size * sizeof(struct key_len)); if (!keys) return -1; i = 0; while (iter) { - keys[i] = json_object_iter_key(iter); + struct key_len *keylen = &keys[i]; + + keylen->key = json_object_iter_key(iter); + keylen->len = json_object_iter_key_len(iter); + iter = json_object_iter_next((json_t *)json, iter); i++; } assert(i == size); - qsort(keys, size, sizeof(const char *), compare_keys); + qsort(keys, size, sizeof(struct key_len), compare_keys); for (i = 0; i < size; i++) { - const char *key; + const struct key_len *key; json_t *value; - key = keys[i]; - value = json_object_get(json, key); + key = &keys[i]; + value = json_object_getn(json, key->key, key->len); assert(value); - dump_string(key, strlen(key), dump, data, flags); + dump_string(key->key, key->len, dump, data, flags); if (dump(separator, separator_length, data) || do_dump(value, flags, depth + 1, parents, dump, data)) { jsonp_free(keys); @@ -372,8 +392,9 @@ static int do_dump(const json_t *json, size_t flags, int depth, hashtable_t *par while (iter) { void *next = json_object_iter_next((json_t *)json, iter); const char *key = json_object_iter_key(iter); + const size_t key_len = json_object_iter_key_len(iter); - dump_string(key, strlen(key), dump, data, flags); + dump_string(key, key_len, dump, data, flags); if (dump(separator, separator_length, data) || do_dump(json_object_iter_value(iter), flags, depth + 1, parents, dump, data)) @@ -392,7 +413,7 @@ static int do_dump(const json_t *json, size_t flags, int depth, hashtable_t *par } } - hashtable_del(parents, loop_key, strlen(loop_key)); + hashtable_del(parents, loop_key, loop_key_len); return embed ? 0 : dump("}", 1, data); } diff --git a/src/jansson_private.h b/src/jansson_private.h index d3b2a64..ea2593c 100644 --- a/src/jansson_private.h +++ b/src/jansson_private.h @@ -91,8 +91,8 @@ char *jsonp_strndup(const char *str, size_t len) JANSSON_ATTRS((warn_unused_resu /* Circular reference check*/ /* Space for "0x", double the sizeof a pointer for the hex and a terminator. */ #define LOOP_KEY_LEN (2 + (sizeof(json_t *) * 2) + 1) -int jsonp_loop_check(hashtable_t *parents, const json_t *json, char *key, - size_t key_size); +int jsonp_loop_check(hashtable_t *parents, const json_t *json, char *key, size_t key_size, + size_t *key_len_out); /* Windows compatibility */ #if defined(_WIN32) || defined(WIN32) diff --git a/src/load.c b/src/load.c index ea6692f..8ae7abd 100644 --- a/src/load.c +++ b/src/load.c @@ -689,7 +689,7 @@ static json_t *parse_object(lex_t *lex, size_t flags, json_error_t *error) { } if (flags & JSON_REJECT_DUPLICATES) { - if (json_object_get(object, key)) { + if (json_object_getn(object, key, len)) { jsonp_free(key); error_set(error, lex, json_error_duplicate_key, "duplicate object key"); goto error; @@ -710,7 +710,7 @@ static json_t *parse_object(lex_t *lex, size_t flags, json_error_t *error) { goto error; } - if (json_object_set_new_nocheck(object, key, value)) { + if (json_object_setn_new_nocheck(object, key, len, value)) { jsonp_free(key); goto error; } diff --git a/src/value.c b/src/value.c index 6cb79c5..07af087 100644 --- a/src/value.c +++ b/src/value.c @@ -44,10 +44,13 @@ static JSON_INLINE void json_init(json_t *json, json_type type) { json->refcount = 1; } -int jsonp_loop_check(hashtable_t *parents, const json_t *json, char *key, - size_t key_size) { +int jsonp_loop_check(hashtable_t *parents, const json_t *json, char *key, size_t key_size, + size_t *key_len_out) { size_t key_len = snprintf(key, key_size, "%p", json); + if (key_len_out) + *key_len_out = key_len; + if (hashtable_get(parents, key, key_len)) return -1; @@ -203,14 +206,15 @@ int json_object_update(json_t *object, json_t *other) { int json_object_update_existing(json_t *object, json_t *other) { const char *key; + size_t key_len; json_t *value; if (!json_is_object(object) || !json_is_object(other)) return -1; - json_object_foreach(other, key, value) { - if (json_object_get(object, key)) - json_object_set_nocheck(object, key, value); + json_object_keylen_foreach(other, key, key_len, value) { + if (json_object_getn(object, key, key_len)) + json_object_setn_nocheck(object, key, key_len, value); } return 0; @@ -233,17 +237,19 @@ int json_object_update_missing(json_t *object, json_t *other) { int do_object_update_recursive(json_t *object, json_t *other, hashtable_t *parents) { const char *key; + size_t key_len; json_t *value; char loop_key[LOOP_KEY_LEN]; int res = 0; + size_t loop_key_len; if (!json_is_object(object) || !json_is_object(other)) return -1; - if (jsonp_loop_check(parents, other, loop_key, sizeof(loop_key))) + if (jsonp_loop_check(parents, other, loop_key, sizeof(loop_key), &loop_key_len)) return -1; - json_object_foreach(other, key, value) { + json_object_keylen_foreach(other, key, key_len, value) { json_t *v = json_object_get(object, key); if (json_is_object(v) && json_is_object(value)) { @@ -252,14 +258,14 @@ int do_object_update_recursive(json_t *object, json_t *other, hashtable_t *paren break; } } else { - if (json_object_set_nocheck(object, key, value)) { + if (json_object_setn_nocheck(object, key, key_len, value)) { res = -1; break; } } } - hashtable_del(parents, loop_key, strlen(loop_key)); + hashtable_del(parents, loop_key, loop_key_len); return res; } @@ -380,8 +386,9 @@ static json_t *json_object_deep_copy(const json_t *object, hashtable_t *parents) json_t *result; void *iter; char loop_key[LOOP_KEY_LEN]; + size_t loop_key_len; - if (jsonp_loop_check(parents, object, loop_key, sizeof(loop_key))) + if (jsonp_loop_check(parents, object, loop_key, sizeof(loop_key), &loop_key_len)) return NULL; result = json_object(); @@ -406,7 +413,7 @@ static json_t *json_object_deep_copy(const json_t *object, hashtable_t *parents) } out: - hashtable_del(parents, loop_key, strlen(loop_key)); + hashtable_del(parents, loop_key, loop_key_len); return result; } @@ -673,8 +680,9 @@ static json_t *json_array_deep_copy(const json_t *array, hashtable_t *parents) { json_t *result; size_t i; char loop_key[LOOP_KEY_LEN]; + size_t loop_key_len; - if (jsonp_loop_check(parents, array, loop_key, sizeof(loop_key))) + if (jsonp_loop_check(parents, array, loop_key, sizeof(loop_key), &loop_key_len)) return NULL; result = json_array(); @@ -691,7 +699,7 @@ static json_t *json_array_deep_copy(const json_t *array, hashtable_t *parents) { } out: - hashtable_del(parents, loop_key, strlen(loop_key)); + hashtable_del(parents, loop_key, loop_key_len); return result; } -- cgit v1.1