Skip to content

Commit

Permalink
Refactor Indexable::Mutable#fill's overloads (#11368)
Browse files Browse the repository at this point in the history
  • Loading branch information
HertzDevil committed Nov 10, 2021
1 parent 71bdd14 commit 207bdc6
Show file tree
Hide file tree
Showing 8 changed files with 396 additions and 290 deletions.
195 changes: 28 additions & 167 deletions spec/std/array_spec.cr
Original file line number Diff line number Diff line change
Expand Up @@ -698,173 +698,34 @@ describe "Array" do
end

describe "#fill" do
it "replaces all values" do
a = ['a', 'b', 'c']
expected = ['x', 'x', 'x']
a.fill('x').should be(a)
a.should eq(expected)

a = [1, 2, 3]
expected = [0, 0, 0]
a.fill(0).should be(a)
a.should eq(expected)

a = [1.0, 2.0, 3.0]
expected = [0.0, 0.0, 0.0]
a.fill(0.0).should be(a)
a.should eq(expected)
end

it "replaces only values between index and size" do
a = ['a', 'b', 'c']
expected = ['x', 'x', 'c']
a.fill('x', 0, 2).should be(a)
a.should eq(expected)

a = [1, 2, 3]
expected = [0, 0, 3]
a.fill(0, 0, 2).should be(a)
a.should eq(expected)

a = [1.0, 2.0, 3.0]
expected = [0, 0, 3]
a.fill(0, 0, 2).should be(a)
a.should eq(expected)
end

it "replaces only values between index and size (2)" do
a = ['a', 'b', 'c']
expected = ['a', 'x', 'x']
a.fill('x', 1, 2).should be(a)
a.should eq(expected)

a = [1, 2, 3]
expected = [1, 0, 0]
a.fill(0, 1, 2).should be(a)
a.should eq(expected)

a = [1.0, 2.0, 3.0]
expected = [1, 0, 0]
a.fill(0, 1, 2).should be(a)
a.should eq(expected)
end

it "replaces all values from index onwards" do
a = ['a', 'b', 'c']
expected = ['a', 'x', 'x']
a.fill('x', -2).should be(a)
a.should eq(expected)

a = [1, 2, 3]
expected = [1, 0, 0]
a.fill(0, -2).should be(a)
a.should eq(expected)

a = [1.0, 2.0, 3.0]
expected = [1, 0, 0]
a.fill(0, -2).should be(a)
a.should eq(expected)
end

it "raises when given big negative number (#4539)" do
expect_raises(IndexError) do
['a', 'b', 'c'].fill('x', -4)
end
expect_raises(IndexError) do
[1, 2, 3].fill(0, -4)
end
expect_raises(IndexError) do
[1.0, 2.0, 3.0].fill(0, -4)
end
end

it "replaces only values between negative index and size" do
a = ['a', 'b', 'c']
expected = ['a', 'b', 'x']
a.fill('x', -1, 1).should be(a)
a.should eq(expected)

a = [1, 2, 3]
expected = [1, 2, 0]
a.fill(0, -1, 1).should be(a)
a.should eq(expected)

a = [1.0, 2.0, 3.0]
expected = [1, 2, 0]
a.fill(0, -1, 1).should be(a)
a.should eq(expected)
end

it "raises when given big negative number in from/count (#4539)" do
expect_raises(IndexError) do
['a', 'b', 'c'].fill('x', -4, 1)
end
expect_raises(IndexError) do
[1, 2, 3].fill(0, -4, 1)
end
expect_raises(IndexError) do
[1.0, 2.0, 3.0].fill(0, -4, 1)
end
end

it "replaces only values in range" do
a = ['a', 'b', 'c']
expected = ['x', 'x', 'c']
a.fill('x', -3..1).should be(a)
a.should eq(expected)

a = [1, 2, 3]
expected = [0, 0, 3]
a.fill(0, -3..1).should be(a)
a.should eq(expected)

a = [1.0, 2.0, 3.0]
expected = [0, 0, 3]
a.fill(0, -3..1).should be(a)
a.should eq(expected)
end

it "replaces only values in range without end" do
a = ['a', 'b', 'c']
expected = ['a', 'x', 'x']
a.fill('x', 1..nil).should be(a)
a.should eq(expected)

a = [1, 2, 3]
expected = [1, 0, 0]
a.fill(0, 1..nil).should be(a)
a.should eq(expected)

a = [1.0, 2.0, 3.0]
expected = [1, 0, 0]
a.fill(0, 1..nil).should be(a)
a.should eq(expected)
end

it "replaces only values in range begin" do
a = ['a', 'b', 'c']
expected = ['x', 'x', 'c']
a.fill('x', nil..1).should be(a)
a.should eq(expected)

a = [1, 2, 3]
expected = [0, 0, 3]
a.fill(0, nil..1).should be(a)
a.should eq(expected)

a = [1.0, 2.0, 3.0]
expected = [0, 0, 3]
a.fill(0, nil..1).should be(a)
a.should eq(expected)
end

it "works with a block" do
a = [3, 6, 9]
a.clone.fill { 0 }.should eq([0, 0, 0])
a.clone.fill { |i| i }.should eq([0, 1, 2])
a.clone.fill(1) { |i| i ** i }.should eq([3, 1, 4])
a.clone.fill(1, 1) { |i| i ** i }.should eq([3, 1, 9])
a.clone.fill(1..1) { |i| i ** i }.should eq([3, 1, 9])
it "replaces values in a subrange" do
a = [0, 1, 2, 3, 4]
a.fill(7).should be(a)
a.should eq([7, 7, 7, 7, 7])

a = [0, 1, 2, 3, 4]
a.fill(7, 1, 2).should be(a)
a.should eq([0, 7, 7, 3, 4])

a = [0, 1, 2, 3, 4]
a.fill(7, 2..3).should be(a)
a.should eq([0, 1, 7, 7, 4])

a = [0, 0, 0, 0, 0]
a.fill { |i| i + 7 }.should be(a)
a.should eq([7, 8, 9, 10, 11])

a = [0, 0, 0, 0, 0]
a.fill(offset: 2) { |i| i * i }.should be(a)
a.should eq([4, 9, 16, 25, 36])

a = [0, 0, 0, 0, 0]
a.fill(1, 2) { |i| i + 7 }.should be(a)
a.should eq([0, 8, 9, 0, 0])

a = [0, 0, 0, 0, 0]
a.fill(2..3) { |i| i + 7 }.should be(a)
a.should eq([0, 0, 9, 10, 0])
end
end

Expand Down
156 changes: 148 additions & 8 deletions spec/std/indexable/mutable_spec.cr
Original file line number Diff line number Diff line change
Expand Up @@ -161,41 +161,181 @@ describe Indexable::Mutable do
context "without block" do
it "sets all elements to the same value" do
coll = SafeIndexableMutable.new(5)
coll.fill(4)
coll.fill(4).should be(coll)
coll.to_a.should eq([4, 4, 4, 4, 4])

coll = SafeIndexableMutableFoo.new(5)
foo = Foo.new
coll.fill(foo)
coll.fill(foo).should be(coll)
coll.to_a.should eq([foo, foo, foo, foo, foo])
end
end

context "without block, with start + count" do
it "sets a subrange of elements to the same value" do
coll = SafeIndexableMutable.new(5)
coll.fill(7, 2, 2).should be(coll)
coll.to_a.should eq([0, 1, 7, 7, 4])

coll = SafeIndexableMutableFoo.new(5)
foos = coll.to_a
foo = Foo.new
coll.fill(foo, -4, 2).should be(coll)
coll.to_a.should eq([foos[0], foo, foo, foos[3], foos[4]])
end

it "sets zero elements" do
coll = SafeIndexableMutable.new(5)
coll.fill(7, 1, 0).to_a.should eq([0, 1, 2, 3, 4])
coll.fill(7, 5, 0).to_a.should eq([0, 1, 2, 3, 4])
coll.fill(7, -3, 0).to_a.should eq([0, 1, 2, 3, 4])
coll.fill(7, -5, 0).to_a.should eq([0, 1, 2, 3, 4])
coll.fill(7, 4, -1).to_a.should eq([0, 1, 2, 3, 4])

coll = SafeIndexableMutableFoo.new(5)
foo = Foo.new
coll.fill(foo, 1, 0).includes?(foo).should be_false
coll.fill(foo, 5, 0).includes?(foo).should be_false
coll.fill(foo, -3, 0).includes?(foo).should be_false
coll.fill(foo, -5, 0).includes?(foo).should be_false
coll.fill(foo, 4, -1).includes?(foo).should be_false
end

it "raises on out of bound start index" do
expect_raises(IndexError) { SafeIndexableMutable.new(5).fill(7, 6, 1) }
expect_raises(IndexError) { SafeIndexableMutable.new(5).fill(7, -6, 1) }
end
end

context "without block, with range" do
it "sets a subrange of elements to the same value" do
coll = SafeIndexableMutable.new(5)
coll.fill(7, 2..3).should be(coll)
coll.to_a.should eq([0, 1, 7, 7, 4])

coll = SafeIndexableMutableFoo.new(5)
foos = coll.to_a
foo = Foo.new
coll.fill(foo, -4...-2).should be(coll)
coll.to_a.should eq([foos[0], foo, foo, foos[3], foos[4]])
end

it "sets zero elements" do
coll = SafeIndexableMutable.new(5)
coll.fill(7, 1..0).to_a.should eq([0, 1, 2, 3, 4])
coll.fill(7, 5...5).to_a.should eq([0, 1, 2, 3, 4])
coll.fill(7, -3...1).to_a.should eq([0, 1, 2, 3, 4])
coll.fill(7, -5..-6).to_a.should eq([0, 1, 2, 3, 4])

coll = SafeIndexableMutableFoo.new(5)
foo = Foo.new
coll.fill(foo, 1..0).includes?(foo).should be_false
coll.fill(foo, 5...5).includes?(foo).should be_false
coll.fill(foo, -3...1).includes?(foo).should be_false
coll.fill(foo, -5..-6).includes?(foo).should be_false
end

it "raises on out of bound start index" do
expect_raises(IndexError) { SafeIndexableMutable.new(5).fill(7, 6..7) }
expect_raises(IndexError) { SafeIndexableMutable.new(5).fill(7, -6..-1) }
end
end

context "with block" do
it "yields index to the block and sets all elements" do
coll = SafeIndexableMutable.new(5)
coll.fill { |i| i * i }
coll = SafeIndexableMutable.new(5, offset: 10)
coll.fill { |i| i * i }.should be(coll)
coll.to_a.should eq([0, 1, 4, 9, 16])

coll = SafeIndexableMutableFoo.new(5)
foo = Foo.new
coll.fill { foo }
coll.fill { foo }.should be(coll)
coll.to_a.should eq([foo, foo, foo, foo, foo])
end
end

context "with block + offset" do
it "yields index plus offset to the block and sets all elements" do
coll = SafeIndexableMutable.new(5)
coll.fill(offset: 7) { |i| i * i }
coll = SafeIndexableMutable.new(5, offset: 10)
coll.fill(offset: 7) { |i| i * i }.should be(coll)
coll.to_a.should eq([49, 64, 81, 100, 121])

coll = SafeIndexableMutableFoo.new(5)
foos = coll.to_a
coll.fill(offset: -2) { |i| foos[i] }
coll.fill(offset: -2) { |i| foos[i] }.should be(coll)
coll.to_a.should eq([foos[-2], foos[-1], foos[0], foos[1], foos[2]])
end
end

context "with block + start + count" do
it "yields index to the block and sets elements in a subrange" do
coll = SafeIndexableMutable.new(5, offset: 10)
coll.fill(2, 2) { |i| i + 7 }.should be(coll)
coll.to_a.should eq([10, 11, 9, 10, 14])

coll = SafeIndexableMutableFoo.new(5)
foos = coll.to_a
foo = Foo.new
coll.fill(-4, 2) { foo }.should be(coll)
coll.to_a.should eq([foos[0], foo, foo, foos[3], foos[4]])
end

it "sets zero elements" do
coll = SafeIndexableMutable.new(5, offset: 10)
coll.fill(1, 0) { |i| i + 7 }.to_a.should eq([10, 11, 12, 13, 14])
coll.fill(5, 0) { |i| i + 7 }.to_a.should eq([10, 11, 12, 13, 14])
coll.fill(-3, 0) { |i| i + 7 }.to_a.should eq([10, 11, 12, 13, 14])
coll.fill(-5, 0) { |i| i + 7 }.to_a.should eq([10, 11, 12, 13, 14])
coll.fill(4, -1) { |i| i + 7 }.to_a.should eq([10, 11, 12, 13, 14])

coll = SafeIndexableMutableFoo.new(5)
foo = Foo.new
coll.fill(1, 0) { foo }.includes?(foo).should be_false
coll.fill(5, 0) { foo }.includes?(foo).should be_false
coll.fill(-3, 0) { foo }.includes?(foo).should be_false
coll.fill(-5, 0) { foo }.includes?(foo).should be_false
coll.fill(4, -1) { foo }.includes?(foo).should be_false
end

it "raises on out of bound start index" do
expect_raises(IndexError) { SafeIndexableMutable.new(5).fill(6, 1, &.itself) }
expect_raises(IndexError) { SafeIndexableMutable.new(5).fill(-6, 1, &.itself) }
end
end

context "with block + range" do
it "yields index to the block and sets elements in a subrange" do
coll = SafeIndexableMutable.new(5, offset: 10)
coll.fill(2..3) { |i| i + 7 }.should be(coll)
coll.to_a.should eq([10, 11, 9, 10, 14])

coll = SafeIndexableMutableFoo.new(5)
foos = coll.to_a
foo = Foo.new
coll.fill(-4...-2) { foo }.should be(coll)
coll.to_a.should eq([foos[0], foo, foo, foos[3], foos[4]])
end

it "sets zero elements" do
coll = SafeIndexableMutable.new(5, offset: 10)
coll.fill(1..0) { |i| i + 7 }.to_a.should eq([10, 11, 12, 13, 14])
coll.fill(5...5) { |i| i + 7 }.to_a.should eq([10, 11, 12, 13, 14])
coll.fill(-3...1) { |i| i + 7 }.to_a.should eq([10, 11, 12, 13, 14])
coll.fill(-5..-6) { |i| i + 7 }.to_a.should eq([10, 11, 12, 13, 14])

coll = SafeIndexableMutableFoo.new(5)
foo = Foo.new
coll.fill(1..0) { foo }.includes?(foo).should be_false
coll.fill(5...5) { foo }.includes?(foo).should be_false
coll.fill(-3...1) { foo }.includes?(foo).should be_false
coll.fill(-5..-6) { foo }.includes?(foo).should be_false
end

it "raises on out of bound start index" do
expect_raises(IndexError) { SafeIndexableMutable.new(5).fill(6..7, &.itself) }
expect_raises(IndexError) { SafeIndexableMutable.new(5).fill(-6..-1, &.itself) }
end
end
end

describe "#map!" do
Expand Down

0 comments on commit 207bdc6

Please sign in to comment.