Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: rubinius/rubinius
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: 2642a30c5797
Choose a base ref
...
head repository: rubinius/rubinius
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: 88545672f086
Choose a head ref
  • 2 commits
  • 2 files changed
  • 1 contributor

Commits on May 14, 2015

  1. Copy the full SHA
    7a13ef4 View commit details
  2. Fixed Array::concat, again.

    brixen committed May 14, 2015
    Copy the full SHA
    8854567 View commit details
Showing with 31 additions and 12 deletions.
  1. +13 −0 spec/ruby/core/array/concat_spec.rb
  2. +18 −12 vm/builtin/array.cpp
13 changes: 13 additions & 0 deletions spec/ruby/core/array/concat_spec.rb
Original file line number Diff line number Diff line change
@@ -96,4 +96,17 @@
ary[2].untrusted?.should be_true
ary[3].untrusted?.should be_false
end

it "appends elements to an Array with enough capacity that has been shifted" do
ary = 1, 2, 3, 4, 5
2.times { ary.shift }
2.times { ary.pop }
ary.concat([5, 6]).should == [3, 5, 6]
end

it "appends elements to an Array without enough capacity that has been shifted" do
ary = 1, 2, 3, 4
3.times { ary.shift }
ary.concat([5, 6]).should == [4, 5, 6]
end
end
30 changes: 18 additions & 12 deletions vm/builtin/array.cpp
Original file line number Diff line number Diff line change
@@ -180,38 +180,44 @@ namespace rubinius {
Array* Array::concat(STATE, Array* other) {
if(is_frozen_p()) return force_as<Array>(Primitives::failure());

native_int size = this->size();
native_int osize = other->size();

if(osize == 0) return this;

if(osize == 1) {
set(state, size(), other->get(state, 0));
set(state, size, other->get(state, 0));
return this;
}

native_int new_size = size() + osize;
native_int new_size = size + osize;
if(new_size <= tuple_->num_fields()) {
// There is enough space in the current tuple, so just copy into it.
tuple_->copy_from(state, other->tuple(), other->start(), other->total(), total_);
// We have enough space, but may need to shift elements.
if(start_->to_native() + new_size <= tuple_->num_fields()) {
tuple_->copy_from(state, other->tuple(), other->start(), other->total(),
Fixnum::from(start_->to_native() + total_->to_native()));
} else {
tuple_->copy_from(state, tuple_, start_, total_, Fixnum::from(0));
tuple_->copy_from(state, other->tuple(), other->start(), other->total(), total_);
start(state, Fixnum::from(0));
}
} else {
native_int s = size();

if(s == 0) s = 2;
while(s <= new_size) s *= 2;

// We need to create a bigger tuple, then copy both tuples into it.
Tuple* nt = Tuple::create_dirty(state, s);
if(size == 0) size = 2;
while(size <= new_size) size *= 2;

Tuple* nt = Tuple::create_dirty(state, size);
nt->copy_from(state, tuple_, start_, total_, Fixnum::from(0));
nt->copy_from(state, other->tuple(), other->start(), other->total(), total_);

for(native_int i = new_size; i < s; i++) {
for(native_int i = new_size; i < size; i++) {
nt->put_nil(i);
}

tuple(state, nt);
start(state, Fixnum::from(0));
}

start(state, Fixnum::from(0));
total(state, Fixnum::from(new_size));

return this;