From: Rusty Russell Date: Tue, 21 May 2019 04:34:49 +0000 (+0930) Subject: json_escape: add fast-path for when we don't need to escape. X-Git-Url: https://git.ozlabs.org/?a=commitdiff_plain;h=3ceb24bf19adbe59bf8aeda9cc1426b4ba2244c2;p=ccan json_escape: add fast-path for when we don't need to escape. Signed-off-by: Rusty Russell --- diff --git a/ccan/json_escape/json_escape.c b/ccan/json_escape/json_escape.c index d344940d..ed4bfab9 100644 --- a/ccan/json_escape/json_escape.c +++ b/ccan/json_escape/json_escape.c @@ -19,6 +19,18 @@ bool json_escape_eq(const struct json_escape *a, const struct json_escape *b) return streq(a->s, b->s); } +bool json_escape_needed(const char *str, size_t len) +{ + for (size_t i = 0; i < len; i++) { + if ((unsigned)str[i] < ' ' + || str[i] == 127 + || str[i] == '"' + || str[i] == '\\') + return true; + } + return false; +} + static struct json_escape *escape(const tal_t *ctx, const char *str TAKES, size_t len, @@ -27,6 +39,16 @@ static struct json_escape *escape(const tal_t *ctx, struct json_escape *esc; size_t i, n; + /* Fast path: can steal, and nothing to escape. */ + if (is_taken(str) + && tal_count(str) > len + && !json_escape_needed(str, len)) { + taken(str); + esc = (struct json_escape *)tal_steal(ctx, str); + esc->s[len] = '\0'; + return esc; + } + /* Worst case: all \uXXXX */ esc = (struct json_escape *)tal_arr(ctx, char, len * 6 + 1); diff --git a/ccan/json_escape/json_escape.h b/ccan/json_escape/json_escape.h index b8e0dfca..5b33432f 100644 --- a/ccan/json_escape/json_escape.h +++ b/ccan/json_escape/json_escape.h @@ -27,7 +27,8 @@ struct json_escape *json_escape_len(const tal_t *ctx, struct json_escape *json_partial_escape(const tal_t *ctx, const char *str TAKES); -/* Extract a JSON-escaped string. */ +/* Do we need to escape this str? */ +bool json_escape_needed(const char *str, size_t len); /* Are two escape json strings identical? */ bool json_escape_eq(const struct json_escape *a, diff --git a/ccan/json_escape/test/run-take.c b/ccan/json_escape/test/run-take.c new file mode 100644 index 00000000..f3b62a79 --- /dev/null +++ b/ccan/json_escape/test/run-take.c @@ -0,0 +1,35 @@ +#include +/* Include the C files directly. */ +#include +#include + +int main(void) +{ + const tal_t *ctx = tal(NULL, char); + struct json_escape *e; + char *p; + + /* This is how many tests you plan to run */ + plan_tests(5); + + /* This should simply be tal_steal */ + p = tal_dup_arr(NULL, char, "Hello", 6, 0); + e = json_escape(ctx, take(p)); + ok1(!strcmp(e->s, "Hello")); + ok1((void *)e == (void *)p); + ok1(tal_parent(e) == ctx); + + /* This can't be tal_steal, but still should be freed. */ + p = tal_dup_arr(NULL, char, + "\\\b\f\n\r\t\"" + "\\\\\\b\\f\\n\\r\\t\\\"", 22, 0); + e = json_escape(ctx, take(p)); + ok1(tal_parent(e) == ctx); + ok1(!strcmp(e->s, + "\\\\\\b\\f\\n\\r\\t\\\"" + "\\\\\\\\\\\\b\\\\f\\\\n\\\\r\\\\t\\\\\\\"")); + tal_free(ctx); + + /* This exits depending on whether all tests passed */ + return exit_status(); +}