Array#shift operations will lead to unused leading tuple elements.
Left-shift the tuple in cases where we want to reuse that memory
for appended elements.
---
vm/builtin/array.cpp | 21 +++++++++++++--------
vm/builtin/tuple.cpp | 14 ++++++++++++++
vm/builtin/tuple.hpp | 3 +++
3 files changed, 30 insertions(+), 8 deletions(-)
--
--- !ruby/object:MailingList
name: rubinius-dev
view: http://groups.google.com/group/rubinius-dev?hl=en
post: [email protected]
unsubscribe: [email protected]
diff --git a/vm/builtin/array.cpp b/vm/builtin/array.cpp
index 6ee77a7..0f37a77 100644
--- a/vm/builtin/array.cpp
+++ b/vm/builtin/array.cpp
@@ -129,15 +129,20 @@ namespace rubinius {
idx += start_->to_native();
if(idx >= tuple_size) {
- // Uses the same algo as 1.8 to resize the tuple
- size_t new_size = tuple_size / 2;
- if(new_size < 3) {
- new_size = 3;
+ if (oidx < tuple_size) {
+ // There is enough space in the tuple for this element
+ tuple_->lshift_inplace(state, start_);
+ } else {
+ // Uses the same algo as 1.8 to resize the tuple
+ size_t new_size = tuple_size / 2;
+ if(new_size < 3) {
+ new_size = 3;
+ }
+
+ Tuple* nt = Tuple::create(state, new_size+idx);
+ nt->copy_from(state, tuple_, start_, total_, Fixnum::from(0));
+ tuple(state, nt);
}
-
- Tuple* nt = Tuple::create(state, new_size+idx);
- nt->copy_from(state, tuple_, start_, total_, Fixnum::from(0));
- tuple(state, nt);
start(state, Fixnum::from(0));
idx = oidx;
}
diff --git a/vm/builtin/tuple.cpp b/vm/builtin/tuple.cpp
index b8323ed..cad701a 100644
--- a/vm/builtin/tuple.cpp
+++ b/vm/builtin/tuple.cpp
@@ -150,6 +150,20 @@ namespace rubinius {
return Fixnum::from(0);
}
+ Tuple *Tuple::lshift_inplace(STATE, Fixnum *shift) {
+ int size = this->num_fields();
+ const int n = shift->to_native();
+
+ if (n > 0) {
+ int i = 0;
+ int j = i + n;
+ while (j < size) this->field[i++] = this->field[j++];
+ while (i < size) this->field[i++] = Qnil;
+ }
+
+ return this;
+ }
+
Object* Tuple::reverse(STATE, Fixnum* o_start, Fixnum* o_total) {
native_int start = o_start->to_native();
native_int total = o_total->to_native();
diff --git a/vm/builtin/tuple.hpp b/vm/builtin/tuple.hpp
index 226fb6c..7a9d8a5 100644
--- a/vm/builtin/tuple.hpp
+++ b/vm/builtin/tuple.hpp
@@ -49,6 +49,9 @@ namespace rubinius {
// Ruby.primitive :tuple_delete_inplace
Fixnum* delete_inplace(STATE, Fixnum *start, Fixnum *length, Object *obj);
+ // Ruby.primitive :tuple_lshift_inplace
+ Tuple* lshift_inplace(STATE, Fixnum *shift);
+
// Ruby.primitive :tuple_reverse
Object* reverse(STATE, Fixnum* start, Fixnum* total);