summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorBen Pfaff <blp@ovn.org>2018-03-23 15:46:58 -0700
committerBen Pfaff <blp@ovn.org>2018-03-31 12:22:58 -0700
commit828129d9271da18c2742648aa910e1fe399bb8db (patch)
treeb6c38580b22179dc7c7efd4c030aed5b9ff89b38 /lib
parent056caea89bffe5f27000944c0ed5aaa6f7a2d852 (diff)
downloadopenvswitch-828129d9271da18c2742648aa910e1fe399bb8db.tar.gz
json: Avoid extra memory allocation and string copy parsing object members.
Until now, every time the JSON parser added an object member, it made an extra copy of the member name and then freed the original copy. This is wasteful, so this commit eliminates the extra copy. Signed-off-by: Ben Pfaff <blp@ovn.org> Reviewed-by: Yifeng Sun <pkusunyifeng@gmail.com>
Diffstat (limited to 'lib')
-rw-r--r--lib/json.c9
-rw-r--r--lib/shash.c23
2 files changed, 30 insertions, 2 deletions
diff --git a/lib/json.c b/lib/json.c
index 07ca87b21..603fd1df8 100644
--- a/lib/json.c
+++ b/lib/json.c
@@ -280,6 +280,12 @@ json_object_put(struct json *json, const char *name, struct json *value)
}
void
+json_object_put_nocopy(struct json *json, char *name, struct json *value)
+{
+ json_destroy(shash_replace_nocopy(json->u.object, name, value));
+}
+
+void
json_object_put_string(struct json *json, const char *name, const char *value)
{
json_object_put(json, name, json_string_create(value));
@@ -1217,8 +1223,7 @@ json_parser_put_value(struct json_parser *p, struct json *value)
{
struct json_parser_node *node = json_parser_top(p);
if (node->json->type == JSON_OBJECT) {
- json_object_put(node->json, p->member_name, value);
- free(p->member_name);
+ json_object_put_nocopy(node->json, p->member_name, value);
p->member_name = NULL;
} else if (node->json->type == JSON_ARRAY) {
json_array_add(node->json, value);
diff --git a/lib/shash.c b/lib/shash.c
index 318a30ffc..a8433629a 100644
--- a/lib/shash.c
+++ b/lib/shash.c
@@ -166,6 +166,29 @@ shash_replace(struct shash *sh, const char *name, const void *data)
}
}
+/* Searches for 'name' in 'sh'. If it does not already exist, adds it along
+ * with 'data' and returns NULL. If it does already exist, replaces its data
+ * by 'data' and returns the data that it formerly contained.
+ *
+ * Takes ownership of 'name'. */
+void *
+shash_replace_nocopy(struct shash *sh, char *name, const void *data)
+{
+ size_t hash = hash_name(name);
+ struct shash_node *node;
+
+ node = shash_find__(sh, name, strlen(name), hash);
+ if (!node) {
+ shash_add_nocopy__(sh, name, data, hash);
+ return NULL;
+ } else {
+ free(name);
+ void *old_data = node->data;
+ node->data = CONST_CAST(void *, data);
+ return old_data;
+ }
+}
+
/* Deletes 'node' from 'sh' and frees the node's name. The caller is still
* responsible for freeing the node's data, if necessary. */
void