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);
 

Reply via email to