summaryrefslogtreecommitdiffhomepage
path: root/src/string.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/string.c')
-rw-r--r--src/string.c45
1 files changed, 31 insertions, 14 deletions
diff --git a/src/string.c b/src/string.c
index 6eba9cb20..2d5c67655 100644
--- a/src/string.c
+++ b/src/string.c
@@ -261,11 +261,8 @@ mrb_str_new_cstr(mrb_state *mrb, const char *p)
}
static void
-str_make_shared(mrb_state *mrb, mrb_value str)
+str_make_shared(mrb_state *mrb, struct RString *s)
{
- struct RString *s;
-
- s = mrb_str_ptr(str);
if (!(s->flags & MRB_STR_SHARED)) {
struct mrb_shared_string *shared = mrb_malloc(mrb, sizeof(struct mrb_shared_string));
@@ -298,7 +295,7 @@ mrb_str_literal(mrb_state *mrb, mrb_value str)
s = str_new(mrb, 0, 0);
orig = mrb_str_ptr(str);
if (!(orig->flags & MRB_STR_SHARED)) {
- str_make_shared(mrb, str);
+ str_make_shared(mrb, mrb_str_ptr(str));
}
shared = orig->aux.shared;
shared->refcnt++;
@@ -1199,8 +1196,9 @@ mrb_str_subseq(mrb_state *mrb, mrb_value str, int beg, int len)
struct RString *s;
struct mrb_shared_string *shared;
- str_make_shared(mrb, str);
- shared = RSTRING(str)->aux.shared;
+ s = mrb_str_ptr(str);
+ str_make_shared(mrb, s);
+ shared = s->aux.shared;
s = mrb_obj_alloc_string(mrb);
s->buf = shared->buf + beg;
s->len = len;
@@ -1541,16 +1539,35 @@ mrb_str_index_m(mrb_state *mrb, mrb_value str)
return mrb_fixnum_value(pos);
}
+#define STR_REPLACE_SHARED_MIN 10
+
static mrb_value
str_replace(mrb_state *mrb, struct RString *s1, struct RString *s2)
{
- int len = s2->len;
-
- str_modify(mrb, s1);
- s1->buf = mrb_realloc(mrb, s1->buf, len);
- memcpy(s1->buf, s2->buf, len);
- s1->len = s2->len;
- s2->aux.capa = s2->len;
+ if (s2->flags & MRB_STR_SHARED) {
+ L_SHARE:
+ s1->buf = s2->buf;
+ s1->len = s2->len;
+ s1->aux.shared = s2->aux.shared;
+ s1->flags |= MRB_STR_SHARED;
+ }
+ else if (s2->len > STR_REPLACE_SHARED_MIN) {
+ str_make_shared(mrb, s2);
+ goto L_SHARE;
+ }
+ else {
+ if (s1->flags & MRB_STR_SHARED) {
+ mrb_str_decref(mrb, s1->aux.shared);
+ s1->buf = mrb_malloc(mrb, s2->len+1);
+ }
+ else {
+ s1->buf = mrb_realloc(mrb, s1->buf, s2->len+1);
+ }
+ memcpy(s1->buf, s2->buf, s2->len);
+ s1->buf[s2->len] = 0;
+ s1->len = s2->len;
+ s2->aux.capa = s2->len;
+ }
return mrb_obj_value(s1);
}