This provides more control over some detail aspects, many of which are performance related.tags/json-c-0.13-20171207
| @@ -355,7 +355,8 @@ static int json_object_object_to_json_string(struct json_object* jso, | |||||
| static void json_object_lh_entry_free(struct lh_entry *ent) | static void json_object_lh_entry_free(struct lh_entry *ent) | ||||
| { | { | ||||
| free(ent->k); | |||||
| if (!ent->k_is_constant) | |||||
| free(ent->k); | |||||
| json_object_put((struct json_object*)ent->v); | json_object_put((struct json_object*)ent->v); | ||||
| } | } | ||||
| @@ -396,6 +397,31 @@ struct lh_table* json_object_get_object(struct json_object *jso) | |||||
| } | } | ||||
| } | } | ||||
| void json_object_object_add_ex(struct json_object* jso, | |||||
| const char *const key, | |||||
| struct json_object *const val, | |||||
| const unsigned opts) | |||||
| { | |||||
| // We lookup the entry and replace the value, rather than just deleting | |||||
| // and re-adding it, so the existing key remains valid. | |||||
| json_object *existing_value = NULL; | |||||
| struct lh_entry *existing_entry; | |||||
| const unsigned long hash = lh_get_hash(jso->o.c_object, (void*)key); | |||||
| existing_entry = (opts & JSON_C_OBJECT_ADD_KEY_IS_NEW) ? NULL : | |||||
| lh_table_lookup_entry_w_hash(jso->o.c_object, (void*)key, hash); | |||||
| if (!existing_entry) | |||||
| { | |||||
| void *const k = (opts & JSON_C_OBJECT_KEY_IS_CONSTANT) ? | |||||
| (void*)key : strdup(key); | |||||
| lh_table_insert_w_hash(jso->o.c_object, k, val, hash, opts); | |||||
| return; | |||||
| } | |||||
| existing_value = (void *)existing_entry->v; | |||||
| if (existing_value) | |||||
| json_object_put(existing_value); | |||||
| existing_entry->v = val; | |||||
| } | |||||
| void json_object_object_add(struct json_object* jso, const char *key, | void json_object_object_add(struct json_object* jso, const char *key, | ||||
| struct json_object *val) | struct json_object *val) | ||||
| { | { | ||||
| @@ -407,7 +433,7 @@ void json_object_object_add(struct json_object* jso, const char *key, | |||||
| existing_entry = lh_table_lookup_entry_w_hash(jso->o.c_object, (void*)key, hash); | existing_entry = lh_table_lookup_entry_w_hash(jso->o.c_object, (void*)key, hash); | ||||
| if (!existing_entry) | if (!existing_entry) | ||||
| { | { | ||||
| lh_table_insert_w_hash(jso->o.c_object, strdup(key), val, hash); | |||||
| lh_table_insert_w_hash(jso->o.c_object, strdup(key), val, hash, 0); | |||||
| return; | return; | ||||
| } | } | ||||
| existing_value = (void *)existing_entry->v; | existing_value = (void *)existing_entry->v; | ||||
| @@ -55,6 +55,36 @@ extern "C" { | |||||
| */ | */ | ||||
| #define JSON_C_TO_STRING_NOZERO (1<<2) | #define JSON_C_TO_STRING_NOZERO (1<<2) | ||||
| /** | |||||
| * A flag for the json_object_object_add_ex function which | |||||
| * causes the value to be added without a check if it already exists. | |||||
| * Note: it is the responsibilty of the caller to ensure that no | |||||
| * key is added multiple times. If this is done, results are | |||||
| * unpredictable. While this option is somewhat dangerous, it | |||||
| * permits potentially large performance savings in code that | |||||
| * knows for sure the key values are unique (e.g. because the | |||||
| * code adds a well-known set of constant key values). | |||||
| */ | |||||
| #define JSON_C_OBJECT_ADD_KEY_IS_NEW (1<<1) | |||||
| /** | |||||
| * A flag for the json_object_object_add_ex function which | |||||
| * flags the key as being constant memory. This means that | |||||
| * the key will NOT be copied via strdup(), resulting in a | |||||
| * potentially huge performance win (malloc, strdup and | |||||
| * free are usually performance hogs). It is acceptable to | |||||
| * use this flag for keys in non-constant memory blocks if | |||||
| * the caller ensure that the memory holding the key lives | |||||
| * longer than the corresponding json object. However, this | |||||
| * is somewhat dangerous and should only be done if really | |||||
| * justified. | |||||
| * The general use-case for this flag is cases where the | |||||
| * key is given as a real constant value in the function | |||||
| * call, e.g. as in | |||||
| * json_object_object_add_ex(obj, "ip", json, | |||||
| * JSON_C_OBJECT_KEY_IS_CONSTANT); | |||||
| */ | |||||
| #define JSON_C_OBJECT_KEY_IS_CONSTANT (1<<2) | |||||
| #undef FALSE | #undef FALSE | ||||
| #define FALSE ((json_bool)0) | #define FALSE ((json_bool)0) | ||||
| @@ -275,6 +305,22 @@ extern int json_object_object_length(struct json_object* obj); | |||||
| extern void json_object_object_add(struct json_object* obj, const char *key, | extern void json_object_object_add(struct json_object* obj, const char *key, | ||||
| struct json_object *val); | struct json_object *val); | ||||
| /** Add an object field to a json_object of type json_type_object | |||||
| * | |||||
| * The semantics are identical to json_object_object_add, except that an | |||||
| * additional flag fields gives you more control over some detail aspects | |||||
| * of processing. See the description of JSON_C_OBJECT_ADD_* flags for more | |||||
| * details. | |||||
| * | |||||
| * @param obj the json_object instance | |||||
| * @param key the object field name (a private copy will be duplicated) | |||||
| * @param val a json_object or NULL member to associate with the given field | |||||
| * @param opts process-modifying options. To specify multiple options, use | |||||
| * arithmetic or (OPT1|OPT2) | |||||
| */ | |||||
| extern void json_object_object_add_ex(struct json_object* obj, const char *key, | |||||
| struct json_object *val, const unsigned opts); | |||||
| /** Get the json_object associate with a given object field | /** Get the json_object associate with a given object field | ||||
| * | * | ||||
| * *No* reference counts will be changed. There is no need to manually adjust | * *No* reference counts will be changed. There is no need to manually adjust | ||||
| @@ -490,7 +490,7 @@ void lh_table_free(struct lh_table *t) | |||||
| } | } | ||||
| int lh_table_insert_w_hash(struct lh_table *t, void *k, const void *v, const unsigned long h) | |||||
| int lh_table_insert_w_hash(struct lh_table *t, void *k, const void *v, const unsigned long h, const unsigned opts) | |||||
| { | { | ||||
| unsigned long n; | unsigned long n; | ||||
| @@ -506,6 +506,7 @@ int lh_table_insert_w_hash(struct lh_table *t, void *k, const void *v, const uns | |||||
| } | } | ||||
| t->table[n].k = k; | t->table[n].k = k; | ||||
| t->table[n].k_is_constant = (opts & JSON_C_OBJECT_KEY_IS_CONSTANT); | |||||
| t->table[n].v = v; | t->table[n].v = v; | ||||
| t->count++; | t->count++; | ||||
| @@ -523,7 +524,7 @@ int lh_table_insert_w_hash(struct lh_table *t, void *k, const void *v, const uns | |||||
| } | } | ||||
| int lh_table_insert(struct lh_table *t, void *k, const void *v) | int lh_table_insert(struct lh_table *t, void *k, const void *v) | ||||
| { | { | ||||
| return lh_table_insert_w_hash(t, k, v, lh_get_hash(t, k)); | |||||
| return lh_table_insert_w_hash(t, k, v, lh_get_hash(t, k), 0); | |||||
| } | } | ||||
| @@ -64,6 +64,7 @@ struct lh_entry { | |||||
| * The key. | * The key. | ||||
| */ | */ | ||||
| void *k; | void *k; | ||||
| int k_is_constant; | |||||
| /** | /** | ||||
| * The value. | * The value. | ||||
| */ | */ | ||||
| @@ -241,8 +242,9 @@ extern int lh_table_insert(struct lh_table *t, void *k, const void *v); | |||||
| * @param k a pointer to the key to insert. | * @param k a pointer to the key to insert. | ||||
| * @param v a pointer to the value to insert. | * @param v a pointer to the value to insert. | ||||
| * @param h hash value of the key to insert | * @param h hash value of the key to insert | ||||
| * @param opts opts, a subset of JSON_OBJECT_ADD_* flags is supported | |||||
| */ | */ | ||||
| extern int lh_table_insert_w_hash(struct lh_table *t, void *k, const void *v, const unsigned long h); | |||||
| extern int lh_table_insert_w_hash(struct lh_table *t, void *k, const void *v, const unsigned long h, const unsigned opts); | |||||
| /** | /** | ||||