diff --git a/ChangeLog b/ChangeLog index a3b36b27e0..076d638be8 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,11 @@ +Fri Apr 18 21:48:24 2014 Nobuyoshi Nakada + + * string.c (rb_str_new_frozen): consider the shared string at + middle. + + * string.c (rb_str_subseq, rb_str_substr, str_byte_substr): share + middle of a string. + Fri Apr 18 15:40:05 2014 NARUSE, Yui * string.c: use uintptr_t instead of VALUE because they are not ruby diff --git a/NEWS b/NEWS index f1f7e66758..d7e13216a5 100644 --- a/NEWS +++ b/NEWS @@ -107,3 +107,8 @@ with all sufficient information, see the ChangeLog file. Ruby's heaps. * rb_str_cat_cstr() added. This is same as `rb_str_cat2()`. + +* `rb_str_substr()` and `rb_str_subseq()` now share middle of a string, + but not only the end of a string. Therefore, result strings may not + be NULL-terminated, `StringValueCStr()` is needed calling to obtain a + NULL-terminated C string. diff --git a/string.c b/string.c index 6294ea8d1a..aa3eff8cd1 100644 --- a/string.c +++ b/string.c @@ -823,16 +823,17 @@ rb_str_new_frozen(VALUE orig) else { if (FL_TEST(orig, STR_SHARED)) { VALUE shared = RSTRING(orig)->as.heap.aux.shared; - long ofs = RSTRING_LEN(shared) - RSTRING_LEN(orig); + long ofs = RSTRING_PTR(orig) - RSTRING_PTR(shared); + long rest = RSTRING_LEN(shared) - ofs - RSTRING_LEN(orig); assert(OBJ_FROZEN(shared)); - if ((ofs > 0) || + if ((ofs > 0) || (rest > 0) || (klass != RBASIC(shared)->klass) || ((RBASIC(shared)->flags ^ RBASIC(orig)->flags) & FL_TAINT) || ENCODING_GET(shared) != ENCODING_GET(orig)) { str = str_new_shared(klass, shared); RSTRING(str)->as.heap.ptr += ofs; - RSTRING(str)->as.heap.len -= ofs; + RSTRING(str)->as.heap.len -= ofs + rest; } else { return shared; @@ -1789,10 +1790,12 @@ rb_str_subseq(VALUE str, long beg, long len) { VALUE str2; - if (RSTRING_LEN(str) == beg + len && - RSTRING_EMBED_LEN_MAX < len) { - str2 = rb_str_new_shared(rb_str_new_frozen(str)); - rb_str_drop_bytes(str2, beg); + if (RSTRING_EMBED_LEN_MAX < len) { + long olen; + str2 = rb_str_new_shared(rb_str_new_frozen(str)); + RSTRING(str2)->as.heap.ptr += beg; + olen = RSTRING(str2)->as.heap.len; + if (olen > len) RSTRING(str2)->as.heap.len = len; } else { str2 = rb_str_new_with_class(str, RSTRING_PTR(str)+beg, len); @@ -1897,10 +1900,11 @@ rb_str_substr(VALUE str, long beg, long len) char *p = rb_str_subpos(str, beg, &len); if (!p) return Qnil; - if (len > RSTRING_EMBED_LEN_MAX && p + len == RSTRING_END(str)) { + if (len > RSTRING_EMBED_LEN_MAX) { + long ofs = p - RSTRING_PTR(str); str2 = rb_str_new_frozen(str); str2 = str_new_shared(rb_obj_class(str2), str2); - RSTRING(str2)->as.heap.ptr += RSTRING(str2)->as.heap.len - len; + RSTRING(str2)->as.heap.ptr += ofs; RSTRING(str2)->as.heap.len = len; } else { @@ -4409,10 +4413,10 @@ str_byte_substr(VALUE str, long beg, long len) else p = s + beg; - if (len > RSTRING_EMBED_LEN_MAX && beg + len == n) { + if (len > RSTRING_EMBED_LEN_MAX) { str2 = rb_str_new_frozen(str); str2 = str_new_shared(rb_obj_class(str2), str2); - RSTRING(str2)->as.heap.ptr += RSTRING(str2)->as.heap.len - len; + RSTRING(str2)->as.heap.ptr += beg; RSTRING(str2)->as.heap.len = len; } else {