reuse key len from loop check for better performance
Signed-off-by: Maxim Zhukov <mussitantesmortem@gmail.com>
This commit is contained in:
parent
16a3899a9e
commit
0758caaac0
53
src/dump.c
53
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);
|
return dump("\"", 1, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct key_len {
|
||||||
|
const char *key;
|
||||||
|
int len;
|
||||||
|
};
|
||||||
|
|
||||||
static int compare_keys(const void *key1, const void *key2) {
|
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,
|
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
|
/* Space for "0x", double the sizeof a pointer for the hex and a
|
||||||
* terminator. */
|
* terminator. */
|
||||||
char key[2 + (sizeof(json) * 2) + 1];
|
char key[2 + (sizeof(json) * 2) + 1];
|
||||||
|
size_t key_len;
|
||||||
|
|
||||||
/* detect circular references */
|
/* 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;
|
return -1;
|
||||||
|
|
||||||
n = json_array_size(json);
|
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))
|
if (!embed && dump("[", 1, data))
|
||||||
return -1;
|
return -1;
|
||||||
if (n == 0) {
|
if (n == 0) {
|
||||||
hashtable_del(parents, key, strlen(key));
|
hashtable_del(parents, key, key_len);
|
||||||
return embed ? 0 : dump("]", 1, data);
|
return embed ? 0 : dump("]", 1, data);
|
||||||
}
|
}
|
||||||
if (dump_indent(flags, depth + 1, 0, dump, 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);
|
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;
|
const char *separator;
|
||||||
int separator_length;
|
int separator_length;
|
||||||
char loop_key[LOOP_KEY_LEN];
|
char loop_key[LOOP_KEY_LEN];
|
||||||
|
size_t loop_key_len;
|
||||||
|
|
||||||
if (flags & JSON_COMPACT) {
|
if (flags & JSON_COMPACT) {
|
||||||
separator = ":";
|
separator = ":";
|
||||||
@ -303,7 +318,8 @@ static int do_dump(const json_t *json, size_t flags, int depth, hashtable_t *par
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* detect circular references */
|
/* 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;
|
return -1;
|
||||||
|
|
||||||
iter = json_object_iter((json_t *)json);
|
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))
|
if (!embed && dump("{", 1, data))
|
||||||
return -1;
|
return -1;
|
||||||
if (!iter) {
|
if (!iter) {
|
||||||
hashtable_del(parents, loop_key, strlen(loop_key));
|
hashtable_del(parents, loop_key, loop_key_len);
|
||||||
return embed ? 0 : dump("}", 1, data);
|
return embed ? 0 : dump("}", 1, data);
|
||||||
}
|
}
|
||||||
if (dump_indent(flags, depth + 1, 0, dump, data))
|
if (dump_indent(flags, depth + 1, 0, dump, data))
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
if (flags & JSON_SORT_KEYS) {
|
if (flags & JSON_SORT_KEYS) {
|
||||||
const char **keys;
|
struct key_len *keys;
|
||||||
size_t size, i;
|
size_t size, i;
|
||||||
|
|
||||||
size = json_object_size(json);
|
size = json_object_size(json);
|
||||||
keys = jsonp_malloc(size * sizeof(const char *));
|
keys = jsonp_malloc(size * sizeof(struct key_len));
|
||||||
if (!keys)
|
if (!keys)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
i = 0;
|
i = 0;
|
||||||
while (iter) {
|
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);
|
iter = json_object_iter_next((json_t *)json, iter);
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
assert(i == size);
|
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++) {
|
for (i = 0; i < size; i++) {
|
||||||
const char *key;
|
const struct key_len *key;
|
||||||
json_t *value;
|
json_t *value;
|
||||||
|
|
||||||
key = keys[i];
|
key = &keys[i];
|
||||||
value = json_object_get(json, key);
|
value = json_object_getn(json, key->key, key->len);
|
||||||
assert(value);
|
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) ||
|
if (dump(separator, separator_length, data) ||
|
||||||
do_dump(value, flags, depth + 1, parents, dump, data)) {
|
do_dump(value, flags, depth + 1, parents, dump, data)) {
|
||||||
jsonp_free(keys);
|
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) {
|
while (iter) {
|
||||||
void *next = json_object_iter_next((json_t *)json, iter);
|
void *next = json_object_iter_next((json_t *)json, iter);
|
||||||
const char *key = json_object_iter_key(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) ||
|
if (dump(separator, separator_length, data) ||
|
||||||
do_dump(json_object_iter_value(iter), flags, depth + 1, parents,
|
do_dump(json_object_iter_value(iter), flags, depth + 1, parents,
|
||||||
dump, data))
|
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);
|
return embed ? 0 : dump("}", 1, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -91,8 +91,8 @@ char *jsonp_strndup(const char *str, size_t len) JANSSON_ATTRS((warn_unused_resu
|
|||||||
/* Circular reference check*/
|
/* Circular reference check*/
|
||||||
/* Space for "0x", double the sizeof a pointer for the hex and a terminator. */
|
/* Space for "0x", double the sizeof a pointer for the hex and a terminator. */
|
||||||
#define LOOP_KEY_LEN (2 + (sizeof(json_t *) * 2) + 1)
|
#define LOOP_KEY_LEN (2 + (sizeof(json_t *) * 2) + 1)
|
||||||
int jsonp_loop_check(hashtable_t *parents, const json_t *json, char *key,
|
int jsonp_loop_check(hashtable_t *parents, const json_t *json, char *key, size_t key_size,
|
||||||
size_t key_size);
|
size_t *key_len_out);
|
||||||
|
|
||||||
/* Windows compatibility */
|
/* Windows compatibility */
|
||||||
#if defined(_WIN32) || defined(WIN32)
|
#if defined(_WIN32) || defined(WIN32)
|
||||||
|
@ -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 (flags & JSON_REJECT_DUPLICATES) {
|
||||||
if (json_object_get(object, key)) {
|
if (json_object_getn(object, key, len)) {
|
||||||
jsonp_free(key);
|
jsonp_free(key);
|
||||||
error_set(error, lex, json_error_duplicate_key, "duplicate object key");
|
error_set(error, lex, json_error_duplicate_key, "duplicate object key");
|
||||||
goto error;
|
goto error;
|
||||||
@ -710,7 +710,7 @@ static json_t *parse_object(lex_t *lex, size_t flags, json_error_t *error) {
|
|||||||
goto 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);
|
jsonp_free(key);
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
34
src/value.c
34
src/value.c
@ -44,10 +44,13 @@ static JSON_INLINE void json_init(json_t *json, json_type type) {
|
|||||||
json->refcount = 1;
|
json->refcount = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int jsonp_loop_check(hashtable_t *parents, const json_t *json, char *key,
|
int jsonp_loop_check(hashtable_t *parents, const json_t *json, char *key, size_t key_size,
|
||||||
size_t key_size) {
|
size_t *key_len_out) {
|
||||||
size_t key_len = snprintf(key, key_size, "%p", json);
|
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))
|
if (hashtable_get(parents, key, key_len))
|
||||||
return -1;
|
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) {
|
int json_object_update_existing(json_t *object, json_t *other) {
|
||||||
const char *key;
|
const char *key;
|
||||||
|
size_t key_len;
|
||||||
json_t *value;
|
json_t *value;
|
||||||
|
|
||||||
if (!json_is_object(object) || !json_is_object(other))
|
if (!json_is_object(object) || !json_is_object(other))
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
json_object_foreach(other, key, value) {
|
json_object_keylen_foreach(other, key, key_len, value) {
|
||||||
if (json_object_get(object, key))
|
if (json_object_getn(object, key, key_len))
|
||||||
json_object_set_nocheck(object, key, value);
|
json_object_setn_nocheck(object, key, key_len, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
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) {
|
int do_object_update_recursive(json_t *object, json_t *other, hashtable_t *parents) {
|
||||||
const char *key;
|
const char *key;
|
||||||
|
size_t key_len;
|
||||||
json_t *value;
|
json_t *value;
|
||||||
char loop_key[LOOP_KEY_LEN];
|
char loop_key[LOOP_KEY_LEN];
|
||||||
int res = 0;
|
int res = 0;
|
||||||
|
size_t loop_key_len;
|
||||||
|
|
||||||
if (!json_is_object(object) || !json_is_object(other))
|
if (!json_is_object(object) || !json_is_object(other))
|
||||||
return -1;
|
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;
|
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);
|
json_t *v = json_object_get(object, key);
|
||||||
|
|
||||||
if (json_is_object(v) && json_is_object(value)) {
|
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;
|
break;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (json_object_set_nocheck(object, key, value)) {
|
if (json_object_setn_nocheck(object, key, key_len, value)) {
|
||||||
res = -1;
|
res = -1;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
hashtable_del(parents, loop_key, strlen(loop_key));
|
hashtable_del(parents, loop_key, loop_key_len);
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
@ -380,8 +386,9 @@ static json_t *json_object_deep_copy(const json_t *object, hashtable_t *parents)
|
|||||||
json_t *result;
|
json_t *result;
|
||||||
void *iter;
|
void *iter;
|
||||||
char loop_key[LOOP_KEY_LEN];
|
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;
|
return NULL;
|
||||||
|
|
||||||
result = json_object();
|
result = json_object();
|
||||||
@ -406,7 +413,7 @@ static json_t *json_object_deep_copy(const json_t *object, hashtable_t *parents)
|
|||||||
}
|
}
|
||||||
|
|
||||||
out:
|
out:
|
||||||
hashtable_del(parents, loop_key, strlen(loop_key));
|
hashtable_del(parents, loop_key, loop_key_len);
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@ -673,8 +680,9 @@ static json_t *json_array_deep_copy(const json_t *array, hashtable_t *parents) {
|
|||||||
json_t *result;
|
json_t *result;
|
||||||
size_t i;
|
size_t i;
|
||||||
char loop_key[LOOP_KEY_LEN];
|
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;
|
return NULL;
|
||||||
|
|
||||||
result = json_array();
|
result = json_array();
|
||||||
@ -691,7 +699,7 @@ static json_t *json_array_deep_copy(const json_t *array, hashtable_t *parents) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
out:
|
out:
|
||||||
hashtable_del(parents, loop_key, strlen(loop_key));
|
hashtable_del(parents, loop_key, loop_key_len);
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user