Skip to content

Commit 5274647

Browse files
committed
mruby-string-ext/string.c: new method String#byteslice
1 parent 7b27346 commit 5274647

1 file changed

Lines changed: 81 additions & 0 deletions

File tree

mrbgems/mruby-string-ext/src/string.c

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1278,6 +1278,86 @@ mrb_str_uminus(mrb_state *mrb, mrb_value str)
12781278
return mrb_obj_freeze(mrb, mrb_str_dup(mrb, str));
12791279
}
12801280

1281+
static mrb_value
1282+
str_bytesplice(mrb_state *mrb, mrb_value str, mrb_int idx1, mrb_int len1, mrb_value replace, mrb_int idx2, mrb_int len2)
1283+
{
1284+
struct RString *s = RSTRING(str);
1285+
if (RSTR_LEN(s) <= idx1 || RSTRING_LEN(replace) <= idx2) {
1286+
mrb_raise(mrb, E_INDEX_ERROR, "index out of string");
1287+
}
1288+
if (RSTR_LEN(s) <= idx1+len1) {
1289+
len1 = RSTR_LEN(s) - idx1;
1290+
}
1291+
if (RSTRING_LEN(replace) <= idx2+len2) {
1292+
len2 = RSTRING_LEN(replace) - idx2;
1293+
}
1294+
if (len2 == 0) return replace;
1295+
mrb_str_modify(mrb, s);
1296+
if (len1 >= len2) {
1297+
memmove(RSTR_PTR(s)+idx1, RSTRING_PTR(replace)+idx2, len2);
1298+
if (len1 > len2) {
1299+
memmove(RSTR_PTR(s)+idx1+len2, RSTR_PTR(s)+idx1+len1, RSTR_LEN(s)-(idx1+len1));
1300+
RSTR_SET_LEN(s, RSTR_LEN(s)-(len1-len2));
1301+
}
1302+
}
1303+
else { /* len1 < len2 */
1304+
mrb_int slen = RSTR_LEN(s);
1305+
mrb_str_resize(mrb, str, slen+len2-len1);
1306+
memmove(RSTR_PTR(s)+idx1+len2, RSTR_PTR(s)+idx1+len1, slen-(idx1+len1));
1307+
memmove(RSTR_PTR(s)+idx1, RSTRING_PTR(replace)+idx2, len2);
1308+
}
1309+
return replace;
1310+
}
1311+
1312+
/*
1313+
* call-seq:
1314+
* bytesplice(index, length, str) -> string
1315+
* bytesplice(index, length, str, str_index, str_length) -> string
1316+
* bytesplice(range, str) -> string
1317+
* bytesplice(range, str, str_range) -> string
1318+
*
1319+
* Replaces some or all of the content of +self+ with +str+, and returns +self+.
1320+
* The portion of the string affected is determined using
1321+
* the same criteria as String#byteslice, except that +length+ cannot be omitted.
1322+
* If the replacement string is not the same length as the text it is replacing,
1323+
* the string will be adjusted accordingly.
1324+
*
1325+
* 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.
1326+
*
1327+
* The form that take an Integer will raise an IndexError if the value is out
1328+
* of range; the Range form will raise a RangeError.
1329+
* If the beginning or ending offset does not land on character (codepoint)
1330+
* boundary, an IndexError will be raised.
1331+
*/
1332+
static mrb_value
1333+
mrb_str_bytesplice(mrb_state *mrb, mrb_value str)
1334+
{
1335+
mrb_int idx1, len1, idx2, len2;
1336+
mrb_value range1, range2, replace;
1337+
switch (mrb_get_argc(mrb)) {
1338+
case 3:
1339+
mrb_get_args(mrb, "ooo", &range1, &replace, &range2);
1340+
if (mrb_integer_p(range1)) {
1341+
mrb_get_args(mrb, "iiS", &idx1, &len1, &replace);
1342+
return str_bytesplice(mrb, str, idx1, len1, replace, 0, RSTRING_LEN(replace));
1343+
}
1344+
if (mrb_range_beg_len(mrb, range1, &idx1, &len1, RSTRING_LEN(str), FALSE) != MRB_RANGE_OK) break;
1345+
if (mrb_range_beg_len(mrb, range2, &idx2, &len2, RSTRING_LEN(replace), FALSE) != MRB_RANGE_OK) break;
1346+
return str_bytesplice(mrb, str, idx1, len1, replace, idx2, len2);
1347+
case 5:
1348+
mrb_get_args(mrb, "iiSii", &idx1, &len1, &replace, &idx2, &len2);
1349+
return str_bytesplice(mrb, str, idx1, len1, replace, idx2, len2);
1350+
case 2:
1351+
mrb_get_args(mrb, "oS", &range1, &replace);
1352+
if (mrb_range_beg_len(mrb, range1, &idx1, &len1, RSTRING_LEN(str), FALSE) == MRB_RANGE_OK) {
1353+
return str_bytesplice(mrb, str, idx1, len1, replace, 0, RSTRING_LEN(replace));
1354+
}
1355+
default:
1356+
break;
1357+
}
1358+
mrb_raise(mrb, E_ARGUMENT_ERROR, "wrong number of arumgnts");
1359+
}
1360+
12811361
void
12821362
mrb_mruby_string_ext_gem_init(mrb_state* mrb)
12831363
{
@@ -1315,6 +1395,7 @@ mrb_mruby_string_ext_gem_init(mrb_state* mrb)
13151395
mrb_define_method(mrb, s, "casecmp?", mrb_str_casecmp_p, MRB_ARGS_REQ(1));
13161396
mrb_define_method(mrb, s, "+@", mrb_str_uplus, MRB_ARGS_REQ(1));
13171397
mrb_define_method(mrb, s, "-@", mrb_str_uminus, MRB_ARGS_REQ(1));
1398+
mrb_define_method(mrb, s, "bytesplice", mrb_str_bytesplice, MRB_ARGS_ANY());
13181399

13191400
mrb_define_method(mrb, s, "__lines", mrb_str_lines, MRB_ARGS_NONE());
13201401

0 commit comments

Comments
 (0)