Skip to content

Commit fa54a9c

Browse files
noteflakesmatzbot
authored andcommitted
[ruby/erb] html_escape: Avoid buffer allocation for strings with no
escapable character (ruby/erb#87) This change improves reduces allocations and makes `html_escape` ~35% faster in a benchmark with escaped strings taken from the `test_html_escape` test in `test/test_erb.rb`. - Perform buffer allocation on first instance of escapable character. - Instead of copying characters one at a time, copy unescaped segments using `memcpy`. ruby/erb@aa482890fe
1 parent 89dc79e commit fa54a9c

File tree

1 file changed

+21
-6
lines changed

1 file changed

+21
-6
lines changed

ext/erb/escape/escape.c

Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -39,29 +39,44 @@ static VALUE
3939
optimized_escape_html(VALUE str)
4040
{
4141
VALUE vbuf;
42-
char *buf = ALLOCV_N(char, vbuf, escaped_length(str));
42+
char *buf = NULL;
4343
const char *cstr = RSTRING_PTR(str);
4444
const char *end = cstr + RSTRING_LEN(str);
4545

46-
char *dest = buf;
46+
const char *segment_start = cstr;
47+
char *dest = NULL;
4748
while (cstr < end) {
4849
const unsigned char c = *cstr++;
4950
uint8_t len = html_escape_table[c].len;
5051
if (len) {
52+
uint16_t segment_len = cstr - segment_start - 1;
53+
if (!buf) {
54+
buf = ALLOCV_N(char, vbuf, escaped_length(str));
55+
dest = buf;
56+
}
57+
if (segment_len) {
58+
memcpy(dest, segment_start, segment_len);
59+
dest += segment_len;
60+
}
61+
segment_start = cstr;
5162
memcpy(dest, html_escape_table[c].str, len);
5263
dest += len;
5364
}
54-
else {
55-
*dest++ = c;
65+
}
66+
if (buf) {
67+
uint16_t segment_len = cstr - segment_start;
68+
if (segment_len) {
69+
memcpy(dest, segment_start, segment_len);
70+
dest += segment_len;
5671
}
5772
}
5873

5974
VALUE escaped = str;
60-
if (RSTRING_LEN(str) < (dest - buf)) {
75+
if (buf) {
6176
escaped = rb_str_new(buf, dest - buf);
6277
preserve_original_state(str, escaped);
78+
ALLOCV_END(vbuf);
6379
}
64-
ALLOCV_END(vbuf);
6580
return escaped;
6681
}
6782

0 commit comments

Comments
 (0)