Skip to content

Commit 8834387

Browse files
committed
escape_html: Avoid buffer allocation for strings
with no escapable character - Perform buffer allocation on first instance of escapable character. - Instead of copying characters one at a time, copy unescaped segments using `memcpy`.
1 parent 9d9a2eb commit 8834387

File tree

1 file changed

+20
-8
lines changed

1 file changed

+20
-8
lines changed

ext/cgi/escape/escape.c

Lines changed: 20 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -46,32 +46,44 @@ static VALUE
4646
optimized_escape_html(VALUE str)
4747
{
4848
VALUE vbuf;
49-
char *buf = ALLOCV_N(char, vbuf, escaped_length(str));
49+
char *buf = NULL;
5050
const char *cstr = RSTRING_PTR(str);
5151
const char *end = cstr + RSTRING_LEN(str);
5252

53-
char *dest = buf;
53+
const char *segment_start = cstr;
54+
char *dest = NULL;
5455
while (cstr < end) {
5556
const unsigned char c = *cstr++;
5657
uint8_t len = html_escape_table[c].len;
5758
if (len) {
59+
size_t segment_len = cstr - segment_start - 1;
60+
if (!buf) {
61+
buf = ALLOCV_N(char, vbuf, escaped_length(str));
62+
dest = buf;
63+
}
64+
if (segment_len) {
65+
memcpy(dest, segment_start, segment_len);
66+
dest += segment_len;
67+
}
68+
segment_start = cstr;
5869
memcpy(dest, html_escape_table[c].str, len);
5970
dest += len;
6071
}
61-
else {
62-
*dest++ = c;
63-
}
6472
}
65-
6673
VALUE escaped;
67-
if (RSTRING_LEN(str) < (dest - buf)) {
74+
if (buf) {
75+
size_t segment_len = cstr - segment_start;
76+
if (segment_len) {
77+
memcpy(dest, segment_start, segment_len);
78+
dest += segment_len;
79+
}
6880
escaped = rb_str_new(buf, dest - buf);
6981
preserve_original_state(str, escaped);
82+
ALLOCV_END(vbuf);
7083
}
7184
else {
7285
escaped = rb_str_dup(str);
7386
}
74-
ALLOCV_END(vbuf);
7587
return escaped;
7688
}
7789

0 commit comments

Comments
 (0)