Skip to content

Commit

Permalink
Array/Enumerable/Iterator reuse flag
Browse files Browse the repository at this point in the history
  • Loading branch information
asterite committed Dec 20, 2016
1 parent 7f0182c commit 19f767b
Show file tree
Hide file tree
Showing 7 changed files with 621 additions and 88 deletions.
158 changes: 158 additions & 0 deletions spec/std/array_spec.cr
Expand Up @@ -1484,6 +1484,18 @@ describe "Array" do
sums.should eq([9, 9, 9, 9, 9, 9])
end

it "yields with reuse = true" do
sums = [] of Int32
object_ids = Set(UInt64).new
[1, 2, 3].each_permutation(3, reuse: true) do |perm|
object_ids << perm.object_id
perm.map! &.+(1)
sums << perm.sum
end.should eq([1, 2, 3])
sums.should eq([9, 9, 9, 9, 9, 9])
object_ids.size.should eq(1)
end

assert { expect_raises(ArgumentError, "size must be positive") { [1].each_permutation(-1) { } } }

it "returns iterator" do
Expand Down Expand Up @@ -1511,6 +1523,20 @@ describe "Array" do
iter.rewind
iter.next.should eq(perms[0])
end

it "returns iterator with reuse = true" do
a = [1, 2, 3]
object_ids = Set(UInt64).new
perms = a.permutations
iter = a.each_permutation(reuse: true)
perms.each do |perm|
b = iter.next.as(Array)
object_ids << b.object_id
b.should eq(perm)
end
iter.next.should be_a(Iterator::Stop)
object_ids.size.should eq(1)
end
end

describe "combinations" do
Expand Down Expand Up @@ -1542,6 +1568,27 @@ describe "Array" do
sums.should eq([9])
end

it "does with reuse = true" do
sums = [] of Int32
object_ids = Set(UInt64).new
[1, 2, 3].each_combination(2, reuse: true) do |comb|
sums << comb.sum
object_ids << comb.object_id
end
sums.should eq([3, 4, 5])
object_ids.size.should eq(1)
end

it "does with reuse = array" do
sums = [] of Int32
reuse = [] of Int32
[1, 2, 3].each_combination(2, reuse: reuse) do |comb|
sums << comb.sum
comb.should be(reuse)
end
sums.should eq([3, 4, 5])
end

assert { expect_raises(ArgumentError, "size must be positive") { [1].each_combination(-1) { } } }

it "returns iterator" do
Expand All @@ -1556,6 +1603,33 @@ describe "Array" do
iter.rewind
iter.next.should eq(combs[0])
end

it "returns iterator with reuse = true" do
a = [1, 2, 3, 4]
combs = a.combinations(2)
object_ids = Set(UInt64).new
iter = a.each_combination(2, reuse: true)
combs.each do |comb|
b = iter.next
object_ids << b.object_id
b.should eq(comb)
end
iter.next.should be_a(Iterator::Stop)
object_ids.size.should eq(1)
end

it "returns iterator with reuse = array" do
a = [1, 2, 3, 4]
reuse = [] of Int32
combs = a.combinations(2)
iter = a.each_combination(2, reuse: reuse)
combs.each do |comb|
b = iter.next
b.should be(reuse)
b.should eq(comb)
end
iter.next.should be_a(Iterator::Stop)
end
end

describe "repeated_combinations" do
Expand Down Expand Up @@ -1587,6 +1661,29 @@ describe "Array" do

assert { expect_raises(ArgumentError, "size must be positive") { [1].each_repeated_combination(-1) { } } }

it "yields with reuse = true" do
sums = [] of Int32
object_ids = Set(UInt64).new
[1, 2, 3].each_repeated_combination(3, reuse: true) do |comb|
object_ids << comb.object_id
comb.map! &.+(1)
sums << comb.sum
end.should eq([1, 2, 3])
sums.should eq([6, 7, 8, 8, 9, 10, 9, 10, 11, 12])
object_ids.size.should eq(1)
end

it "yields with reuse = array" do
sums = [] of Int32
reuse = [] of Int32
[1, 2, 3].each_repeated_combination(3, reuse: reuse) do |comb|
comb.should be(reuse)
comb.map! &.+(1)
sums << comb.sum
end.should eq([1, 2, 3])
sums.should eq([6, 7, 8, 8, 9, 10, 9, 10, 11, 12])
end

it "returns iterator" do
a = [1, 2, 3, 4]
combs = a.repeated_combinations(2)
Expand All @@ -1599,6 +1696,33 @@ describe "Array" do
iter.rewind
iter.next.should eq(combs[0])
end

it "returns iterator with reuse = true" do
a = [1, 2, 3, 4]
object_ids = Set(UInt64).new
combs = a.repeated_combinations(2)
iter = a.each_repeated_combination(2, reuse: true)
combs.each do |comb|
b = iter.next
object_ids << b.object_id
b.should eq(comb)
end
iter.next.should be_a(Iterator::Stop)
object_ids.size.should eq(1)
end

it "returns iterator with reuse = array" do
a = [1, 2, 3, 4]
reuse = [] of Int32
combs = a.repeated_combinations(2)
iter = a.each_repeated_combination(2, reuse: reuse)
combs.each do |comb|
b = iter.next
b.should be(reuse)
b.should eq(comb)
end
iter.next.should be_a(Iterator::Stop)
end
end

describe "repeated_permutations" do
Expand Down Expand Up @@ -1628,6 +1752,29 @@ describe "Array" do
sums.should eq([6, 7, 8, 7, 8, 9, 8, 9, 10, 7, 8, 9, 8, 9, 10, 9, 10, 11, 8, 9, 10, 9, 10, 11, 10, 11, 12])
end

it "yields with reuse = true" do
sums = [] of Int32
object_ids = Set(UInt64).new
[1, 2, 3].each_repeated_permutation(3, reuse: true) do |a|
object_ids << a.object_id
a.map! &.+(1)
sums << a.sum
end.should eq([1, 2, 3])
sums.should eq([6, 7, 8, 7, 8, 9, 8, 9, 10, 7, 8, 9, 8, 9, 10, 9, 10, 11, 8, 9, 10, 9, 10, 11, 10, 11, 12])
object_ids.size.should eq(1)
end

it "yields with reuse = array" do
sums = [] of Int32
reuse = [] of Int32
[1, 2, 3].each_repeated_permutation(3, reuse: reuse) do |a|
a.should be(reuse)
a.map! &.+(1)
sums << a.sum
end.should eq([1, 2, 3])
sums.should eq([6, 7, 8, 7, 8, 9, 8, 9, 10, 7, 8, 9, 8, 9, 10, 9, 10, 11, 8, 9, 10, 9, 10, 11, 10, 11, 12])
end

assert { expect_raises(ArgumentError, "size must be positive") { [1].each_repeated_permutation(-1) { } } }
end

Expand Down Expand Up @@ -1656,6 +1803,17 @@ describe "Array" do
res.should eq([[1, 3, 5], [1, 3, 6], [2, 3, 5], [2, 3, 6]])
end

it "more arrays, reuse = true" do
res = [] of Array(Int32)
object_ids = Set(UInt64).new
Array.each_product([[1, 2], [3], [5, 6]], reuse: true) do |r|
object_ids << r.object_id
res << r.dup
end
res.should eq([[1, 3, 5], [1, 3, 6], [2, 3, 5], [2, 3, 6]])
object_ids.size.should eq(1)
end

it "with splat" do
res = [] of Array(Int32 | Char)
Array.each_product([1, 2], ['a', 'b']) { |r| res << r }
Expand Down
103 changes: 103 additions & 0 deletions spec/std/enumerable_spec.cr
Expand Up @@ -154,6 +154,25 @@ describe "Enumerable" do
result = [nil, nil, 1, 1, nil].chunk(&.itself).to_a
result.should eq [{nil, [nil, nil]}, {1, [1, 1]}, {nil, [nil]}]
end

it "reuses true" do
iter = [1, 1, 2, 3, 3].chunk(reuse: true, &.itself)
a = iter.next.as(Tuple)
a.should eq({1, [1, 1]})

b = iter.next.as(Tuple)
b.should eq({2, [2]})
b[1].should be(a[1])

c = iter.next.as(Tuple)
c.should eq({3, [3, 3]})
c[1].should be(a[1])

iter.rewind
a1 = iter.next.as(Tuple)
a1.should eq({1, [1, 1]})
a1[1].should be(a[1])
end
end

describe "chunks" do
Expand Down Expand Up @@ -227,19 +246,82 @@ describe "Enumerable" do
iter.rewind
iter.next.should eq([1, 2, 3])
end

it "returns each_cons iterator with reuse = true" do
iter = [1, 2, 3, 4, 5].each_cons(3, reuse: true)

a = iter.next
a.should eq([1, 2, 3])

b = iter.next
b.should be(a)
end

it "returns each_cons iterator with reuse = array" do
reuse = [] of Int32
iter = [1, 2, 3, 4, 5].each_cons(3, reuse: reuse)

a = iter.next
a.should eq([1, 2, 3])
a.should be(reuse)
end

it "returns running pairs with reuse = true" do
array = [] of Array(Int32)
object_ids = Set(UInt64).new
[1, 2, 3, 4].each_cons(2, reuse: true) do |pair|
object_ids << pair.object_id
array << pair.dup
end
array.should eq([[1, 2], [2, 3], [3, 4]])
object_ids.size.should eq(1)
end

it "returns running pairs with reuse = array" do
array = [] of Array(Int32)
reuse = [] of Int32
[1, 2, 3, 4].each_cons(2, reuse: reuse) do |pair|
pair.should be(reuse)
array << pair.dup
end
array.should eq([[1, 2], [2, 3], [3, 4]])
end
end

describe "each_slice" do
it "returns partial slices" do
array = [] of Array(Int32)
[1, 2, 3].each_slice(2) { |slice| array << slice }
array.should eq([[1, 2], [3]])
array[0].should_not be(array[1])
end

it "returns full slices" do
array = [] of Array(Int32)
[1, 2, 3, 4].each_slice(2) { |slice| array << slice }
array.should eq([[1, 2], [3, 4]])
array[0].should_not be(array[1])
end

it "reuses with true" do
array = [] of Array(Int32)
object_ids = Set(UInt64).new
[1, 2, 3, 4].each_slice(2, reuse: true) do |slice|
object_ids << slice.object_id
array << slice.dup
end
array.should eq([[1, 2], [3, 4]])
object_ids.size.should eq(1)
end

it "reuses with existing array" do
array = [] of Array(Int32)
reuse = [] of Int32
[1, 2, 3, 4].each_slice(2, reuse: reuse) do |slice|
slice.should be(reuse)
array << slice.dup
end
array.should eq([[1, 2], [3, 4]])
end

it "returns each_slice iterator" do
Expand Down Expand Up @@ -396,6 +478,27 @@ describe "Enumerable" do
[1, 2, 4, 5].in_groups_of(3, 10) { |a| sums << a.sum }
sums.should eq([7, 25])
end

it "reuses with true" do
array = [] of Array(Int32)
object_ids = Set(UInt64).new
[1, 2, 4, 5].in_groups_of(3, 10, reuse: true) do |group|
object_ids << group.object_id
array << group.dup
end
array.should eq([[1, 2, 4], [5, 10, 10]])
object_ids.size.should eq(1)
end

it "reuses with existing array" do
array = [] of Array(Int32)
reuse = [] of Int32
[1, 2, 4, 5].in_groups_of(3, 10, reuse: reuse) do |slice|
slice.should be(reuse)
array << slice.dup
end
array.should eq([[1, 2, 4], [5, 10, 10]])
end
end

describe "includes?" do
Expand Down

0 comments on commit 19f767b

Please sign in to comment.