Skip to content

Instantly share code, notes, and snippets.

@k0kubun
Created October 29, 2022 07:14
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save k0kubun/f66d6fe1e6ba821e4263257e504ba28f to your computer and use it in GitHub Desktop.
Save k0kubun/f66d6fe1e6ba821e4263257e504ba28f to your computer and use it in GitHub Desktop.
ruby 3.2.0dev (2022-10-26T06:02:04Z master 94f3aa2126) [x86_64-linux]
Warming up --------------------------------------
before 1.409M i/100ms
after 1.895M i/100ms
Calculating -------------------------------------
before 13.931M (± 0.1%) i/s - 70.435M in 5.055915s
after 18.669M (± 0.3%) i/s - 94.769M in 5.076395s
Comparison:
after: 18668840.0 i/s
before: 13931312.1 i/s - 1.34x (± 0.00) slower
require 'benchmark/ips'
require 'cgi'
require 'cgi/escape'
str = "string"
Benchmark.ips do |x|
x.report('before') { CGI.escapeHTML(str) }
x.report('after') { CGI.escapeHTML2(str) }
x.compare!
end
diff --git a/ext/cgi/escape/escape.c b/ext/cgi/escape/escape.c
index c5b76de596..508cd36f72 100644
--- a/ext/cgi/escape/escape.c
+++ b/ext/cgi/escape/escape.c
@@ -75,6 +75,39 @@ optimized_escape_html(VALUE str)
return escaped;
}
+static VALUE
+optimized_escape_html2(VALUE str)
+{
+ VALUE vbuf;
+ char *buf = ALLOCV_N(char, vbuf, escaped_length(str));
+ const char *cstr = RSTRING_PTR(str);
+ const char *end = cstr + RSTRING_LEN(str);
+
+ char *dest = buf;
+ while (cstr < end) {
+ const unsigned char c = *cstr++;
+ uint8_t len = html_escape_table[c].len;
+ if (len) {
+ memcpy(dest, html_escape_table[c].str, len);
+ dest += len;
+ }
+ else {
+ *dest++ = c;
+ }
+ }
+
+ VALUE escaped;
+ if (RSTRING_LEN(str) < (dest - buf)) {
+ escaped = rb_str_new(buf, dest - buf);
+ preserve_original_state(str, escaped);
+ }
+ else {
+ escaped = str;
+ }
+ ALLOCV_END(vbuf);
+ return escaped;
+}
+
static VALUE
optimized_unescape_html(VALUE str)
{
@@ -324,6 +357,19 @@ cgiesc_escape_html(VALUE self, VALUE str)
}
}
+static VALUE
+cgiesc_escape_html2(VALUE self, VALUE str)
+{
+ StringValue(str);
+
+ if (rb_enc_str_asciicompat_p(str)) {
+ return optimized_escape_html2(str);
+ }
+ else {
+ return rb_call_super(1, &str);
+ }
+}
+
/*
* call-seq:
* CGI.unescapeHTML(string) -> string
@@ -456,6 +502,7 @@ InitVM_escape(void)
rb_mEscape = rb_define_module_under(rb_cCGI, "Escape");
rb_mUtil = rb_define_module_under(rb_cCGI, "Util");
rb_define_method(rb_mEscape, "escapeHTML", cgiesc_escape_html, 1);
+ rb_define_method(rb_mEscape, "escapeHTML2", cgiesc_escape_html2, 1);
rb_define_method(rb_mEscape, "unescapeHTML", cgiesc_unescape_html, 1);
rb_define_method(rb_mEscape, "escapeURIComponent", cgiesc_escape_uri_component, 1);
rb_define_method(rb_mEscape, "unescapeURIComponent", cgiesc_unescape_uri_component, -1);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment