Skip to content

Commit a98fa0f

Browse files
committed
array.c : speedup Array#unshift by using space in shared array
- when array owns its shared array (ARY_SHARED_NUM == 1), and there is enough space then try unshift values directly into shared array - when resulting array is big (~>64 items) then make it shared with enough room for future #unshifts, and then insert into shared array
1 parent 88d6ab2 commit a98fa0f

File tree

1 file changed

+55
-9
lines changed

1 file changed

+55
-9
lines changed

array.c

Lines changed: 55 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -970,6 +970,55 @@ rb_ary_shift_m(int argc, VALUE *argv, VALUE ary)
970970
return result;
971971
}
972972

973+
static void
974+
ary_ensure_room_for_unshift(VALUE ary, int argc)
975+
{
976+
long len = RARRAY_LEN(ary);
977+
long new_len = len + argc;
978+
long capa;
979+
VALUE *head, *sharedp;
980+
981+
if (ARY_SHARED_P(ary)) {
982+
VALUE shared = ARY_SHARED(ary);
983+
capa = RARRAY_LEN(shared);
984+
if (ARY_SHARED_NUM(shared) == 1 && capa > new_len) {
985+
head = RARRAY_PTR(ary);
986+
sharedp = RARRAY_PTR(shared);
987+
goto makeroom_if_need;
988+
}
989+
}
990+
991+
rb_ary_modify(ary);
992+
capa = ARY_CAPA(ary);
993+
if (capa - (capa >> 6) <= new_len) {
994+
ary_double_capa(ary, new_len);
995+
}
996+
997+
/* use shared array for big "queues" */
998+
if (new_len > ARY_DEFAULT_SIZE * 4) {
999+
/* make a room for unshifted items */
1000+
capa = ARY_CAPA(ary);
1001+
ary_make_shared(ary);
1002+
1003+
head = sharedp = RARRAY_PTR(ary);
1004+
goto makeroom;
1005+
makeroom_if_need:
1006+
if (head - sharedp < argc) {
1007+
long room;
1008+
makeroom:
1009+
room = capa - new_len;
1010+
room -= room >> 4;
1011+
MEMMOVE(sharedp + argc + room, head, VALUE, len);
1012+
head = sharedp + argc + room;
1013+
}
1014+
ARY_SET_PTR(ary, head - argc);
1015+
}
1016+
else {
1017+
/* sliding items */
1018+
MEMMOVE(RARRAY_PTR(ary) + argc, RARRAY_PTR(ary), VALUE, len);
1019+
}
1020+
}
1021+
9731022
/*
9741023
* call-seq:
9751024
* ary.unshift(obj, ...) -> ary
@@ -985,19 +1034,16 @@ rb_ary_shift_m(int argc, VALUE *argv, VALUE ary)
9851034
static VALUE
9861035
rb_ary_unshift_m(int argc, VALUE *argv, VALUE ary)
9871036
{
988-
long len;
1037+
long len = RARRAY_LEN(ary);
9891038

990-
rb_ary_modify(ary);
991-
if (argc == 0) return ary;
992-
if (ARY_CAPA(ary) <= (len = RARRAY_LEN(ary)) + argc) {
993-
ary_double_capa(ary, len + argc);
1039+
if (argc == 0) {
1040+
rb_ary_modify_check(ary);
1041+
return ary;
9941042
}
9951043

996-
/* sliding items */
997-
MEMMOVE(RARRAY_PTR(ary) + argc, RARRAY_PTR(ary), VALUE, len);
1044+
ary_ensure_room_for_unshift(ary, argc);
9981045
MEMCPY(RARRAY_PTR(ary), argv, VALUE, argc);
999-
ARY_INCREASE_LEN(ary, argc);
1000-
1046+
ARY_SET_LEN(ary, len + argc);
10011047
return ary;
10021048
}
10031049

0 commit comments

Comments
 (0)