diff --git a/json_object.c b/json_object.c index f950257..8dd6082 100644 --- a/json_object.c +++ b/json_object.c @@ -95,9 +95,18 @@ static void json_object_fini(void) #endif /* REFCOUNT_DEBUG */ +/* helper for accessing the optimized string data component in json_object + */ +static const char * +get_string_component(struct json_object *jso) +{ + return (jso->o.c_string.len < LEN_DIRECT_STRING_DATA) ? + jso->o.c_string.str.data : jso->o.c_string.str.ptr; +} + /* string escaping */ -static int json_escape_str(struct printbuf *pb, char *str, int len) +static int json_escape_str(struct printbuf *pb, const char *str, int len) { int pos = 0, start_offset = 0; unsigned char c; @@ -559,7 +568,7 @@ int32_t json_object_get_int(struct json_object *jso) * Parse strings into 64-bit numbers, then use the * 64-to-32-bit number handling below. */ - if (json_parse_int64(jso->o.c_string.str, &cint64) != 0) + if (json_parse_int64(get_string_component(jso), &cint64) != 0) return 0; /* whoops, it didn't work. */ o_type = json_type_int; } @@ -607,7 +616,7 @@ int64_t json_object_get_int64(struct json_object *jso) case json_type_boolean: return jso->o.c_boolean; case json_type_string: - if (json_parse_int64(jso->o.c_string.str, &cint) == 0) + if (json_parse_int64(get_string_component(jso), &cint) == 0) return cint; default: return 0; @@ -714,10 +723,10 @@ double json_object_get_double(struct json_object *jso) return jso->o.c_boolean; case json_type_string: errno = 0; - cdouble = strtod(jso->o.c_string.str,&errPtr); + cdouble = strtod(get_string_component(jso), &errPtr); /* if conversion stopped at the first character, return 0.0 */ - if (errPtr == jso->o.c_string.str) + if (errPtr == get_string_component(jso)) return 0.0; /* @@ -757,14 +766,15 @@ static int json_object_string_to_json_string(struct json_object* jso, int flags) { sprintbuf(pb, "\""); - json_escape_str(pb, jso->o.c_string.str, jso->o.c_string.len); + json_escape_str(pb, get_string_component(jso), jso->o.c_string.len); sprintbuf(pb, "\""); return 0; } static void json_object_string_delete(struct json_object* jso) { - free(jso->o.c_string.str); + if(jso->o.c_string.len >= LEN_DIRECT_STRING_DATA) + free(jso->o.c_string.str.ptr); json_object_generic_delete(jso); } @@ -775,33 +785,43 @@ struct json_object* json_object_new_string(const char *s) return NULL; jso->_delete = &json_object_string_delete; jso->_to_json_string = &json_object_string_to_json_string; - jso->o.c_string.str = strdup(s); - if (!jso->o.c_string.str) - { - json_object_generic_delete(jso); - errno = ENOMEM; - return NULL; - } jso->o.c_string.len = strlen(s); + if(jso->o.c_string.len < LEN_DIRECT_STRING_DATA) { + memcpy(jso->o.c_string.str.data, s, jso->o.c_string.len); + } else { + jso->o.c_string.str.ptr = strdup(s); + if (!jso->o.c_string.str.ptr) + { + json_object_generic_delete(jso); + errno = ENOMEM; + return NULL; + } + } return jso; } struct json_object* json_object_new_string_len(const char *s, int len) { + char *dstbuf; struct json_object *jso = json_object_new(json_type_string); if (!jso) return NULL; jso->_delete = &json_object_string_delete; jso->_to_json_string = &json_object_string_to_json_string; - jso->o.c_string.str = (char*)malloc(len + 1); - if (!jso->o.c_string.str) - { - json_object_generic_delete(jso); - errno = ENOMEM; - return NULL; + if(len < LEN_DIRECT_STRING_DATA) { + dstbuf = jso->o.c_string.str.data; + } else { + jso->o.c_string.str.ptr = (char*)malloc(len + 1); + if (!jso->o.c_string.str.ptr) + { + json_object_generic_delete(jso); + errno = ENOMEM; + return NULL; + } + dstbuf = jso->o.c_string.str.ptr; } - memcpy(jso->o.c_string.str, (void *)s, len); - jso->o.c_string.str[len] = '\0'; + memcpy(dstbuf, (void *)s, len); + dstbuf[len] = '\0'; jso->o.c_string.len = len; return jso; } @@ -813,7 +833,7 @@ const char* json_object_get_string(struct json_object *jso) switch(jso->o_type) { case json_type_string: - return jso->o.c_string.str; + return get_string_component(jso); default: return json_object_to_json_string(jso); } diff --git a/json_object_private.h b/json_object_private.h index 5ed791b..67a77f8 100644 --- a/json_object_private.h +++ b/json_object_private.h @@ -16,6 +16,8 @@ extern "C" { #endif +#define LEN_DIRECT_STRING_DATA 32 /**< how many bytes are directly stored in json_object for strings? */ + typedef void (json_object_private_delete_fn)(struct json_object *o); struct json_object @@ -32,7 +34,13 @@ struct json_object struct lh_table *c_object; struct array_list *c_array; struct { - char *str; + union { + /* optimize: if we have small strings, we can store them + * directly. This saves considerable CPU cycles AND memory. + */ + char *ptr; + char data[LEN_DIRECT_STRING_DATA]; + } str; int len; } c_string; } o;