pass length of the key to internal API
Use key length for internal API Signed-off-by: Maxim Zhukov <mussitantesmortem@gmail.com>
This commit is contained in:
parent
966f9cc20a
commit
ba4503804b
@ -263,7 +263,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);
|
hashtable_del(parents, key, strlen(key));
|
||||||
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 +284,7 @@ static int do_dump(const json_t *json, size_t flags, int depth, hashtable_t *par
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
hashtable_del(parents, key);
|
hashtable_del(parents, key, strlen(key));
|
||||||
return embed ? 0 : dump("]", 1, data);
|
return embed ? 0 : dump("]", 1, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -311,7 +311,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 (!iter) {
|
if (!iter) {
|
||||||
hashtable_del(parents, loop_key);
|
hashtable_del(parents, loop_key, strlen(loop_key));
|
||||||
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))
|
||||||
@ -392,7 +392,7 @@ static int do_dump(const json_t *json, size_t flags, int depth, hashtable_t *par
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
hashtable_del(parents, loop_key);
|
hashtable_del(parents, loop_key, strlen(loop_key));
|
||||||
return embed ? 0 : dump("}", 1, data);
|
return embed ? 0 : dump("}", 1, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -35,7 +35,7 @@ extern volatile uint32_t hashtable_seed;
|
|||||||
|
|
||||||
#define list_to_pair(list_) container_of(list_, pair_t, list)
|
#define list_to_pair(list_) container_of(list_, pair_t, list)
|
||||||
#define ordered_list_to_pair(list_) container_of(list_, pair_t, ordered_list)
|
#define ordered_list_to_pair(list_) container_of(list_, pair_t, ordered_list)
|
||||||
#define hash_str(key) ((size_t)hashlittle((key), strlen(key), hashtable_seed))
|
#define hash_str(key, len) ((size_t)hashlittle((key), len, hashtable_seed))
|
||||||
|
|
||||||
static JSON_INLINE void list_init(list_t *list) {
|
static JSON_INLINE void list_init(list_t *list) {
|
||||||
list->next = list;
|
list->next = list;
|
||||||
@ -69,7 +69,7 @@ static void insert_to_bucket(hashtable_t *hashtable, bucket_t *bucket, list_t *l
|
|||||||
}
|
}
|
||||||
|
|
||||||
static pair_t *hashtable_find_pair(hashtable_t *hashtable, bucket_t *bucket,
|
static pair_t *hashtable_find_pair(hashtable_t *hashtable, bucket_t *bucket,
|
||||||
const char *key, size_t hash) {
|
const char *key, size_t key_len, size_t hash) {
|
||||||
list_t *list;
|
list_t *list;
|
||||||
pair_t *pair;
|
pair_t *pair;
|
||||||
|
|
||||||
@ -79,7 +79,8 @@ static pair_t *hashtable_find_pair(hashtable_t *hashtable, bucket_t *bucket,
|
|||||||
list = bucket->first;
|
list = bucket->first;
|
||||||
while (1) {
|
while (1) {
|
||||||
pair = list_to_pair(list);
|
pair = list_to_pair(list);
|
||||||
if (pair->hash == hash && strcmp(pair->key, key) == 0)
|
if (pair->hash == hash && pair->key_len == key_len &&
|
||||||
|
memcmp(pair->key, key, key_len) == 0)
|
||||||
return pair;
|
return pair;
|
||||||
|
|
||||||
if (list == bucket->last)
|
if (list == bucket->last)
|
||||||
@ -92,7 +93,8 @@ static pair_t *hashtable_find_pair(hashtable_t *hashtable, bucket_t *bucket,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* returns 0 on success, -1 if key was not found */
|
/* returns 0 on success, -1 if key was not found */
|
||||||
static int hashtable_do_del(hashtable_t *hashtable, const char *key, size_t hash) {
|
static int hashtable_do_del(hashtable_t *hashtable, const char *key, size_t key_len,
|
||||||
|
size_t hash) {
|
||||||
pair_t *pair;
|
pair_t *pair;
|
||||||
bucket_t *bucket;
|
bucket_t *bucket;
|
||||||
size_t index;
|
size_t index;
|
||||||
@ -100,7 +102,7 @@ static int hashtable_do_del(hashtable_t *hashtable, const char *key, size_t hash
|
|||||||
index = hash & hashmask(hashtable->order);
|
index = hash & hashmask(hashtable->order);
|
||||||
bucket = &hashtable->buckets[index];
|
bucket = &hashtable->buckets[index];
|
||||||
|
|
||||||
pair = hashtable_find_pair(hashtable, bucket, key, hash);
|
pair = hashtable_find_pair(hashtable, bucket, key, key_len, hash);
|
||||||
if (!pair)
|
if (!pair)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
@ -193,7 +195,37 @@ void hashtable_close(hashtable_t *hashtable) {
|
|||||||
jsonp_free(hashtable->buckets);
|
jsonp_free(hashtable->buckets);
|
||||||
}
|
}
|
||||||
|
|
||||||
int hashtable_set(hashtable_t *hashtable, const char *key, json_t *value) {
|
static pair_t *init_pair(json_t *value, const char *key, size_t key_len, size_t hash) {
|
||||||
|
pair_t *pair;
|
||||||
|
|
||||||
|
/* offsetof(...) returns the size of pair_t without the last,
|
||||||
|
flexible member. This way, the correct amount is
|
||||||
|
allocated. */
|
||||||
|
|
||||||
|
if (key_len >= (size_t)-1 - offsetof(pair_t, key)) {
|
||||||
|
/* Avoid an overflow if the key is very long */
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
pair = jsonp_malloc(offsetof(pair_t, key) + key_len + 1);
|
||||||
|
|
||||||
|
if (!pair)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
pair->hash = hash;
|
||||||
|
memcpy(pair->key, key, key_len);
|
||||||
|
pair->key[key_len] = '\0';
|
||||||
|
pair->key_len = key_len;
|
||||||
|
pair->value = value;
|
||||||
|
|
||||||
|
list_init(&pair->list);
|
||||||
|
list_init(&pair->ordered_list);
|
||||||
|
|
||||||
|
return pair;
|
||||||
|
}
|
||||||
|
|
||||||
|
int hashtable_set(hashtable_t *hashtable, const char *key, size_t key_len,
|
||||||
|
json_t *value) {
|
||||||
pair_t *pair;
|
pair_t *pair;
|
||||||
bucket_t *bucket;
|
bucket_t *bucket;
|
||||||
size_t hash, index;
|
size_t hash, index;
|
||||||
@ -203,35 +235,20 @@ int hashtable_set(hashtable_t *hashtable, const char *key, json_t *value) {
|
|||||||
if (hashtable_do_rehash(hashtable))
|
if (hashtable_do_rehash(hashtable))
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
hash = hash_str(key);
|
hash = hash_str(key, key_len);
|
||||||
index = hash & hashmask(hashtable->order);
|
index = hash & hashmask(hashtable->order);
|
||||||
bucket = &hashtable->buckets[index];
|
bucket = &hashtable->buckets[index];
|
||||||
pair = hashtable_find_pair(hashtable, bucket, key, hash);
|
pair = hashtable_find_pair(hashtable, bucket, key, key_len, hash);
|
||||||
|
|
||||||
if (pair) {
|
if (pair) {
|
||||||
json_decref(pair->value);
|
json_decref(pair->value);
|
||||||
pair->value = value;
|
pair->value = value;
|
||||||
} else {
|
} else {
|
||||||
/* offsetof(...) returns the size of pair_t without the last,
|
pair = init_pair(value, key, key_len, hash);
|
||||||
flexible member. This way, the correct amount is
|
|
||||||
allocated. */
|
|
||||||
|
|
||||||
size_t len = strlen(key);
|
|
||||||
if (len >= (size_t)-1 - offsetof(pair_t, key)) {
|
|
||||||
/* Avoid an overflow if the key is very long */
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
pair = jsonp_malloc(offsetof(pair_t, key) + len + 1);
|
|
||||||
if (!pair)
|
if (!pair)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
pair->hash = hash;
|
|
||||||
strncpy(pair->key, key, len + 1);
|
|
||||||
pair->value = value;
|
|
||||||
list_init(&pair->list);
|
|
||||||
list_init(&pair->ordered_list);
|
|
||||||
|
|
||||||
insert_to_bucket(hashtable, bucket, &pair->list);
|
insert_to_bucket(hashtable, bucket, &pair->list);
|
||||||
list_insert(&hashtable->ordered_list, &pair->ordered_list);
|
list_insert(&hashtable->ordered_list, &pair->ordered_list);
|
||||||
|
|
||||||
@ -240,24 +257,24 @@ int hashtable_set(hashtable_t *hashtable, const char *key, json_t *value) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void *hashtable_get(hashtable_t *hashtable, const char *key) {
|
void *hashtable_get(hashtable_t *hashtable, const char *key, size_t key_len) {
|
||||||
pair_t *pair;
|
pair_t *pair;
|
||||||
size_t hash;
|
size_t hash;
|
||||||
bucket_t *bucket;
|
bucket_t *bucket;
|
||||||
|
|
||||||
hash = hash_str(key);
|
hash = hash_str(key, key_len);
|
||||||
bucket = &hashtable->buckets[hash & hashmask(hashtable->order)];
|
bucket = &hashtable->buckets[hash & hashmask(hashtable->order)];
|
||||||
|
|
||||||
pair = hashtable_find_pair(hashtable, bucket, key, hash);
|
pair = hashtable_find_pair(hashtable, bucket, key, key_len, hash);
|
||||||
if (!pair)
|
if (!pair)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
return pair->value;
|
return pair->value;
|
||||||
}
|
}
|
||||||
|
|
||||||
int hashtable_del(hashtable_t *hashtable, const char *key) {
|
int hashtable_del(hashtable_t *hashtable, const char *key, size_t key_len) {
|
||||||
size_t hash = hash_str(key);
|
size_t hash = hash_str(key, key_len);
|
||||||
return hashtable_do_del(hashtable, key, hash);
|
return hashtable_do_del(hashtable, key, key_len, hash);
|
||||||
}
|
}
|
||||||
|
|
||||||
void hashtable_clear(hashtable_t *hashtable) {
|
void hashtable_clear(hashtable_t *hashtable) {
|
||||||
@ -278,15 +295,15 @@ void *hashtable_iter(hashtable_t *hashtable) {
|
|||||||
return hashtable_iter_next(hashtable, &hashtable->ordered_list);
|
return hashtable_iter_next(hashtable, &hashtable->ordered_list);
|
||||||
}
|
}
|
||||||
|
|
||||||
void *hashtable_iter_at(hashtable_t *hashtable, const char *key) {
|
void *hashtable_iter_at(hashtable_t *hashtable, const char *key, size_t key_len) {
|
||||||
pair_t *pair;
|
pair_t *pair;
|
||||||
size_t hash;
|
size_t hash;
|
||||||
bucket_t *bucket;
|
bucket_t *bucket;
|
||||||
|
|
||||||
hash = hash_str(key);
|
hash = hash_str(key, key_len);
|
||||||
bucket = &hashtable->buckets[hash & hashmask(hashtable->order)];
|
bucket = &hashtable->buckets[hash & hashmask(hashtable->order)];
|
||||||
|
|
||||||
pair = hashtable_find_pair(hashtable, bucket, key, hash);
|
pair = hashtable_find_pair(hashtable, bucket, key, key_len, hash);
|
||||||
if (!pair)
|
if (!pair)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
|
@ -24,6 +24,7 @@ struct hashtable_pair {
|
|||||||
struct hashtable_list ordered_list;
|
struct hashtable_list ordered_list;
|
||||||
size_t hash;
|
size_t hash;
|
||||||
json_t *value;
|
json_t *value;
|
||||||
|
size_t key_len;
|
||||||
char key[1];
|
char key[1];
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -69,6 +70,7 @@ void hashtable_close(hashtable_t *hashtable);
|
|||||||
*
|
*
|
||||||
* @hashtable: The hashtable object
|
* @hashtable: The hashtable object
|
||||||
* @key: The key
|
* @key: The key
|
||||||
|
* @key: The length of key
|
||||||
* @serial: For addition order of keys
|
* @serial: For addition order of keys
|
||||||
* @value: The value
|
* @value: The value
|
||||||
*
|
*
|
||||||
@ -79,27 +81,29 @@ void hashtable_close(hashtable_t *hashtable);
|
|||||||
*
|
*
|
||||||
* Returns 0 on success, -1 on failure (out of memory).
|
* Returns 0 on success, -1 on failure (out of memory).
|
||||||
*/
|
*/
|
||||||
int hashtable_set(hashtable_t *hashtable, const char *key, json_t *value);
|
int hashtable_set(hashtable_t *hashtable, const char *key, size_t key_len, json_t *value);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* hashtable_get - Get a value associated with a key
|
* hashtable_get - Get a value associated with a key
|
||||||
*
|
*
|
||||||
* @hashtable: The hashtable object
|
* @hashtable: The hashtable object
|
||||||
* @key: The key
|
* @key: The key
|
||||||
|
* @key: The length of key
|
||||||
*
|
*
|
||||||
* Returns value if it is found, or NULL otherwise.
|
* Returns value if it is found, or NULL otherwise.
|
||||||
*/
|
*/
|
||||||
void *hashtable_get(hashtable_t *hashtable, const char *key);
|
void *hashtable_get(hashtable_t *hashtable, const char *key, size_t key_len);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* hashtable_del - Remove a value from the hashtable
|
* hashtable_del - Remove a value from the hashtable
|
||||||
*
|
*
|
||||||
* @hashtable: The hashtable object
|
* @hashtable: The hashtable object
|
||||||
* @key: The key
|
* @key: The key
|
||||||
|
* @key: The length of key
|
||||||
*
|
*
|
||||||
* Returns 0 on success, or -1 if the key was not found.
|
* Returns 0 on success, or -1 if the key was not found.
|
||||||
*/
|
*/
|
||||||
int hashtable_del(hashtable_t *hashtable, const char *key);
|
int hashtable_del(hashtable_t *hashtable, const char *key, size_t key_len);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* hashtable_clear - Clear hashtable
|
* hashtable_clear - Clear hashtable
|
||||||
@ -132,11 +136,12 @@ void *hashtable_iter(hashtable_t *hashtable);
|
|||||||
*
|
*
|
||||||
* @hashtable: The hashtable object
|
* @hashtable: The hashtable object
|
||||||
* @key: The key that the iterator should point to
|
* @key: The key that the iterator should point to
|
||||||
|
* @key: The length of key
|
||||||
*
|
*
|
||||||
* Like hashtable_iter() but returns an iterator pointing to a
|
* Like hashtable_iter() but returns an iterator pointing to a
|
||||||
* specific key.
|
* specific key.
|
||||||
*/
|
*/
|
||||||
void *hashtable_iter_at(hashtable_t *hashtable, const char *key);
|
void *hashtable_iter_at(hashtable_t *hashtable, const char *key, size_t key_len);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* hashtable_iter_next - Advance an iterator
|
* hashtable_iter_next - Advance an iterator
|
||||||
|
@ -544,7 +544,7 @@ static int unpack_object(scanner_t *s, json_t *root, va_list *ap) {
|
|||||||
if (unpack(s, value, ap))
|
if (unpack(s, value, ap))
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
hashtable_set(&key_set, key, json_null());
|
hashtable_set(&key_set, key, strlen(key), json_null());
|
||||||
next_token(s);
|
next_token(s);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -554,6 +554,7 @@ static int unpack_object(scanner_t *s, json_t *root, va_list *ap) {
|
|||||||
if (root && strict == 1) {
|
if (root && strict == 1) {
|
||||||
/* We need to check that all non optional items have been parsed */
|
/* We need to check that all non optional items have been parsed */
|
||||||
const char *key;
|
const char *key;
|
||||||
|
size_t key_len;
|
||||||
/* keys_res is 1 for uninitialized, 0 for success, -1 for error. */
|
/* keys_res is 1 for uninitialized, 0 for success, -1 for error. */
|
||||||
int keys_res = 1;
|
int keys_res = 1;
|
||||||
strbuffer_t unrecognized_keys;
|
strbuffer_t unrecognized_keys;
|
||||||
@ -562,7 +563,8 @@ static int unpack_object(scanner_t *s, json_t *root, va_list *ap) {
|
|||||||
|
|
||||||
if (gotopt || json_object_size(root) != key_set.size) {
|
if (gotopt || json_object_size(root) != key_set.size) {
|
||||||
json_object_foreach(root, key, value) {
|
json_object_foreach(root, key, value) {
|
||||||
if (!hashtable_get(&key_set, key)) {
|
key_len = strlen(key);
|
||||||
|
if (!hashtable_get(&key_set, key, key_len)) {
|
||||||
unpacked++;
|
unpacked++;
|
||||||
|
|
||||||
/* Save unrecognized keys for the error message */
|
/* Save unrecognized keys for the error message */
|
||||||
@ -574,7 +576,7 @@ static int unpack_object(scanner_t *s, json_t *root, va_list *ap) {
|
|||||||
|
|
||||||
if (!keys_res)
|
if (!keys_res)
|
||||||
keys_res =
|
keys_res =
|
||||||
strbuffer_append_bytes(&unrecognized_keys, key, strlen(key));
|
strbuffer_append_bytes(&unrecognized_keys, key, key_len);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
21
src/value.c
21
src/value.c
@ -46,11 +46,12 @@ static JSON_INLINE void json_init(json_t *json, json_type type) {
|
|||||||
|
|
||||||
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) {
|
||||||
snprintf(key, key_size, "%p", json);
|
size_t key_len = snprintf(key, key_size, "%p", json);
|
||||||
if (hashtable_get(parents, key))
|
|
||||||
|
if (hashtable_get(parents, key, key_len))
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
return hashtable_set(parents, key, json_null());
|
return hashtable_set(parents, key, key_len, json_null());
|
||||||
}
|
}
|
||||||
|
|
||||||
/*** object ***/
|
/*** object ***/
|
||||||
@ -99,7 +100,7 @@ json_t *json_object_get(const json_t *json, const char *key) {
|
|||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
object = json_to_object(json);
|
object = json_to_object(json);
|
||||||
return hashtable_get(&object->hashtable, key);
|
return hashtable_get(&object->hashtable, key, strlen(key));
|
||||||
}
|
}
|
||||||
|
|
||||||
int json_object_set_new_nocheck(json_t *json, const char *key, json_t *value) {
|
int json_object_set_new_nocheck(json_t *json, const char *key, json_t *value) {
|
||||||
@ -114,7 +115,7 @@ int json_object_set_new_nocheck(json_t *json, const char *key, json_t *value) {
|
|||||||
}
|
}
|
||||||
object = json_to_object(json);
|
object = json_to_object(json);
|
||||||
|
|
||||||
if (hashtable_set(&object->hashtable, key, value)) {
|
if (hashtable_set(&object->hashtable, key, strlen(key), value)) {
|
||||||
json_decref(value);
|
json_decref(value);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@ -138,7 +139,7 @@ int json_object_del(json_t *json, const char *key) {
|
|||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
object = json_to_object(json);
|
object = json_to_object(json);
|
||||||
return hashtable_del(&object->hashtable, key);
|
return hashtable_del(&object->hashtable, key, strlen(key));
|
||||||
}
|
}
|
||||||
|
|
||||||
int json_object_clear(json_t *json) {
|
int json_object_clear(json_t *json) {
|
||||||
@ -226,7 +227,7 @@ int do_object_update_recursive(json_t *object, json_t *other, hashtable_t *paren
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
hashtable_del(parents, loop_key);
|
hashtable_del(parents, loop_key, strlen(loop_key));
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
@ -260,7 +261,7 @@ void *json_object_iter_at(json_t *json, const char *key) {
|
|||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
object = json_to_object(json);
|
object = json_to_object(json);
|
||||||
return hashtable_iter_at(&object->hashtable, key);
|
return hashtable_iter_at(&object->hashtable, key, strlen(key));
|
||||||
}
|
}
|
||||||
|
|
||||||
void *json_object_iter_next(json_t *json, void *iter) {
|
void *json_object_iter_next(json_t *json, void *iter) {
|
||||||
@ -366,7 +367,7 @@ static json_t *json_object_deep_copy(const json_t *object, hashtable_t *parents)
|
|||||||
}
|
}
|
||||||
|
|
||||||
out:
|
out:
|
||||||
hashtable_del(parents, loop_key);
|
hashtable_del(parents, loop_key, strlen(loop_key));
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@ -651,7 +652,7 @@ static json_t *json_array_deep_copy(const json_t *array, hashtable_t *parents) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
out:
|
out:
|
||||||
hashtable_del(parents, loop_key);
|
hashtable_del(parents, loop_key, strlen(loop_key));
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user