Skip to content

Commit

Permalink
Refactor sort methods to #sort and #unstable_sort (#11029)
Browse files Browse the repository at this point in the history
  • Loading branch information
straight-shoota authored Aug 3, 2021
1 parent 2534957 commit 42ce885
Show file tree
Hide file tree
Showing 5 changed files with 258 additions and 194 deletions.
128 changes: 50 additions & 78 deletions spec/std/array_spec.cr
Original file line number Diff line number Diff line change
Expand Up @@ -1311,128 +1311,100 @@ describe "Array" do
end

describe "sort" do
[true, false].each do |stable|
describe "stable: #{stable}" do
it "sort without block" do
{% for sort in ["sort".id, "unstable_sort".id] %}
describe {{ "##{sort}" }} do
it "without block" do
a = [3, 4, 1, 2, 5, 6]
b = a.sort(stable: stable)
b = a.{{ sort }}
b.should eq([1, 2, 3, 4, 5, 6])
a.should_not eq(b)
end

it "sort with a block" do
it "with a block" do
a = ["foo", "a", "hello"]
b = a.sort(stable: stable) { |x, y| x.size <=> y.size }
b = a.{{ sort }} { |x, y| x.size <=> y.size }
b.should eq(["a", "foo", "hello"])
a.should_not eq(b)
end
end
end

it "stable sort without block" do
is_stable_sort(mutable: false, &.sort(stable: true))
end

it "stable sort with a block" do
is_stable_sort(mutable: false, &.sort(stable: true) { |a, b| a.value <=> b.value })
end

it "default is stable (without block)" do
is_stable_sort(mutable: false, &.sort)
end
{% if sort == "sort" %}
it "stable sort without a block" do
is_stable_sort(mutable: false, &.sort)
end

it "default is stable (with a block)" do
is_stable_sort(mutable: false, &.sort { |a, b| a.value <=> b.value })
end
end
it "stable sort with a block" do
is_stable_sort(mutable: false, &.sort { |a, b| a.value <=> b.value })
end
{% end %}
end

describe "sort!" do
[true, false].each do |stable|
describe "stable: #{stable}" do
it "sort! without block" do
describe {{ "##{sort}!" }} do
it "without block" do
a = [3, 4, 1, 2, 5, 6]
a.sort!(stable: stable)
a.{{ sort.id }}!
a.should eq([1, 2, 3, 4, 5, 6])
end

it "sort! with a block" do
it "with a block" do
a = ["foo", "a", "hello"]
a.sort!(stable: stable) { |x, y| x.size <=> y.size }
a.{{ sort.id }}! { |x, y| x.size <=> y.size }
a.should eq(["a", "foo", "hello"])
end
end
end

it "stable sort! without block" do
is_stable_sort(mutable: true, &.sort!(stable: true))
end

it "stable sort! with a block" do
is_stable_sort(mutable: true, &.sort!(stable: true) { |a, b| a.value <=> b.value })
end

it "default is stable (without block)" do
is_stable_sort(mutable: true, &.sort!)
end
{% if sort == "sort" %}
it "stable sort without a block" do
is_stable_sort(mutable: true, &.sort!)
end

it "default is stable (with a block)" do
is_stable_sort(mutable: true, &.sort! { |a, b| a.value <=> b.value })
end
end
it "stable sort with a block" do
is_stable_sort(mutable: true, &.sort! { |a, b| a.value <=> b.value })
end
{% end %}
end

describe "sort_by" do
[true, false].each do |stable|
describe "stable: #{stable}" do
it "sorts by" do
describe {{ "##{sort}_by" }} do
it "sorts" do
a = ["foo", "a", "hello"]
b = a.sort_by(stable: stable, &.size)
b = a.{{ sort }}_by(&.size)
b.should eq(["a", "foo", "hello"])
a.should_not eq(b)
end

it "unpacks tuple" do
a = [{"d", 4}, {"a", 1}, {"c", 3}, {"e", 5}, {"b", 2}]
b = a.sort_by(stable: stable) { |x, y| y }
b = a.{{ sort }}_by { |x, y| y }
b.should eq([{"a", 1}, {"b", 2}, {"c", 3}, {"d", 4}, {"e", 5}])
a.should_not eq(b)
end
end
end

it "stable sort by" do
is_stable_sort(mutable: false, &.sort_by(stable: true, &.value))
end

it "default is stable" do
is_stable_sort(mutable: false, &.sort_by(&.value))
end
end
{% if sort == "sort" %}
it "stable sort" do
is_stable_sort(mutable: false, &.sort_by(&.value))
end
{% end %}
end

describe "sort_by!" do
[true, false].each do |stable|
describe "stable: #{stable}" do
it "sorts by!" do
describe {{ "##{sort}_by!" }} do
it "sorts" do
a = ["foo", "a", "hello"]
a.sort_by!(stable: stable, &.size)
a.{{ sort }}_by!(&.size)
a.should eq(["a", "foo", "hello"])
end

it "calls given block exactly once for each element" do
calls = Hash(String, Int32).new(0)
a = ["foo", "a", "hello"]
a.sort_by!(stable: stable) { |e| calls[e] += 1; e.size }
a.{{ sort }}_by! { |e| calls[e] += 1; e.size }
calls.should eq({"foo" => 1, "a" => 1, "hello" => 1})
end
end
end

it "stable sort by!" do
is_stable_sort(mutable: true, &.sort_by!(stable: true, &.value))
end

it "default is stable" do
is_stable_sort(mutable: true, &.sort_by!(&.value))
end
{% if sort == "sort" %}
it "stable sort" do
is_stable_sort(mutable: true, &.sort_by!(&.value))
end
{% end %}
end
{% end %}
end

describe "swap" do
Expand Down
134 changes: 53 additions & 81 deletions spec/std/slice_spec.cr
Original file line number Diff line number Diff line change
Expand Up @@ -632,59 +632,49 @@ describe "Slice" do
end

describe "sort" do
[true, false].each do |stable|
describe "stable: #{stable}" do
it "sort without block" do
{% for sort in ["sort".id, "unstable_sort".id] %}
describe {{ "##{sort}" }} do
it "without block" do
slice = Slice[3, 4, 1, 2, 5, 6]
sorted_slice = slice.sort(stable: stable)
sorted_slice = slice.{{ sort }}
sorted_slice.to_a.should eq([1, 2, 3, 4, 5, 6])
slice.should_not eq(sorted_slice)
end

it "sort with a block" do
it "with a block" do
a = Slice["foo", "a", "hello"]
b = a.sort(stable: stable) { |x, y| x.size <=> y.size }
b = a.{{ sort }} { |x, y| x.size <=> y.size }
b.to_a.should eq(["a", "foo", "hello"])
a.should_not eq(b)
end
end
end

it "stable sort without block" do
is_stable_sort(mutable: false, &.sort(stable: true))
end

it "stable sort with a block" do
is_stable_sort(mutable: false, &.sort(stable: true) { |a, b| a.value <=> b.value })
end

it "default is stable (without block)" do
is_stable_sort(mutable: false, &.sort)
end
{% if sort == "sort" %}
it "stable sort without a block" do
is_stable_sort(mutable: false, &.sort)
end

it "default is stable (with a block)" do
is_stable_sort(mutable: false, &.sort { |a, b| a.value <=> b.value })
end
end
it "stable sort with a block" do
is_stable_sort(mutable: false, &.sort { |a, b| a.value <=> b.value })
end
{% end %}
end

describe "sort!" do
[true, false].each do |stable|
describe "stable: #{stable}" do
it "sort! without block" do
describe {{ "##{sort}!" }} do
it "without block" do
a = [3, 4, 1, 2, 5, 6]
a.sort!(stable: stable)
a.{{ sort }}!
a.should eq([1, 2, 3, 4, 5, 6])
end

it "sort! with a block" do
it "with a block" do
a = ["foo", "a", "hello"]
a.sort!(stable: stable) { |x, y| x.size <=> y.size }
a.{{ sort }}! { |x, y| x.size <=> y.size }
a.should eq(["a", "foo", "hello"])
end

it "sorts with invalid block (#4379)" do
a = [1] * 17
b = a.sort(stable: stable) { -1 }
b = a.{{ sort }} { -1 }
a.should eq(b)
end

Expand All @@ -696,7 +686,7 @@ describe "Slice" do
Spaceship.new(3),
]

spaceships.sort!(stable: stable)
spaceships.{{ sort }}!
4.times do |i|
spaceships[i].value.should eq(i)
end
Expand All @@ -709,81 +699,63 @@ describe "Slice" do
]

expect_raises(ArgumentError) do
spaceships.sort!(stable: stable)
spaceships.{{ sort }}!
end
end

it "raises if sort! block returns nil" do
expect_raises(ArgumentError) do
Slice[1, 2].sort!(stable: stable) { nil }
Slice[1, 2].{{ sort }}! { nil }
end
end
end
end

it "stable sort! without block" do
is_stable_sort(mutable: true, &.sort!(stable: true))
end

it "stable sort! with a block" do
is_stable_sort(mutable: true, &.sort!(stable: true) { |a, b| a.value <=> b.value })
end

it "default is stable (without block)" do
is_stable_sort(mutable: true, &.sort!)
end
{% if sort == "sort" %}
it "stable sort without a block" do
is_stable_sort(mutable: true, &.sort!)
end

it "default is stable (with a block)" do
is_stable_sort(mutable: true, &.sort! { |a, b| a.value <=> b.value })
end
end
it "stable sort with a block" do
is_stable_sort(mutable: true, &.sort! { |a, b| a.value <=> b.value })
end
{% end %}
end

describe "sort_by" do
[true, false].each do |stable|
describe "stable: #{stable}" do
it "sorts by" do
describe {{ "##{sort}_by" }} do
it "sorts" do
a = Slice["foo", "a", "hello"]
b = a.sort_by(stable: stable, &.size)
b = a.{{ sort }}_by(&.size)
b.to_a.should eq(["a", "foo", "hello"])
a.should_not eq(b)
end
end
end

it "stable sort by" do
is_stable_sort(mutable: false, &.sort_by(stable: true, &.value))
end

it "default is stable" do
is_stable_sort(mutable: false, &.sort_by(&.value))
end
end
{% if sort == "sort" %}
it "stable sort" do
is_stable_sort(mutable: false, &.sort_by(&.value))
end
{% end %}
end

describe "sort_by!" do
[true, false].each do |stable|
describe "stable: #{stable}" do
it "sorts by!" do
describe {{ "##{sort}_by" }} do
it "sorts" do
a = Slice["foo", "a", "hello"]
a.sort_by!(stable: stable, &.size)
a.{{ sort }}_by!(&.size)
a.to_a.should eq(["a", "foo", "hello"])
end

it "calls given block exactly once for each element" do
calls = Hash(String, Int32).new(0)
a = Slice["foo", "a", "hello"]
a.sort_by!(stable: stable) { |e| calls[e] += 1; e.size }
a.{{ sort }}_by! { |e| calls[e] += 1; e.size }
calls.should eq({"foo" => 1, "a" => 1, "hello" => 1})
end
end
end

it "stable sort by!" do
is_stable_sort(mutable: true, &.sort_by!(stable: true, &.value))
end

it "default is stable" do
is_stable_sort(mutable: true, &.sort_by!(&.value))
end
{% if sort == "sort" %}
it "stable sort" do
is_stable_sort(mutable: true, &.sort_by!(&.value))
end
{% end %}
end
{% end %}
end

describe "<=>" do
Expand Down
Loading

0 comments on commit 42ce885

Please sign in to comment.