[前][次][番号順一覧][スレッド一覧]

ruby-changes:41657

From: nobu <ko1@a...>
Date: Thu, 4 Feb 2016 12:39:14 +0900 (JST)
Subject: [ruby-changes:41657] nobu:r53731 (trunk): cgi/escape: Optimize CGI.escape

nobu	2016-02-04 12:39:12 +0900 (Thu, 04 Feb 2016)

  New Revision: 53731

  https://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=revision&revision=53731

  Log:
    cgi/escape: Optimize CGI.escape
    
    * cgi/escape/escape.c: Optimize CGI.escape performance by C ext
      for ASCII-compatible encodings.  [Fix GH-1238]

  Modified files:
    trunk/ChangeLog
    trunk/ext/cgi/escape/escape.c
Index: ChangeLog
===================================================================
--- ChangeLog	(revision 53730)
+++ ChangeLog	(revision 53731)
@@ -1,3 +1,8 @@ https://github.com/ruby/ruby/blob/trunk/ChangeLog#L1
+Thu Feb  4 12:39:08 2016  joker1007  <kakyoin.hierophant@g...>
+
+	* cgi/escape/escape.c: Optimize CGI.escape performance by C ext
+	  for ASCII-compatible encodings.  [Fix GH-1238]
+
 Thu Feb  4 11:53:56 2016  Martin Duerst  <duerst@i...>
 
 	* common.mk: Introduce two variables (UNICODE_DATA_DIR and
Index: ext/cgi/escape/escape.c
===================================================================
--- ext/cgi/escape/escape.c	(revision 53730)
+++ ext/cgi/escape/escape.c	(revision 53731)
@@ -1,6 +1,10 @@ https://github.com/ruby/ruby/blob/trunk/ext/cgi/escape/escape.c#L1
 #include "ruby.h"
 #include "ruby/encoding.h"
 
+RUBY_EXTERN const char ruby_hexdigits[];
+#define lower_hexdigits (ruby_hexdigits+0)
+#define upper_hexdigits (ruby_hexdigits+16)
+
 static VALUE rb_cCGI, rb_mUtil, rb_mEscape;
 
 static void
@@ -73,6 +77,68 @@ optimized_escape_html(VALUE str) https://github.com/ruby/ruby/blob/trunk/ext/cgi/escape/escape.c#L77
     }
 }
 
+static int
+url_unreserved_char(unsigned char c)
+{
+    switch (c) {
+      case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9':
+      case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': case 'g': case 'h': case 'i': case 'j':
+      case 'k': case 'l': case 'm': case 'n': case 'o': case 'p': case 'q': case 'r': case 's': case 't':
+      case 'u': case 'v': case 'w': case 'x': case 'y': case 'z':
+      case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'G': case 'H': case 'I': case 'J':
+      case 'K': case 'L': case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R': case 'S': case 'T':
+      case 'U': case 'V': case 'W': case 'X': case 'Y': case 'Z':
+      case '-': case '.': case '_':
+        return 1;
+      default:
+        break;
+    }
+    return 0;
+}
+
+static VALUE
+optimized_escape(VALUE str)
+{
+    long i, len, modified = 0, beg = 0;
+    VALUE dest;
+    const char *cstr;
+    char buf[4] = {'%'};
+
+    len  = RSTRING_LEN(str);
+    cstr = RSTRING_PTR(str);
+
+    for (i = 0; i < len; i++) {
+	if (!url_unreserved_char(cstr[i])) {
+	    if (!modified) {
+		modified = 1;
+		dest = rb_str_buf_new(len);
+	    }
+
+	    rb_str_cat(dest, cstr + beg, i - beg);
+	    beg = i + 1;
+
+	    if (cstr[i] == ' ') {
+		rb_str_cat_cstr(dest, "+");
+	    }
+	    else {
+		unsigned char c = (unsigned char)cstr[i];
+		buf[1] = upper_hexdigits[c >> 4];
+		buf[2] = upper_hexdigits[c & 0xf];
+		rb_str_cat(dest, buf, 3);
+	    }
+	}
+    }
+
+    if (modified) {
+	rb_str_cat(dest, cstr + beg, len - beg);
+	preserve_original_state(str, dest);
+	return dest;
+    }
+    else {
+	return rb_str_dup(str);
+    }
+}
+
 /*
  *  call-seq:
  *     CGI.escapeHTML(string) -> string
@@ -93,6 +159,26 @@ cgiesc_escape_html(VALUE self, VALUE str https://github.com/ruby/ruby/blob/trunk/ext/cgi/escape/escape.c#L159
     }
 }
 
+/*
+ *  call-seq:
+ *     CGI.escape(string) -> string
+ *
+ *  Returns URL-escaped string.
+ *
+ */
+static VALUE
+cgiesc_escape(VALUE self, VALUE str)
+{
+    StringValue(str);
+
+    if (rb_enc_str_asciicompat_p(str)) {
+	return optimized_escape(str);
+    }
+    else {
+	return rb_call_super(1, &str);
+    }
+}
+
 void
 Init_escape(void)
 {
@@ -100,6 +186,7 @@ Init_escape(void) https://github.com/ruby/ruby/blob/trunk/ext/cgi/escape/escape.c#L186
     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, "escape", cgiesc_escape, 1);
     rb_prepend_module(rb_mUtil, rb_mEscape);
     rb_extend_object(rb_cCGI, rb_mEscape);
 }

--
ML: ruby-changes@q...
Info: http://www.atdot.net/~ko1/quickml/

[前][次][番号順一覧][スレッド一覧]