From: Nobuyoshi Nakada Date: 2008-01-22T23:38:18+09:00 Subject: [ruby-dev:33277] Re: [ruby-cvs:22386] Ruby:r15149 (trunk): * string.c (rb_str_each_char): move forward. なかだです。 At Mon, 21 Jan 2008 21:08:36 +0900, Yukihiro Matsumoto wrote in [ruby-dev:33255]: > ||freezeしたコピーを作っておいて、変更の影響を受けないようにすると > ||いうのを思い付きました。当然のことながら格段に速くなるようです。 > | > |んじゃ、この線でコミットしてください。 > > 他のyieldを呼ぶメソッド(each_lineとかgsubとか)もコピーを作っ > た方がよいでしょうか。 こんなとこでしょうか。 Index: string.c =================================================================== --- string.c (revision 15173) +++ string.c (working copy) @@ -229,5 +229,5 @@ int rb_enc_str_asciionly_p(VALUE str) static inline void -str_mod_check(VALUE s, char *p, long len) +str_mod_check(VALUE s, const char *p, long len) { if (RSTRING_PTR(s) != p || RSTRING_LEN(s) != len){ @@ -416,4 +416,6 @@ rb_str_new4(VALUE orig) } +#define rb_str_shadow(p) (*(volatile VALUE *)(p) = rb_str_new4(*(p))) + VALUE rb_str_new5(VALUE obj, const char *ptr, long len) @@ -4463,10 +4465,8 @@ rb_str_each_line(int argc, VALUE *argv, { rb_encoding *enc; - VALUE rs; + VALUE self = str, rs, line; int newline; - char *p = RSTRING_PTR(str), *pend = p + RSTRING_LEN(str), *s = p; - char *ptr = p; - long len = RSTRING_LEN(str), rslen; - VALUE line; + const char *p, *pend, *s, *ptr, *rsptr; + long len, rslen; int n; @@ -4480,7 +4480,13 @@ rb_str_each_line(int argc, VALUE *argv, return str; } - StringValue(rs); + + rb_str_shadow(&str); enc = rb_enc_check(str, rs); - if (rs == rb_default_rs) { + ptr = s = p = RSTRING_PTR(str); + len = RSTRING_LEN(str); + pend = p + len; + + StringValue(rs); + if (rs == rb_default_rs || rb_str_shadow(&rs) == rb_default_rs) { while (p < pend) { n = rb_enc_mbclen(p, pend, enc); @@ -4490,5 +4496,4 @@ rb_str_each_line(int argc, VALUE *argv, rb_enc_copy(line, str); rb_yield(line); - str_mod_check(str, ptr, len); s = p + n; } @@ -4498,4 +4503,5 @@ rb_str_each_line(int argc, VALUE *argv, } + rsptr = RSTRING_PTR(rs); rslen = RSTRING_LEN(rs); if (rslen == 0) { @@ -4503,5 +4509,5 @@ rb_str_each_line(int argc, VALUE *argv, } else { - newline = rb_enc_codepoint(RSTRING_PTR(rs), RSTRING_END(rs), enc); + newline = rb_enc_codepoint(rsptr, rsptr+rslen, enc); } @@ -4517,10 +4523,9 @@ rb_str_each_line(int argc, VALUE *argv, } if (c == newline && - (rslen <= 1 || memcmp(RSTRING_PTR(rs), p, rslen) == 0)) { + (rslen <= 1 || memcmp(rsptr, p, rslen) == 0)) { line = rb_str_new5(str, s, p - s + (rslen ? rslen : n)); OBJ_INFECT(line, str); rb_enc_copy(line, str); rb_yield(line); - str_mod_check(str, ptr, len); s = p + (rslen ? rslen : n); } @@ -4537,5 +4542,5 @@ rb_str_each_line(int argc, VALUE *argv, } - return str; + return self; } @@ -4570,11 +4575,16 @@ static VALUE rb_str_each_byte(VALUE str) { - long i; + VALUE self = str; + const char *ptr; + long i, len; RETURN_ENUMERATOR(str, 0, 0); - for (i=0; i