From 5abbd19f268a1faded0794d63fb4d8141924160f Mon Sep 17 00:00:00 2001 From: Miloslav Trmač Date: Thu, 21 Jun 2012 12:31:51 +0200 Subject: Remove an unnecessary pointer to array MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Be a little more explicit instead of relying on the compiler to optimize the variable away. Signed-off-by: Miloslav Trmač --- lib/buffer.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib/buffer.c') diff --git a/lib/buffer.c b/lib/buffer.c index ef448bf..acb813d 100644 --- a/lib/buffer.c +++ b/lib/buffer.c @@ -130,7 +130,7 @@ _ul_str_escape (const char *str, char *dest, size_t *length) default: if ((*p < ' ') || (*p >= 0177)) { - const char *json_hex_chars = "0123456789abcdef"; + static const char json_hex_chars[16] = "0123456789abcdef"; *q++ = '\\'; *q++ = 'u'; -- cgit From 4158df7874fe07ff731d756c9742188ce4d6e8c2 Mon Sep 17 00:00:00 2001 From: Miloslav Trmač Date: Thu, 21 Jun 2012 13:01:07 +0200 Subject: Fix 1-byte heap overflow in ul_buffer_finalize MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Miloslav Trmač --- lib/buffer.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'lib/buffer.c') diff --git a/lib/buffer.c b/lib/buffer.c index acb813d..93c5295 100644 --- a/lib/buffer.c +++ b/lib/buffer.c @@ -225,11 +225,15 @@ char * ul_buffer_finalize (ul_buffer_t *buffer) { if (buffer->msg[buffer->len - 1] == ',') - buffer->msg[buffer->len - 1] = '}'; - else { if (!_ul_buffer_ensure_size (buffer, buffer->len + 1)) return NULL; + buffer->msg[buffer->len - 1] = '}'; + } + else + { + if (!_ul_buffer_ensure_size (buffer, buffer->len + 2)) + return NULL; buffer->msg[buffer->len++] = '}'; } buffer->msg[buffer->len] = '\0'; -- cgit From 57e8a2324deb11d76c4b9c176677afa9b98b2e50 Mon Sep 17 00:00:00 2001 From: Gergely Nagy Date: Fri, 22 Jun 2012 15:01:44 +0200 Subject: Don't use \f in JSON MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit JSON-c 0.9 does not parse \f, so fall back to \uNNNN for now. Signed-off-by: Miloslav Trmač Signed-off-by: Gergely Nagy --- lib/buffer.c | 4 ---- 1 file changed, 4 deletions(-) (limited to 'lib/buffer.c') diff --git a/lib/buffer.c b/lib/buffer.c index 93c5295..a613c98 100644 --- a/lib/buffer.c +++ b/lib/buffer.c @@ -103,10 +103,6 @@ _ul_str_escape (const char *str, char *dest, size_t *length) *q++ = '\\'; *q++ = 'b'; break; - case '\f': - *q++ = '\\'; - *q++ = 'f'; - break; case '\n': *q++ = '\\'; *q++ = 'n'; -- cgit From 88c48725d12663dd807e28d65871f8db4ac7273e Mon Sep 17 00:00:00 2001 From: Gergely Nagy Date: Fri, 22 Jun 2012 15:06:49 +0200 Subject: Use a static exception map MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Make the map static, read-only and preinitialized, to avoid thread-safety problems. * Invert the map, making it non-zero for exceptional characters (so that non-exceptional characters don't need to be mentioned) * Tighten the set of exceptional characters, so that most of ASCII goes through the fast path. This increases the speed of test_perf_* by 7.7-20.6%. Signed-off-by: Miloslav Trmač Signed-off-by: Gergely Nagy --- lib/buffer.c | 76 ++++++++++++++++++++---------------------------------------- 1 file changed, 25 insertions(+), 51 deletions(-) (limited to 'lib/buffer.c') diff --git a/lib/buffer.c b/lib/buffer.c index a613c98..5cb8d3f 100644 --- a/lib/buffer.c +++ b/lib/buffer.c @@ -30,30 +30,10 @@ #include "config.h" #include "buffer.h" +#include #include #include -static const unsigned char json_exceptions[] = - { - 0x7f, 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, - 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, - 0x8f, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, - 0x97, 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, - 0x9f, 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, - 0xa7, 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, - 0xaf, 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, - 0xb7, 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, - 0xbf, 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, - 0xc7, 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, - 0xcf, 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, - 0xd7, 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, - 0xdf, 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, - 0xe7, 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, - 0xef, 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, - 0xf7, 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, - 0xff, '\0' - }; - static __thread ul_buffer_t escape_buffer; static void ul_buffer_finish (void) __attribute__((destructor)); @@ -67,10 +47,19 @@ ul_buffer_finish (void) static inline char * _ul_str_escape (const char *str, char *dest, size_t *length) { + /* Assumes ASCII! Keep in sync with the switch! */ + static const unsigned char json_exceptions[UCHAR_MAX + 1] = + { + [0x01] = 1, [0x02] = 1, [0x03] = 1, [0x04] = 1, [0x05] = 1, [0x06] = 1, + [0x07] = 1, [0x08] = 1, [0x09] = 1, [0x0a] = 1, [0x0b] = 1, [0x0c] = 1, + [0x0d] = 1, [0x0e] = 1, [0x0f] = 1, [0x10] = 1, [0x11] = 1, [0x12] = 1, + [0x13] = 1, [0x14] = 1, [0x15] = 1, [0x16] = 1, [0x17] = 1, [0x18] = 1, + [0x19] = 1, [0x1a] = 1, [0x1b] = 1, [0x1c] = 1, [0x1d] = 1, [0x1e] = 1, + [0x1f] = 1, ['\\'] = 1, ['"'] = 1 + }; + const unsigned char *p; char *q; - static unsigned char exmap[256]; - static int exmap_inited; if (!str) return NULL; @@ -78,25 +67,13 @@ _ul_str_escape (const char *str, char *dest, size_t *length) p = (unsigned char *)str; q = dest; - if (!exmap_inited) - { - const unsigned char *e = json_exceptions; - - memset (exmap, 0, 256); - while (*e) - { - exmap[*e] = 1; - e++; - } - exmap_inited = 1; - } - while (*p) { - if (exmap[*p]) + if (json_exceptions[*p] == 0) *q++ = *p; else { + /* Keep in sync with json_exceptions! */ switch (*p) { case '\b': @@ -124,20 +101,17 @@ _ul_str_escape (const char *str, char *dest, size_t *length) *q++ = '"'; break; default: - if ((*p < ' ') || (*p >= 0177)) - { - static const char json_hex_chars[16] = "0123456789abcdef"; - - *q++ = '\\'; - *q++ = 'u'; - *q++ = '0'; - *q++ = '0'; - *q++ = json_hex_chars[(*p) >> 4]; - *q++ = json_hex_chars[(*p) & 0xf]; - } - else - *q++ = *p; - break; + { + static const char json_hex_chars[16] = "0123456789abcdef"; + + *q++ = '\\'; + *q++ = 'u'; + *q++ = '0'; + *q++ = '0'; + *q++ = json_hex_chars[(*p) >> 4]; + *q++ = json_hex_chars[(*p) & 0xf]; + break; + } } } p++; -- cgit From 645e1eb4155bccb4586e63febfbba7828d4a61d7 Mon Sep 17 00:00:00 2001 From: Gergely Nagy Date: Fri, 22 Jun 2012 15:11:42 +0200 Subject: Fix error handling in buffer.c MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Don't lose old msg on realloc() failure * Don't dereference NULL on failure when buffer = (...) if (!buffer) { buffer->len = orig_len; ...} * To avoid the above pattern, use integer return values: "buffer" itself will not change in any case. * Add missing error handling Signed-off-by: Miloslav Trmač Signed-off-by: Gergely Nagy --- lib/buffer.c | 56 ++++++++++++++++++++++++++++++-------------------------- 1 file changed, 30 insertions(+), 26 deletions(-) (limited to 'lib/buffer.c') diff --git a/lib/buffer.c b/lib/buffer.c index 5cb8d3f..d54b048 100644 --- a/lib/buffer.c +++ b/lib/buffer.c @@ -123,26 +123,32 @@ _ul_str_escape (const char *str, char *dest, size_t *length) return dest; } -static inline ul_buffer_t * +static inline int _ul_buffer_ensure_size (ul_buffer_t *buffer, size_t size) { if (buffer->alloc < size) { - buffer->alloc += size * 2; - buffer->msg = realloc (buffer->msg, buffer->alloc); - if (!buffer->msg) - return NULL; + size_t new_alloc; + void *new_msg; + + new_alloc = buffer->alloc + size * 2; + new_msg = realloc (buffer->msg, new_alloc); + if (new_msg == NULL) + return -1; + buffer->alloc = new_alloc; + buffer->msg = new_msg; } - return buffer; + return 0; } -ul_buffer_t * +int ul_buffer_reset (ul_buffer_t *buffer) { + if (_ul_buffer_ensure_size (buffer, 512) != 0) + return -1; buffer->len = 1; - _ul_buffer_ensure_size (buffer, 512); buffer->msg[0] = '{'; - return buffer; + return 0; } ul_buffer_t * @@ -154,14 +160,14 @@ ul_buffer_append (ul_buffer_t *buffer, const char *key, const char *value) /* Append the key to the buffer */ escape_buffer.len = 0; - _ul_buffer_ensure_size (&escape_buffer, strlen (key) * 6 + 1); + if (_ul_buffer_ensure_size (&escape_buffer, strlen (key) * 6 + 1) != 0) + goto err; k = _ul_str_escape (key, escape_buffer.msg, &lk); if (!k) return NULL; - buffer = _ul_buffer_ensure_size (buffer, buffer->len + lk + 4); - if (!buffer) - return NULL; + if (_ul_buffer_ensure_size (buffer, buffer->len + lk + 4) != 0) + goto err; memcpy (buffer->msg + buffer->len, "\"", 1); memcpy (buffer->msg + buffer->len + 1, k, lk); @@ -169,26 +175,24 @@ ul_buffer_append (ul_buffer_t *buffer, const char *key, const char *value) /* Append the value to the buffer */ escape_buffer.len = 0; - _ul_buffer_ensure_size (&escape_buffer, strlen (value) * 6 + 1); + if (_ul_buffer_ensure_size (&escape_buffer, strlen (value) * 6 + 1) != 0) + goto err; v = _ul_str_escape (value, escape_buffer.msg, &lv); if (!v) - { - buffer->len = orig_len; - return NULL; - } + goto err; - buffer = _ul_buffer_ensure_size (buffer, buffer->len + lk + lv + 6); - if (!buffer) - { - buffer->len = orig_len; - return NULL; - } + if (_ul_buffer_ensure_size (buffer, buffer->len + lk + lv + 6) != 0) + goto err; memcpy (buffer->msg + buffer->len + 1 + lk + 3, v, lv); memcpy (buffer->msg + buffer->len + 1 + lk + 3 + lv, "\",", 2); buffer->len += lk + lv + 6; return buffer; + + err: + buffer->len = orig_len; + return NULL; } char * @@ -196,13 +200,13 @@ ul_buffer_finalize (ul_buffer_t *buffer) { if (buffer->msg[buffer->len - 1] == ',') { - if (!_ul_buffer_ensure_size (buffer, buffer->len + 1)) + if (_ul_buffer_ensure_size (buffer, buffer->len + 1) != 0) return NULL; buffer->msg[buffer->len - 1] = '}'; } else { - if (!_ul_buffer_ensure_size (buffer, buffer->len + 2)) + if (_ul_buffer_ensure_size (buffer, buffer->len + 2) != 0) return NULL; buffer->msg[buffer->len++] = '}'; } -- cgit From bae889300263bd5c1a7b8c5953d3545603e360fc Mon Sep 17 00:00:00 2001 From: Miloslav Trmač Date: Thu, 21 Jun 2012 16:20:45 +0200 Subject: Change return type of _ul_str_escape MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use an integer instead of pointer, like in the other cases in buffer.c. We won't need the return value in the future. Signed-off-by: Miloslav Trmač --- lib/buffer.c | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) (limited to 'lib/buffer.c') diff --git a/lib/buffer.c b/lib/buffer.c index d54b048..779d6bf 100644 --- a/lib/buffer.c +++ b/lib/buffer.c @@ -44,7 +44,7 @@ ul_buffer_finish (void) free (escape_buffer.msg); } -static inline char * +static inline int _ul_str_escape (const char *str, char *dest, size_t *length) { /* Assumes ASCII! Keep in sync with the switch! */ @@ -62,7 +62,7 @@ _ul_str_escape (const char *str, char *dest, size_t *length) char *q; if (!str) - return NULL; + return -1; p = (unsigned char *)str; q = dest; @@ -120,7 +120,7 @@ _ul_str_escape (const char *str, char *dest, size_t *length) *q = 0; if (length) *length = q - dest; - return dest; + return 0; } static inline int @@ -154,7 +154,6 @@ ul_buffer_reset (ul_buffer_t *buffer) ul_buffer_t * ul_buffer_append (ul_buffer_t *buffer, const char *key, const char *value) { - char *k, *v; size_t lk, lv; size_t orig_len = buffer->len; @@ -162,29 +161,27 @@ ul_buffer_append (ul_buffer_t *buffer, const char *key, const char *value) escape_buffer.len = 0; if (_ul_buffer_ensure_size (&escape_buffer, strlen (key) * 6 + 1) != 0) goto err; - k = _ul_str_escape (key, escape_buffer.msg, &lk); - if (!k) - return NULL; + if (_ul_str_escape (key, escape_buffer.msg, &lk) != 0) + goto err; if (_ul_buffer_ensure_size (buffer, buffer->len + lk + 4) != 0) goto err; memcpy (buffer->msg + buffer->len, "\"", 1); - memcpy (buffer->msg + buffer->len + 1, k, lk); + memcpy (buffer->msg + buffer->len + 1, escape_buffer.msg, lk); memcpy (buffer->msg + buffer->len + 1 + lk, "\":\"", 3); /* Append the value to the buffer */ escape_buffer.len = 0; if (_ul_buffer_ensure_size (&escape_buffer, strlen (value) * 6 + 1) != 0) goto err; - v = _ul_str_escape (value, escape_buffer.msg, &lv); - if (!v) + if (_ul_str_escape (value, escape_buffer.msg, &lv) != 0) goto err; if (_ul_buffer_ensure_size (buffer, buffer->len + lk + lv + 6) != 0) goto err; - memcpy (buffer->msg + buffer->len + 1 + lk + 3, v, lv); + memcpy (buffer->msg + buffer->len + 1 + lk + 3, escape_buffer.msg, lv); memcpy (buffer->msg + buffer->len + 1 + lk + 3 + lv, "\",", 2); buffer->len += lk + lv + 6; -- cgit From 64577eeed64b0c7a188e3d9d1d9b9fa8d0f7bbf5 Mon Sep 17 00:00:00 2001 From: Gergely Nagy Date: Fri, 22 Jun 2012 15:16:38 +0200 Subject: Simplify extending the buffer MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Most of the callers know how much the buffer needs extending, so don't ask them for the total size: new _ul_buffer_reserve_size replaces _ul_buffer_ensure_size, and the fast path is now inlined. Signed-off-by: Miloslav Trmač Signed-off-by: Gergely Nagy --- lib/buffer.c | 61 ++++++++++++++++++++++++++++++++++-------------------------- 1 file changed, 35 insertions(+), 26 deletions(-) (limited to 'lib/buffer.c') diff --git a/lib/buffer.c b/lib/buffer.c index 779d6bf..e6f064c 100644 --- a/lib/buffer.c +++ b/lib/buffer.c @@ -44,6 +44,32 @@ ul_buffer_finish (void) free (escape_buffer.msg); } +static int +_ul_buffer_realloc_for_min (ul_buffer_t *buffer, size_t min) +{ + size_t new_alloc; + void *new_msg; + + new_alloc = buffer->alloc + min * 2; + new_msg = realloc (buffer->msg, new_alloc); + if (new_msg == NULL) + return -1; + buffer->alloc = new_alloc; + buffer->msg = new_msg; + return 0; +} + +static inline int +_ul_buffer_reserve_size (ul_buffer_t *buffer, size_t size) +{ + size_t min; + + min = buffer->len + size; + if (buffer->alloc < min) + return _ul_buffer_realloc_for_min (buffer, min); + return 0; +} + static inline int _ul_str_escape (const char *str, char *dest, size_t *length) { @@ -123,31 +149,14 @@ _ul_str_escape (const char *str, char *dest, size_t *length) return 0; } -static inline int -_ul_buffer_ensure_size (ul_buffer_t *buffer, size_t size) -{ - if (buffer->alloc < size) - { - size_t new_alloc; - void *new_msg; - - new_alloc = buffer->alloc + size * 2; - new_msg = realloc (buffer->msg, new_alloc); - if (new_msg == NULL) - return -1; - buffer->alloc = new_alloc; - buffer->msg = new_msg; - } - return 0; -} - int ul_buffer_reset (ul_buffer_t *buffer) { - if (_ul_buffer_ensure_size (buffer, 512) != 0) + buffer->len = 0; + if (_ul_buffer_reserve_size (buffer, 512) != 0) return -1; - buffer->len = 1; buffer->msg[0] = '{'; + buffer->len = 1; return 0; } @@ -159,12 +168,12 @@ ul_buffer_append (ul_buffer_t *buffer, const char *key, const char *value) /* Append the key to the buffer */ escape_buffer.len = 0; - if (_ul_buffer_ensure_size (&escape_buffer, strlen (key) * 6 + 1) != 0) + if (_ul_buffer_reserve_size (&escape_buffer, strlen (key) * 6 + 1) != 0) goto err; if (_ul_str_escape (key, escape_buffer.msg, &lk) != 0) goto err; - if (_ul_buffer_ensure_size (buffer, buffer->len + lk + 4) != 0) + if (_ul_buffer_reserve_size (buffer, lk + 4) != 0) goto err; memcpy (buffer->msg + buffer->len, "\"", 1); @@ -173,12 +182,12 @@ ul_buffer_append (ul_buffer_t *buffer, const char *key, const char *value) /* Append the value to the buffer */ escape_buffer.len = 0; - if (_ul_buffer_ensure_size (&escape_buffer, strlen (value) * 6 + 1) != 0) + if (_ul_buffer_reserve_size (&escape_buffer, strlen (value) * 6 + 1) != 0) goto err; if (_ul_str_escape (value, escape_buffer.msg, &lv) != 0) goto err; - if (_ul_buffer_ensure_size (buffer, buffer->len + lk + lv + 6) != 0) + if (_ul_buffer_reserve_size (buffer, lk + lv + 6) != 0) goto err; memcpy (buffer->msg + buffer->len + 1 + lk + 3, escape_buffer.msg, lv); @@ -197,13 +206,13 @@ ul_buffer_finalize (ul_buffer_t *buffer) { if (buffer->msg[buffer->len - 1] == ',') { - if (_ul_buffer_ensure_size (buffer, buffer->len + 1) != 0) + if (_ul_buffer_reserve_size (buffer, 1) != 0) return NULL; buffer->msg[buffer->len - 1] = '}'; } else { - if (_ul_buffer_ensure_size (buffer, buffer->len + 2) != 0) + if (_ul_buffer_reserve_size (buffer, 2) != 0) return NULL; buffer->msg[buffer->len++] = '}'; } -- cgit From 168dc768a7e5f70f2a0b03402f42a173924522c7 Mon Sep 17 00:00:00 2001 From: Gergely Nagy Date: Fri, 22 Jun 2012 15:19:27 +0200 Subject: Use pointers instead of offsets in ul_buffer_t MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This avoids various additions and subtractions on the fast path. Signed-off-by: Miloslav Trmač Signed-off-by: Gergely Nagy --- lib/buffer.c | 55 ++++++++++++++++++++++++++++--------------------------- 1 file changed, 28 insertions(+), 27 deletions(-) (limited to 'lib/buffer.c') diff --git a/lib/buffer.c b/lib/buffer.c index e6f064c..5cc94ed 100644 --- a/lib/buffer.c +++ b/lib/buffer.c @@ -45,28 +45,27 @@ ul_buffer_finish (void) } static int -_ul_buffer_realloc_for_min (ul_buffer_t *buffer, size_t min) +_ul_buffer_realloc_to_reserve (ul_buffer_t *buffer, size_t size) { - size_t new_alloc; + size_t new_alloc, ptr_offset; void *new_msg; - new_alloc = buffer->alloc + min * 2; + new_alloc = (buffer->alloc_end - buffer->msg + size) * 2; + ptr_offset = buffer->ptr - buffer->msg; new_msg = realloc (buffer->msg, new_alloc); if (new_msg == NULL) return -1; - buffer->alloc = new_alloc; buffer->msg = new_msg; + buffer->ptr = new_msg + ptr_offset; + buffer->alloc_end = new_msg + new_alloc; return 0; } static inline int _ul_buffer_reserve_size (ul_buffer_t *buffer, size_t size) { - size_t min; - - min = buffer->len + size; - if (buffer->alloc < min) - return _ul_buffer_realloc_for_min (buffer, min); + if (buffer->alloc_end - buffer->ptr < size) + return _ul_buffer_realloc_to_reserve (buffer, size); return 0; } @@ -152,11 +151,10 @@ _ul_str_escape (const char *str, char *dest, size_t *length) int ul_buffer_reset (ul_buffer_t *buffer) { - buffer->len = 0; + buffer->ptr = buffer->msg; if (_ul_buffer_reserve_size (buffer, 512) != 0) return -1; - buffer->msg[0] = '{'; - buffer->len = 1; + *buffer->ptr++ = '{'; return 0; } @@ -164,10 +162,10 @@ ul_buffer_t * ul_buffer_append (ul_buffer_t *buffer, const char *key, const char *value) { size_t lk, lv; - size_t orig_len = buffer->len; + size_t orig_len = buffer->ptr - buffer->msg; /* Append the key to the buffer */ - escape_buffer.len = 0; + escape_buffer.ptr = escape_buffer.msg; if (_ul_buffer_reserve_size (&escape_buffer, strlen (key) * 6 + 1) != 0) goto err; if (_ul_str_escape (key, escape_buffer.msg, &lk) != 0) @@ -176,46 +174,49 @@ ul_buffer_append (ul_buffer_t *buffer, const char *key, const char *value) if (_ul_buffer_reserve_size (buffer, lk + 4) != 0) goto err; - memcpy (buffer->msg + buffer->len, "\"", 1); - memcpy (buffer->msg + buffer->len + 1, escape_buffer.msg, lk); - memcpy (buffer->msg + buffer->len + 1 + lk, "\":\"", 3); + *buffer->ptr++ = '"'; + memcpy (buffer->ptr, escape_buffer.msg, lk); + buffer->ptr += lk; + memcpy (buffer->ptr, "\":\"", 3); + buffer->ptr += 3; /* Append the value to the buffer */ - escape_buffer.len = 0; + escape_buffer.ptr = escape_buffer.msg; if (_ul_buffer_reserve_size (&escape_buffer, strlen (value) * 6 + 1) != 0) goto err; if (_ul_str_escape (value, escape_buffer.msg, &lv) != 0) goto err; - if (_ul_buffer_reserve_size (buffer, lk + lv + 6) != 0) + if (_ul_buffer_reserve_size (buffer, lv + 2) != 0) goto err; - memcpy (buffer->msg + buffer->len + 1 + lk + 3, escape_buffer.msg, lv); - memcpy (buffer->msg + buffer->len + 1 + lk + 3 + lv, "\",", 2); - buffer->len += lk + lv + 6; + memcpy (buffer->ptr, escape_buffer.msg, lv); + buffer->ptr += lv; + memcpy (buffer->ptr, "\",", 2); + buffer->ptr += 2; return buffer; err: - buffer->len = orig_len; + buffer->ptr = buffer->msg + orig_len; return NULL; } char * ul_buffer_finalize (ul_buffer_t *buffer) { - if (buffer->msg[buffer->len - 1] == ',') + if (buffer->ptr[-1] == ',') { if (_ul_buffer_reserve_size (buffer, 1) != 0) return NULL; - buffer->msg[buffer->len - 1] = '}'; + buffer->ptr[-1] = '}'; } else { if (_ul_buffer_reserve_size (buffer, 2) != 0) return NULL; - buffer->msg[buffer->len++] = '}'; + *buffer->ptr++ = '}'; } - buffer->msg[buffer->len] = '\0'; + *buffer->ptr++ = '\0'; return buffer->msg; } -- cgit From 76a5b0ad508949707cd77c61c173e543221fcef9 Mon Sep 17 00:00:00 2001 From: Gergely Nagy Date: Fri, 22 Jun 2012 15:28:53 +0200 Subject: Escape values directly into a buffer MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Instead of precomputing a buffer length, do only one pass, extending the buffer as necessary. Signed-off-by: Miloslav Trmač Signed-off-by: Gergely Nagy --- lib/buffer.c | 80 +++++++++++++++++++++++++++++++++++++++++------------------- 1 file changed, 55 insertions(+), 25 deletions(-) (limited to 'lib/buffer.c') diff --git a/lib/buffer.c b/lib/buffer.c index 5cc94ed..ef4e2d7 100644 --- a/lib/buffer.c +++ b/lib/buffer.c @@ -70,7 +70,7 @@ _ul_buffer_reserve_size (ul_buffer_t *buffer, size_t size) } static inline int -_ul_str_escape (const char *str, char *dest, size_t *length) +_ul_str_escape (ul_buffer_t *dest, const char *str) { /* Assumes ASCII! Keep in sync with the switch! */ static const unsigned char json_exceptions[UCHAR_MAX + 1] = @@ -84,51 +84,85 @@ _ul_str_escape (const char *str, char *dest, size_t *length) }; const unsigned char *p; - char *q; + char *q, *end; if (!str) return -1; p = (unsigned char *)str; - q = dest; + q = dest->ptr; + end = dest->alloc_end; + +#define BUFFER_RESERVE(SIZE) \ + do \ + { \ + if (end - q < (SIZE)) \ + { \ + dest->ptr = q; \ + if (_ul_buffer_reserve_size (dest, (SIZE)) != 0) \ + return -1; \ + q = dest->ptr; \ + end = dest->alloc_end; \ + } \ + } \ + while (0) while (*p) { if (json_exceptions[*p] == 0) - *q++ = *p; + { + /* This is a slightly faster variant of equivalent to + BUFFER_RESERVE (1) */ + if (q == end) + { + dest->ptr = q; + if (_ul_buffer_reserve_size (dest, 1) != 0) + return -1; + q = dest->ptr; + end = dest->alloc_end; + } + *q++ = *p; + } else { /* Keep in sync with json_exceptions! */ switch (*p) { case '\b': - *q++ = '\\'; - *q++ = 'b'; + BUFFER_RESERVE (2); + memcpy (q, "\\b", 2); + q += 2; break; case '\n': - *q++ = '\\'; - *q++ = 'n'; + BUFFER_RESERVE (2); + memcpy (q, "\\n", 2); + q += 2; break; case '\r': - *q++ = '\\'; - *q++ = 'r'; + BUFFER_RESERVE (2); + memcpy (q, "\\r", 2); + q += 2; break; case '\t': - *q++ = '\\'; - *q++ = 't'; + BUFFER_RESERVE (2); + memcpy (q, "\\t", 2); + q += 2; break; case '\\': - *q++ = '\\'; - *q++ = '\\'; + BUFFER_RESERVE (2); + memcpy (q, "\\\\", 2); + q += 2; break; case '"': - *q++ = '\\'; - *q++ = '"'; + BUFFER_RESERVE (2); + memcpy (q, "\\\"", 2); + q += 2; break; default: { static const char json_hex_chars[16] = "0123456789abcdef"; + BUFFER_RESERVE (6); *q++ = '\\'; *q++ = 'u'; *q++ = '0'; @@ -141,10 +175,8 @@ _ul_str_escape (const char *str, char *dest, size_t *length) } p++; } + dest->ptr = q; - *q = 0; - if (length) - *length = q - dest; return 0; } @@ -166,10 +198,9 @@ ul_buffer_append (ul_buffer_t *buffer, const char *key, const char *value) /* Append the key to the buffer */ escape_buffer.ptr = escape_buffer.msg; - if (_ul_buffer_reserve_size (&escape_buffer, strlen (key) * 6 + 1) != 0) - goto err; - if (_ul_str_escape (key, escape_buffer.msg, &lk) != 0) + if (_ul_str_escape (&escape_buffer, key) != 0) goto err; + lk = escape_buffer.ptr - escape_buffer.msg; if (_ul_buffer_reserve_size (buffer, lk + 4) != 0) goto err; @@ -182,10 +213,9 @@ ul_buffer_append (ul_buffer_t *buffer, const char *key, const char *value) /* Append the value to the buffer */ escape_buffer.ptr = escape_buffer.msg; - if (_ul_buffer_reserve_size (&escape_buffer, strlen (value) * 6 + 1) != 0) - goto err; - if (_ul_str_escape (value, escape_buffer.msg, &lv) != 0) + if (_ul_str_escape (&escape_buffer, value) != 0) goto err; + lv = escape_buffer.ptr - escape_buffer.msg; if (_ul_buffer_reserve_size (buffer, lv + 2) != 0) goto err; -- cgit From 8835222c34bf853f33119eeb49575b8ad71c5c5f Mon Sep 17 00:00:00 2001 From: Gergely Nagy Date: Fri, 22 Jun 2012 15:32:14 +0200 Subject: Remove escape_buffer entirely MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Output the escaped content directly into the destination buffer, avoiding the memory copy and associated overhead. This finishes the series, and brings another 6.6-18.0% speed improvement in test_perf, compared to the previous increase with using a static exception map. Signed-off-by: Miloslav Trmač Signed-off-by: Gergely Nagy --- lib/buffer.c | 32 +++++++------------------------- 1 file changed, 7 insertions(+), 25 deletions(-) (limited to 'lib/buffer.c') diff --git a/lib/buffer.c b/lib/buffer.c index ef4e2d7..cdb494c 100644 --- a/lib/buffer.c +++ b/lib/buffer.c @@ -34,16 +34,6 @@ #include #include -static __thread ul_buffer_t escape_buffer; - -static void ul_buffer_finish (void) __attribute__((destructor)); - -static void -ul_buffer_finish (void) -{ - free (escape_buffer.msg); -} - static int _ul_buffer_realloc_to_reserve (ul_buffer_t *buffer, size_t size) { @@ -193,35 +183,27 @@ ul_buffer_reset (ul_buffer_t *buffer) ul_buffer_t * ul_buffer_append (ul_buffer_t *buffer, const char *key, const char *value) { - size_t lk, lv; size_t orig_len = buffer->ptr - buffer->msg; /* Append the key to the buffer */ - escape_buffer.ptr = escape_buffer.msg; - if (_ul_str_escape (&escape_buffer, key) != 0) + if (_ul_buffer_reserve_size (buffer, 1) != 0) goto err; - lk = escape_buffer.ptr - escape_buffer.msg; + *buffer->ptr++ = '"'; - if (_ul_buffer_reserve_size (buffer, lk + 4) != 0) + if (_ul_str_escape (buffer, key) != 0) goto err; - *buffer->ptr++ = '"'; - memcpy (buffer->ptr, escape_buffer.msg, lk); - buffer->ptr += lk; + if (_ul_buffer_reserve_size (buffer, 3) != 0) + goto err; memcpy (buffer->ptr, "\":\"", 3); buffer->ptr += 3; /* Append the value to the buffer */ - escape_buffer.ptr = escape_buffer.msg; - if (_ul_str_escape (&escape_buffer, value) != 0) + if (_ul_str_escape (buffer, value) != 0) goto err; - lv = escape_buffer.ptr - escape_buffer.msg; - if (_ul_buffer_reserve_size (buffer, lv + 2) != 0) + if (_ul_buffer_reserve_size (buffer, 2) != 0) goto err; - - memcpy (buffer->ptr, escape_buffer.msg, lv); - buffer->ptr += lv; memcpy (buffer->ptr, "\",", 2); buffer->ptr += 2; -- cgit From 5936ab0875cf9a3e5cec59babee45a9016e0e271 Mon Sep 17 00:00:00 2001 From: Miloslav Trmač Date: Mon, 30 Jul 2012 09:19:06 +0200 Subject: Add an explicit cast to avoid a warning MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ... with -Wsign-compare. Signed-off-by: Miloslav Trmač --- lib/buffer.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib/buffer.c') diff --git a/lib/buffer.c b/lib/buffer.c index cdb494c..79c18fd 100644 --- a/lib/buffer.c +++ b/lib/buffer.c @@ -54,7 +54,7 @@ _ul_buffer_realloc_to_reserve (ul_buffer_t *buffer, size_t size) static inline int _ul_buffer_reserve_size (ul_buffer_t *buffer, size_t size) { - if (buffer->alloc_end - buffer->ptr < size) + if ((size_t)(buffer->alloc_end - buffer->ptr) < size) return _ul_buffer_realloc_to_reserve (buffer, size); return 0; } -- cgit