@@ -2945,6 +2945,87 @@ sub_replace(mrb_state *mrb, mrb_value self)
29452945return result;
29462946}
294729472948+2949+static mrb_value
2950+str_bytesplice(mrb_state *mrb, mrb_value str, mrb_int idx1, mrb_int len1, mrb_value replace, mrb_int idx2, mrb_int len2)
2951+{
2952+struct RString *s = RSTRING(str);
2953+if (RSTR_LEN(s) <= idx1 || RSTRING_LEN(replace) <= idx2) {
2954+mrb_raise(mrb, E_INDEX_ERROR, "index out of string");
2955+ }
2956+if (RSTR_LEN(s) <= idx1+len1) {
2957+len1 = RSTR_LEN(s) - idx1;
2958+ }
2959+if (RSTRING_LEN(replace) <= idx2+len2) {
2960+len2 = RSTRING_LEN(replace) - idx2;
2961+ }
2962+if (len2 == 0) return replace;
2963+mrb_str_modify(mrb, s);
2964+if (len1 >= len2) {
2965+memmove(RSTR_PTR(s)+idx1, RSTRING_PTR(replace)+idx2, len2);
2966+if (len1 > len2) {
2967+memmove(RSTR_PTR(s)+idx1+len2, RSTR_PTR(s)+idx1+len1, RSTR_LEN(s)-(idx1+len1));
2968+RSTR_SET_LEN(s, RSTR_LEN(s)-(len1-len2));
2969+ }
2970+ }
2971+else { /* len1 < len2 */
2972+mrb_int slen = RSTR_LEN(s);
2973+mrb_str_resize(mrb, str, slen+len2-len1);
2974+memmove(RSTR_PTR(s)+idx1+len2, RSTR_PTR(s)+idx1+len1, slen-(idx1+len1));
2975+memmove(RSTR_PTR(s)+idx1, RSTRING_PTR(replace)+idx2, len2);
2976+ }
2977+return replace;
2978+}
2979+2980+/*
2981+ * call-seq:
2982+ * bytesplice(index, length, str) -> string
2983+ * bytesplice(index, length, str, str_index, str_length) -> string
2984+ * bytesplice(range, str) -> string
2985+ * bytesplice(range, str, str_range) -> string
2986+ *
2987+ * Replaces some or all of the content of +self+ with +str+, and returns +self+.
2988+ * The portion of the string affected is determined using
2989+ * the same criteria as String#byteslice, except that +length+ cannot be omitted.
2990+ * If the replacement string is not the same length as the text it is replacing,
2991+ * the string will be adjusted accordingly.
2992+ *
2993+ * 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.
2994+ *
2995+ * The form that take an Integer will raise an IndexError if the value is out
2996+ * of range; the Range form will raise a RangeError.
2997+ * If the beginning or ending offset does not land on character (codepoint)
2998+ * boundary, an IndexError will be raised.
2999+ */
3000+static mrb_value
3001+mrb_str_bytesplice(mrb_state *mrb, mrb_value str)
3002+{
3003+mrb_int idx1, len1, idx2, len2;
3004+mrb_value range1, range2, replace;
3005+switch (mrb_get_argc(mrb)) {
3006+case 3:
3007+mrb_get_args(mrb, "ooo", &range1, &replace, &range2);
3008+if (mrb_integer_p(range1)) {
3009+mrb_get_args(mrb, "iiS", &idx1, &len1, &replace);
3010+return str_bytesplice(mrb, str, idx1, len1, replace, 0, RSTRING_LEN(replace));
3011+ }
3012+if (mrb_range_beg_len(mrb, range1, &idx1, &len1, RSTRING_LEN(str), FALSE) != MRB_RANGE_OK) break;
3013+if (mrb_range_beg_len(mrb, range2, &idx2, &len2, RSTRING_LEN(replace), FALSE) != MRB_RANGE_OK) break;
3014+return str_bytesplice(mrb, str, idx1, len1, replace, idx2, len2);
3015+case 5:
3016+mrb_get_args(mrb, "iiSii", &idx1, &len1, &replace, &idx2, &len2);
3017+return str_bytesplice(mrb, str, idx1, len1, replace, idx2, len2);
3018+case 2:
3019+mrb_get_args(mrb, "oS", &range1, &replace);
3020+if (mrb_range_beg_len(mrb, range1, &idx1, &len1, RSTRING_LEN(str), FALSE) == MRB_RANGE_OK) {
3021+return str_bytesplice(mrb, str, idx1, len1, replace, 0, RSTRING_LEN(replace));
3022+ }
3023+default:
3024+break;
3025+ }
3026+mrb_raise(mrb, E_ARGUMENT_ERROR, "wrong number of arumgnts");
3027+}
3028+29483029/* ---------------------------*/
29493030void
29503031mrb_init_string(mrb_state *mrb)
@@ -3008,6 +3089,7 @@ mrb_init_string(mrb_state *mrb)
30083089mrb_define_method(mrb, s, "byteindex", mrb_str_byteindex_m, MRB_ARGS_ARG(1,1));
30093090mrb_define_method(mrb, s, "byterindex", mrb_str_byterindex_m, MRB_ARGS_ARG(1,1));
30103091mrb_define_method(mrb, s, "byteslice", mrb_str_byteslice, MRB_ARGS_ARG(1,1));
3092+mrb_define_method(mrb, s, "bytesplice", mrb_str_bytesplice, MRB_ARGS_ANY());
3011309330123094mrb_define_method(mrb, s, "__sub_replace", sub_replace, MRB_ARGS_REQ(3)); /* internal */
30133095}