summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLloyd Hilaiel <lloyd@hilaiel.com>2011-11-28 12:45:52 -0700
committerLloyd Hilaiel <lloyd@hilaiel.com>2011-11-28 12:45:52 -0700
commitd2d848936c79833a69d09bb73dc068f15cbc6cba (patch)
treef641f96539f1504e421e1891a67e26b8668c149d
parent84fe4e84115099eed3a318337b33141875033676 (diff)
parentb8f76ff2ca777559961a2cf2ae34252c10b5beb1 (diff)
downloadyajl-d2d848936c79833a69d09bb73dc068f15cbc6cba.tar.gz
Merge branch 'encode-speedup' of https://github.com/bpowers/yajl into 2.1.0
-rw-r--r--src/yajl_encode.c48
1 files changed, 35 insertions, 13 deletions
diff --git a/src/yajl_encode.c b/src/yajl_encode.c
index 9dc9a3e..9770df0 100644
--- a/src/yajl_encode.c
+++ b/src/yajl_encode.c
@@ -23,7 +23,7 @@
static void CharToHex(unsigned char c, char * hexBuf)
{
- const char * hexchar = "0123456789ABCDEF";
+ static const char * hexchar = "0123456789ABCDEF";
hexBuf[0] = hexchar[c >> 4];
hexBuf[1] = hexchar[c & 0x0F];
}
@@ -37,36 +37,58 @@ yajl_string_encode(const yajl_print_t print,
{
size_t beg = 0;
size_t end = 0;
+ size_t escaped_len;
+ char escBuf[3];
char hexBuf[7];
+ escBuf[0] = '\\';
+ escBuf[2] = 0;
hexBuf[0] = '\\'; hexBuf[1] = 'u'; hexBuf[2] = '0'; hexBuf[3] = '0';
hexBuf[6] = 0;
while (end < len) {
+ const unsigned char chr = str[end];
const char * escaped = NULL;
- switch (str[end]) {
- case '\r': escaped = "\\r"; break;
- case '\n': escaped = "\\n"; break;
- case '\\': escaped = "\\\\"; break;
+ escBuf[1] = 0;
+ /* we're not going to be escaping most characters, so first
+ * check for this common case (of doing nothing). Doing so
+ * decreases the runtime of this function by around 30%.
+ */
+ if (chr > '/') {
/* it is not required to escape a solidus in JSON:
* read sec. 2.5: http://www.ietf.org/rfc/rfc4627.txt
* specifically, this production from the grammar:
* unescaped = %x20-21 / %x23-5B / %x5D-10FFFF
*/
- case '/': if (escape_solidus) escaped = "\\/"; break;
- case '"': escaped = "\\\""; break;
- case '\f': escaped = "\\f"; break;
- case '\b': escaped = "\\b"; break;
- case '\t': escaped = "\\t"; break;
+ if (chr == '\\') {
+ escBuf[1] = '\\';
+ }
+ } else if (chr == ' ' || (chr < '/' && chr > ')')) {
+ /* skip these fairly common cases */
+ } else {
+ switch (chr) {
+ case '\r': escBuf[1] = 'r'; break;
+ case '\n': escBuf[1] = 'n'; break;
+ case '"': escBuf[1] = '"'; break;
+ case '\t': escBuf[1] = 't'; break;
+ case '\f': escBuf[1] = 'f'; break;
+ case '\b': escBuf[1] = 'b'; break;
+ case '/': if (escape_solidus) escBuf[1] = '/'; break;
default:
- if ((unsigned char) str[end] < 32) {
- CharToHex(str[end], hexBuf + 4);
+ if (chr < 32) {
+ CharToHex(chr, hexBuf + 4);
escaped = hexBuf;
+ escaped_len = 6;
}
break;
+ }
+ }
+ if (escBuf[1] != 0) {
+ escaped = escBuf;
+ escaped_len = 2;
}
if (escaped != NULL) {
print(ctx, (const char *) (str + beg), end - beg);
- print(ctx, escaped, (unsigned int)strlen(escaped));
+ print(ctx, escaped, escaped_len);
beg = ++end;
} else {
++end;