summaryrefslogtreecommitdiffhomepage
path: root/src/array.c
diff options
context:
space:
mode:
authorYukihiro "Matz" Matsumoto <[email protected]>2018-04-17 13:20:09 +0900
committerYukihiro "Matz" Matsumoto <[email protected]>2018-04-17 17:21:45 +0900
commit0e76faed8cfc55b743b1eac36ea92e772d9f2da6 (patch)
tree77adf127c35dc1af070d2f1ae01f922a4264a4ed /src/array.c
parent5c15aa2f3b7bca49b49384951fc5aba1e36bfd79 (diff)
downloadmruby-0e76faed8cfc55b743b1eac36ea92e772d9f2da6.tar.gz
mruby-0e76faed8cfc55b743b1eac36ea92e772d9f2da6.zip
Make `ary_replace()` to share entry buffers if possible.
Diffstat (limited to 'src/array.c')
-rw-r--r--src/array.c29
1 files changed, 28 insertions, 1 deletions
diff --git a/src/array.c b/src/array.c
index 09de566f8..043cd7325 100644
--- a/src/array.c
+++ b/src/array.c
@@ -349,12 +349,39 @@ mrb_ary_plus(mrb_state *mrb, mrb_value self)
return mrb_obj_value(a2);
}
+#define ARY_REPLACE_SHARED_MIN 20
+
static void
ary_replace(mrb_state *mrb, struct RArray *a, struct RArray *b)
{
mrb_int len = ARY_LEN(b);
- ary_modify(mrb, a);
+ ary_modify_check(mrb, a);
+ if (a == b) return;
+ if (ARY_SHARED_P(a)) {
+ mrb_ary_decref(mrb, a->as.heap.aux.shared);
+ a->as.heap.aux.capa = 0;
+ a->as.heap.len = 0;
+ a->as.heap.ptr = NULL;
+ ARY_UNSET_SHARED_FLAG(a);
+ }
+ if (ARY_SHARED_P(b)) {
+ shared_b:
+ if (ARY_EMBED_P(a)) {
+ ARY_UNSET_EMBED_FLAG(a);
+ }
+ a->as.heap.ptr = b->as.heap.ptr;
+ a->as.heap.len = len;
+ a->as.heap.aux.shared = b->as.heap.aux.shared;
+ a->as.heap.aux.shared->refcnt++;
+ ARY_SET_SHARED_FLAG(a);
+ mrb_write_barrier(mrb, (struct RBasic*)a);
+ return;
+ }
+ if (!MRB_FROZEN_P(b) && len > ARY_REPLACE_SHARED_MIN) {
+ ary_make_shared(mrb, b);
+ goto shared_b;
+ }
if (ARY_CAPA(a) < len)
ary_expand_capa(mrb, a, len);
array_copy(ARY_PTR(a), ARY_PTR(b), len);