summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog8
-rw-r--r--NEWS5
-rw-r--r--string.c26
3 files changed, 28 insertions, 11 deletions
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 <nobu@ruby-lang.org>
+
+ * 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 <naruse@ruby-lang.org>
* 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 {