From 419d2fc14d2bedc6d5a7080ee80df8330884ea6c Mon Sep 17 00:00:00 2001 From: Takashi Kokubun Date: Fri, 4 Nov 2022 23:58:43 -0700 Subject: [PATCH] [ruby/erb] Optimize the no-escape case with strpbrk (https://github.com/ruby/erb/pull/29) Typically, strpbrk(3) is optimized pretty well with SIMD instructions. Just using it makes this as fast as a SIMD-based implementation for the no-escape case. Not utilizing this for escaped cases because memory allocation would be a more significant bottleneck for many strings anyway. Also, there'll be some overhead in calling a C function (strpbrk) many times because we're not using SIMD instructions directly. So using strpbrk all the time might not necessarily be faster. --- ext/erb/erb.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/ext/erb/erb.c b/ext/erb/erb.c index c90f77f7b1..1e4842c793 100644 --- a/ext/erb/erb.c +++ b/ext/erb/erb.c @@ -38,6 +38,12 @@ escaped_length(VALUE str) static VALUE optimized_escape_html(VALUE str) { + // Optimize the most common, no-escape case with strpbrk(3). Not using it after + // this because calling a C function many times could be slower for some cases. + if (strpbrk(RSTRING_PTR(str), "'&\"<>") == NULL) { + return str; + } + VALUE vbuf; char *buf = ALLOCV_N(char, vbuf, escaped_length(str)); const char *cstr = RSTRING_PTR(str); @@ -56,11 +62,8 @@ optimized_escape_html(VALUE str) } } - VALUE escaped = str; - if (RSTRING_LEN(str) < (dest - buf)) { - escaped = rb_str_new(buf, dest - buf); - preserve_original_state(str, escaped); - } + VALUE escaped = rb_str_new(buf, dest - buf); + preserve_original_state(str, escaped); ALLOCV_END(vbuf); return escaped; }