summaryrefslogtreecommitdiff
path: root/string.c
diff options
context:
space:
mode:
authorglass <glass@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2017-10-01 13:44:49 +0000
committerglass <glass@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2017-10-01 13:44:49 +0000
commit8320be1007be68232580e374669f54232657dc73 (patch)
tree47399c3fb76ba2ca3d2f729f3f6452fe63acbf0b /string.c
parent8875e0ca4affbe1c24ed7c13728124e58881061e (diff)
string.c: avoid unnecessary call of str_strlen()
* string.c (rb_strseq_index): refactor and avoid call of str_strlen() when offset == 0. it will improve performance of String#index and #include? * benchmark/bm_string_index.rb: benchmark for this change git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@60086 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
Diffstat (limited to 'string.c')
-rw-r--r--string.c57
1 files changed, 32 insertions, 25 deletions
diff --git a/string.c b/string.c
index 0c782a430f..27d40fbe26 100644
--- a/string.c
+++ b/string.c
@@ -3394,43 +3394,50 @@ str_casecmp_p(VALUE str1, VALUE str2)
static long
rb_strseq_index(VALUE str, VALUE sub, long offset, int in_byte)
{
- const char *s, *sptr, *e;
- long pos, len, slen;
+ const char *str_ptr, *str_ptr_end, *sub_ptr, *search_start;
+ long pos, str_len, sub_len, search_len;
int single_byte = single_byte_optimizable(str);
rb_encoding *enc;
enc = rb_enc_check(str, sub);
if (is_broken_string(sub)) return -1;
- len = (in_byte || single_byte) ? RSTRING_LEN(str) : str_strlen(str, enc); /* rb_enc_check */
- slen = in_byte ? RSTRING_LEN(sub) : str_strlen(sub, enc); /* rb_enc_check */
- if (offset < 0) {
- offset += len;
- if (offset < 0) return -1;
- }
- if (len - offset < slen) return -1;
+ str_ptr = RSTRING_PTR(str);
+ str_ptr_end = RSTRING_END(str);
+ str_len = RSTRING_LEN(str);
+ sub_ptr = RSTRING_PTR(sub);
+ sub_len = RSTRING_LEN(sub);
- s = RSTRING_PTR(str);
- e = RSTRING_END(str);
- if (offset) {
- if (!in_byte) offset = str_offset(s, e, offset, enc, single_byte);
- s += offset;
+ if (str_len < sub_len) return -1;
+
+ if (offset != 0) {
+ long str_len_char, sub_len_char;
+ str_len_char = (in_byte || single_byte) ? str_len : str_strlen(str, enc);
+ sub_len_char = in_byte ? sub_len : str_strlen(sub, enc);
+ if (offset < 0) {
+ offset += str_len_char;
+ if (offset < 0) return -1;
+ }
+ if (str_len_char - offset < sub_len_char) return -1;
+ if (!in_byte) offset = str_offset(str_ptr, str_ptr_end, offset, enc, single_byte);
+ str_ptr += offset;
}
- if (slen == 0) return offset;
+ if (sub_len == 0) return offset;
+
/* need proceed one character at a time */
- sptr = RSTRING_PTR(sub);
- slen = RSTRING_LEN(sub);
- len = RSTRING_LEN(str) - offset;
+
+ search_start = str_ptr;
+ search_len = RSTRING_LEN(str) - offset;
for (;;) {
const char *t;
- pos = rb_memsearch(sptr, slen, s, len, enc);
+ pos = rb_memsearch(sub_ptr, sub_len, search_start, search_len, enc);
if (pos < 0) return pos;
- t = rb_enc_right_char_head(s, s+pos, e, enc);
- if (t == s + pos) break;
- len -= t - s;
- if (len <= 0) return -1;
- offset += t - s;
- s = t;
+ t = rb_enc_right_char_head(search_start, search_start+pos, str_ptr_end, enc);
+ if (t == search_start + pos) break;
+ search_len -= t - search_start;
+ if (search_len <= 0) return -1;
+ offset += t - search_start;
+ search_start = t;
}
return pos + offset;
}