string.c: implement `__sub_replace()` in C.
To reduce number of string allocation.
MODIFY
mrblib/string.rb
mrblib/string.rb
@@ -42,32 +42,6 @@ class String
self
end
- # private method for gsub/sub
- def __sub_replace(rep, pre, m, post)
- s = ""
- i = 0
- while j = rep.index("\\", i)
- break if j == rep.length-1
- t = case rep[j+1]
- when "\\"
- "\\"
- when "`"
- pre
- when "&", "0"
- m
- when "'"
- post
- when "1", "2", "3", "4", "5", "6", "7", "8", "9"
- ""
- else
- rep[j, 2]
- end
- s += rep[i, j-i] + t
- i = j + 2
- end
- s + rep[i, rep.length-i]
- end
-
##
# Replace all matches of +pattern+ with +replacement+.
# Call block (if given) for each match and replace
@@ -92,7 +66,7 @@ class String
result << if block
block.call(pattern).to_s
else
- __sub_replace(replace, self[0, found], pattern, self[offset..-1] || "")
+ self.__sub_replace(replace, pattern, found)
end
if plen == 0
result << self[offset, 1]
@@ -145,17 +119,16 @@ class String
block = nil
end
result = []
- this = dup
found = index(pattern)
- return this unless found
- result << this[0, found]
+ return self.dup unless found
+ result << self[0, found]
offset = found + pattern.length
result << if block
block.call(pattern).to_s
else
- __sub_replace(replace, this[0, found], pattern, this[offset..-1] || "")
+ self.__sub_replace(replace, pattern, found)
end
- result << this[offset..-1] if offset < length
+ result << self[offset..-1] if offset < length
result.join
end

MODIFY
src/string.c
src/string.c
@@ -2847,6 +2847,51 @@ mrb_str_byteslice(mrb_state *mrb, mrb_value str)
}
}
+static mrb_value
+sub_replace(mrb_state *mrb, mrb_value self)
+{
+ char *p, *match;
+ mrb_int plen, mlen;
+ mrb_int found, offset;
+ mrb_value result;
+
+ mrb_get_args(mrb, "ssi", &p, &plen, &match, &mlen, &found);
+ result = mrb_str_new(mrb, 0, 0);
+ for (mrb_int i=0; i<plen; i++) {
+ if (p[i] != '\\' || i+1==plen) {
+ mrb_str_cat(mrb, result, p+i, 1);
+ continue;
+ }
+ i++;
+ switch (p[i]) {
+ case '\\':
+ mrb_str_cat(mrb, result, "\\", 1);
+ break;
+ case '`':
+ mrb_str_cat(mrb, result, RSTRING_PTR(self), found);
+ break;
+ case '&': case '0':
+ mrb_str_cat(mrb, result, match, mlen);
+ break;
+ case '\'':
+ offset = found + mlen;
+ if (RSTRING_LEN(self) > offset) {
+ mrb_str_cat(mrb, result, RSTRING_PTR(self)+offset, RSTRING_LEN(self)-offset);
+ }
+ break;
+ case '1': case '2': case '3':
+ case '4': case '5': case '6':
+ case '7': case '8': case '9':
+ /* ignore sub-group match (no Regexp supported) */
+ break;
+ default:
+ mrb_str_cat(mrb, result, &p[i-1], 2);
+ break;
+ }
+ }
+ return result;
+}
+
/* ---------------------------*/
void
mrb_init_string(mrb_state *mrb)
@@ -2908,4 +2953,6 @@ mrb_init_string(mrb_state *mrb)
mrb_define_method(mrb, s, "getbyte", mrb_str_getbyte, MRB_ARGS_REQ(1));
mrb_define_method(mrb, s, "setbyte", mrb_str_setbyte, MRB_ARGS_REQ(2));
mrb_define_method(mrb, s, "byteslice", mrb_str_byteslice, MRB_ARGS_ARG(1,1));
+
+ mrb_define_method(mrb, s, "__sub_replace", sub_replace, MRB_ARGS_REQ(3)); /* internal */
}

string.c: implement `__sub_replace()` in C.

To reduce number of string allocation.