diff --git a/mrbgems/mruby-string-ext/src/string.c b/mrbgems/mruby-string-ext/src/string.c index 2da7b7a3e..881409ada 100644 --- a/mrbgems/mruby-string-ext/src/string.c +++ b/mrbgems/mruby-string-ext/src/string.c @@ -1278,86 +1278,6 @@ mrb_str_uminus(mrb_state *mrb, mrb_value str) return mrb_obj_freeze(mrb, mrb_str_dup(mrb, str)); } -static mrb_value -str_bytesplice(mrb_state *mrb, mrb_value str, mrb_int idx1, mrb_int len1, mrb_value replace, mrb_int idx2, mrb_int len2) -{ - struct RString *s = RSTRING(str); - if (RSTR_LEN(s) <= idx1 || RSTRING_LEN(replace) <= idx2) { - mrb_raise(mrb, E_INDEX_ERROR, "index out of string"); - } - if (RSTR_LEN(s) <= idx1+len1) { - len1 = RSTR_LEN(s) - idx1; - } - if (RSTRING_LEN(replace) <= idx2+len2) { - len2 = RSTRING_LEN(replace) - idx2; - } - if (len2 == 0) return replace; - mrb_str_modify(mrb, s); - if (len1 >= len2) { - memmove(RSTR_PTR(s)+idx1, RSTRING_PTR(replace)+idx2, len2); - if (len1 > len2) { - memmove(RSTR_PTR(s)+idx1+len2, RSTR_PTR(s)+idx1+len1, RSTR_LEN(s)-(idx1+len1)); - RSTR_SET_LEN(s, RSTR_LEN(s)-(len1-len2)); - } - } - else { /* len1 < len2 */ - mrb_int slen = RSTR_LEN(s); - mrb_str_resize(mrb, str, slen+len2-len1); - memmove(RSTR_PTR(s)+idx1+len2, RSTR_PTR(s)+idx1+len1, slen-(idx1+len1)); - memmove(RSTR_PTR(s)+idx1, RSTRING_PTR(replace)+idx2, len2); - } - return replace; -} - -/* - * call-seq: - * bytesplice(index, length, str) -> string - * bytesplice(index, length, str, str_index, str_length) -> string - * bytesplice(range, str) -> string - * bytesplice(range, str, str_range) -> string - * - * Replaces some or all of the content of +self+ with +str+, and returns +self+. - * The portion of the string affected is determined using - * the same criteria as String#byteslice, except that +length+ cannot be omitted. - * If the replacement string is not the same length as the text it is replacing, - * the string will be adjusted accordingly. - * - * If +str_index+ and +str_length+, or +str_range+ are given, the content of +self+ is replaced by str.byteslice(str_index, str_length) or str.byteslice(str_range); however the substring of +str+ is not allocated as a new string. - * - * The form that take an Integer will raise an IndexError if the value is out - * of range; the Range form will raise a RangeError. - * If the beginning or ending offset does not land on character (codepoint) - * boundary, an IndexError will be raised. - */ -static mrb_value -mrb_str_bytesplice(mrb_state *mrb, mrb_value str) -{ - mrb_int idx1, len1, idx2, len2; - mrb_value range1, range2, replace; - switch (mrb_get_argc(mrb)) { - case 3: - mrb_get_args(mrb, "ooo", &range1, &replace, &range2); - if (mrb_integer_p(range1)) { - mrb_get_args(mrb, "iiS", &idx1, &len1, &replace); - return str_bytesplice(mrb, str, idx1, len1, replace, 0, RSTRING_LEN(replace)); - } - if (mrb_range_beg_len(mrb, range1, &idx1, &len1, RSTRING_LEN(str), FALSE) != MRB_RANGE_OK) break; - if (mrb_range_beg_len(mrb, range2, &idx2, &len2, RSTRING_LEN(replace), FALSE) != MRB_RANGE_OK) break; - return str_bytesplice(mrb, str, idx1, len1, replace, idx2, len2); - case 5: - mrb_get_args(mrb, "iiSii", &idx1, &len1, &replace, &idx2, &len2); - return str_bytesplice(mrb, str, idx1, len1, replace, idx2, len2); - case 2: - mrb_get_args(mrb, "oS", &range1, &replace); - if (mrb_range_beg_len(mrb, range1, &idx1, &len1, RSTRING_LEN(str), FALSE) == MRB_RANGE_OK) { - return str_bytesplice(mrb, str, idx1, len1, replace, 0, RSTRING_LEN(replace)); - } - default: - break; - } - mrb_raise(mrb, E_ARGUMENT_ERROR, "wrong number of arumgnts"); -} - void mrb_mruby_string_ext_gem_init(mrb_state* mrb) { @@ -1395,7 +1315,6 @@ mrb_mruby_string_ext_gem_init(mrb_state* mrb) mrb_define_method(mrb, s, "casecmp?", mrb_str_casecmp_p, MRB_ARGS_REQ(1)); mrb_define_method(mrb, s, "+@", mrb_str_uplus, MRB_ARGS_REQ(1)); mrb_define_method(mrb, s, "-@", mrb_str_uminus, MRB_ARGS_REQ(1)); - mrb_define_method(mrb, s, "bytesplice", mrb_str_bytesplice, MRB_ARGS_ANY()); mrb_define_method(mrb, s, "__lines", mrb_str_lines, MRB_ARGS_NONE()); diff --git a/mrbgems/mruby-string-ext/test/string.rb b/mrbgems/mruby-string-ext/test/string.rb index 52ee2fcb6..0400a8da5 100644 --- a/mrbgems/mruby-string-ext/test/string.rb +++ b/mrbgems/mruby-string-ext/test/string.rb @@ -726,66 +726,3 @@ assert('String#-@') do a = -(a.freeze) assert_true(a.frozen?) end - -assert('String#bytesplice') do - # range, replace (len1=len2) - a = "0123456789" - assert_equal "ab", a.bytesplice(1..2, "ab") - assert_equal "0ab3456789", a - - # range, replace (len1>len2) - a = "0123456789" - assert_equal "ab", a.bytesplice(1..3, "ab") - assert_equal "0ab456789", a - - # range, replace (len1len2) - a = "0123456789" - assert_equal "ab", a.bytesplice(1, 3, "ab") - assert_equal "0ab456789", a - - # idx, len, replace (len1len2) - a = "0123456789" - assert_equal b, a.bytesplice(1..3, b, 1..2) - assert_equal "0bc456789", a - - # range, replace, range (len1len2) - a = "0123456789" - assert_equal b, a.bytesplice(1, 3, b, 1, 2) - assert_equal "0bc456789", a - - # idx, len, replace, idx, len (len1= len2) { + memmove(RSTR_PTR(s)+idx1, RSTRING_PTR(replace)+idx2, len2); + if (len1 > len2) { + memmove(RSTR_PTR(s)+idx1+len2, RSTR_PTR(s)+idx1+len1, RSTR_LEN(s)-(idx1+len1)); + RSTR_SET_LEN(s, RSTR_LEN(s)-(len1-len2)); + } + } + else { /* len1 < len2 */ + mrb_int slen = RSTR_LEN(s); + mrb_str_resize(mrb, str, slen+len2-len1); + memmove(RSTR_PTR(s)+idx1+len2, RSTR_PTR(s)+idx1+len1, slen-(idx1+len1)); + memmove(RSTR_PTR(s)+idx1, RSTRING_PTR(replace)+idx2, len2); + } + return replace; +} + +/* + * call-seq: + * bytesplice(index, length, str) -> string + * bytesplice(index, length, str, str_index, str_length) -> string + * bytesplice(range, str) -> string + * bytesplice(range, str, str_range) -> string + * + * Replaces some or all of the content of +self+ with +str+, and returns +self+. + * The portion of the string affected is determined using + * the same criteria as String#byteslice, except that +length+ cannot be omitted. + * If the replacement string is not the same length as the text it is replacing, + * the string will be adjusted accordingly. + * + * If +str_index+ and +str_length+, or +str_range+ are given, the content of +self+ is replaced by str.byteslice(str_index, str_length) or str.byteslice(str_range); however the substring of +str+ is not allocated as a new string. + * + * The form that take an Integer will raise an IndexError if the value is out + * of range; the Range form will raise a RangeError. + * If the beginning or ending offset does not land on character (codepoint) + * boundary, an IndexError will be raised. + */ +static mrb_value +mrb_str_bytesplice(mrb_state *mrb, mrb_value str) +{ + mrb_int idx1, len1, idx2, len2; + mrb_value range1, range2, replace; + switch (mrb_get_argc(mrb)) { + case 3: + mrb_get_args(mrb, "ooo", &range1, &replace, &range2); + if (mrb_integer_p(range1)) { + mrb_get_args(mrb, "iiS", &idx1, &len1, &replace); + return str_bytesplice(mrb, str, idx1, len1, replace, 0, RSTRING_LEN(replace)); + } + if (mrb_range_beg_len(mrb, range1, &idx1, &len1, RSTRING_LEN(str), FALSE) != MRB_RANGE_OK) break; + if (mrb_range_beg_len(mrb, range2, &idx2, &len2, RSTRING_LEN(replace), FALSE) != MRB_RANGE_OK) break; + return str_bytesplice(mrb, str, idx1, len1, replace, idx2, len2); + case 5: + mrb_get_args(mrb, "iiSii", &idx1, &len1, &replace, &idx2, &len2); + return str_bytesplice(mrb, str, idx1, len1, replace, idx2, len2); + case 2: + mrb_get_args(mrb, "oS", &range1, &replace); + if (mrb_range_beg_len(mrb, range1, &idx1, &len1, RSTRING_LEN(str), FALSE) == MRB_RANGE_OK) { + return str_bytesplice(mrb, str, idx1, len1, replace, 0, RSTRING_LEN(replace)); + } + default: + break; + } + mrb_raise(mrb, E_ARGUMENT_ERROR, "wrong number of arumgnts"); +} + /* ---------------------------*/ void mrb_init_string(mrb_state *mrb) @@ -3008,6 +3089,7 @@ mrb_init_string(mrb_state *mrb) mrb_define_method(mrb, s, "byteindex", mrb_str_byteindex_m, MRB_ARGS_ARG(1,1)); mrb_define_method(mrb, s, "byterindex", mrb_str_byterindex_m, MRB_ARGS_ARG(1,1)); mrb_define_method(mrb, s, "byteslice", mrb_str_byteslice, MRB_ARGS_ARG(1,1)); + mrb_define_method(mrb, s, "bytesplice", mrb_str_bytesplice, MRB_ARGS_ANY()); mrb_define_method(mrb, s, "__sub_replace", sub_replace, MRB_ARGS_REQ(3)); /* internal */ } diff --git a/test/t/string.rb b/test/t/string.rb index 11b5cae0f..892899346 100644 --- a/test/t/string.rb +++ b/test/t/string.rb @@ -898,3 +898,66 @@ assert('String#byteslice') do assert_equal("o", str1.byteslice(4.0)) assert_equal("\x82ab", str2.byteslice(2.0, 3.0)) end + +assert('String#bytesplice') do + # range, replace (len1=len2) + a = "0123456789" + assert_equal "ab", a.bytesplice(1..2, "ab") + assert_equal "0ab3456789", a + + # range, replace (len1>len2) + a = "0123456789" + assert_equal "ab", a.bytesplice(1..3, "ab") + assert_equal "0ab456789", a + + # range, replace (len1len2) + a = "0123456789" + assert_equal "ab", a.bytesplice(1, 3, "ab") + assert_equal "0ab456789", a + + # idx, len, replace (len1len2) + a = "0123456789" + assert_equal b, a.bytesplice(1..3, b, 1..2) + assert_equal "0bc456789", a + + # range, replace, range (len1len2) + a = "0123456789" + assert_equal b, a.bytesplice(1, 3, b, 1, 2) + assert_equal "0bc456789", a + + # idx, len, replace, idx, len (len1