Skip to content

Commit 6a77d43

Browse files
noteflakesnobu
authored andcommitted
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 3a54b25 commit 6a77d43

File tree

1 file changed

+20
-7
lines changed

1 file changed

+20
-7
lines changed

ext/cgi/escape/escape.c

Lines changed: 20 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -47,31 +47,44 @@ optimized_escape_html(VALUE str)
4747
{
4848
VALUE escaped;
4949
VALUE vbuf;
50-
char *buf = ALLOCV_N(char, vbuf, escaped_length(str));
50+
char *buf = NULL;
5151
const char *cstr = RSTRING_PTR(str);
5252
const char *end = cstr + RSTRING_LEN(str);
5353

54-
char *dest = buf;
54+
const char *segment_start = cstr;
55+
char *dest = NULL;
5556
while (cstr < end) {
5657
const unsigned char c = *cstr++;
5758
uint8_t len = html_escape_table[c].len;
5859
if (len) {
60+
size_t segment_len = cstr - segment_start - 1;
61+
if (!buf) {
62+
buf = ALLOCV_N(char, vbuf, escaped_length(str));
63+
dest = buf;
64+
}
65+
if (segment_len) {
66+
memcpy(dest, segment_start, segment_len);
67+
dest += segment_len;
68+
}
69+
segment_start = cstr;
5970
memcpy(dest, html_escape_table[c].str, len);
6071
dest += len;
6172
}
62-
else {
63-
*dest++ = c;
64-
}
6573
}
6674

67-
if (RSTRING_LEN(str) < (dest - buf)) {
75+
if (buf) {
76+
size_t segment_len = cstr - segment_start;
77+
if (segment_len) {
78+
memcpy(dest, segment_start, segment_len);
79+
dest += segment_len;
80+
}
6881
escaped = rb_str_new(buf, dest - buf);
6982
preserve_original_state(str, escaped);
83+
ALLOCV_END(vbuf);
7084
}
7185
else {
7286
escaped = rb_str_dup(str);
7387
}
74-
ALLOCV_END(vbuf);
7588
return escaped;
7689
}
7790

0 commit comments

Comments
 (0)