static void ary_expand_capa(mrb_state *mrb, struct RArray *a, mrb_int len) { mrb_int capa = ARY_CAPA(a); if (len > ARY_MAX_SIZE || len < 0) { size_error: mrb_raise(mrb, E_ARGUMENT_ERROR, "array size too big"); } if (capa < ARY_DEFAULT_LEN) { capa = ARY_DEFAULT_LEN; } while (capa < len) { if (capa <= ARY_MAX_SIZE / 2) { capa *= 2; } else { capa = len; } } if (capa < len || capa > ARY_MAX_SIZE) { goto size_error; } if (ARY_EMBED_P(a)) { mrb_value *ptr = ARY_EMBED_PTR(a); mrb_int len = ARY_EMBED_LEN(a); mrb_value *expanded_ptr = (mrb_value *)mrb_malloc(mrb, sizeof(mrb_value)*capa); ARY_UNSET_EMBED_FLAG(a); array_copy(expanded_ptr, ptr, len); a->as.heap.len = len; a->as.heap.aux.capa = capa; a->as.heap.ptr = expanded_ptr; } else if (capa > a->as.heap.aux.capa) { mrb_value *expanded_ptr = (mrb_value *)mrb_realloc(mrb, a->as.heap.ptr, sizeof(mrb_value)*capa); a->as.heap.aux.capa = capa; a->as.heap.ptr = expanded_ptr; } }
static void ary_replace(mrb_state *mrb, struct RArray *a, struct RArray *b) { mrb_int len = ARY_LEN(b); 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); } else { mrb_free(mrb, a->as.heap.ptr); } 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); mrb_write_barrier(mrb, (struct RBasic*)a); ARY_SET_LEN(a, len); }