Skip to content

Commit

Permalink
Always copy Hash's default block on #dup and #clone (#10744)
Browse files Browse the repository at this point in the history
  • Loading branch information
HertzDevil authored May 27, 2021
1 parent 7962801 commit 3f99d7d
Show file tree
Hide file tree
Showing 2 changed files with 27 additions and 2 deletions.
20 changes: 20 additions & 0 deletions spec/std/hash_spec.cr
Original file line number Diff line number Diff line change
Expand Up @@ -494,6 +494,16 @@ describe "Hash" do
clone = h.clone
clone.should be(clone.first[1])
end

it "retains default block on clone" do
h1 = Hash(Int32, String).new("a")
h2 = h1.clone
h2[0].should eq("a")

h1[1] = "b"
h3 = h1.clone
h3[0].should eq("a")
end
end

describe "dup" do
Expand Down Expand Up @@ -536,6 +546,16 @@ describe "Hash" do
h1.delete(0)
h2[0].should eq([0])
end

it "retains default block on dup" do
h1 = Hash(Int32, String).new("a")
h2 = h1.dup
h2[0].should eq("a")

h1[1] = "b"
h3 = h1.dup
h3[0].should eq("a")
end
end

it "initializes with block" do
Expand Down
9 changes: 7 additions & 2 deletions src/hash.cr
Original file line number Diff line number Diff line change
Expand Up @@ -640,6 +640,7 @@ class Hash(K, V)
# Initializes a `dup` copy from the contents of `other`.
protected def initialize_dup(other)
initialize_compare_by_identity(other)
initialize_default_block(other)

return if other.empty?

Expand All @@ -650,6 +651,7 @@ class Hash(K, V)
# Initializes a `clone` copy from the contents of `other`.
protected def initialize_clone(other)
initialize_compare_by_identity(other)
initialize_default_block(other)

return if other.empty?

Expand All @@ -661,6 +663,10 @@ class Hash(K, V)
compare_by_identity if other.compare_by_identity?
end

private def initialize_default_block(other)
@block = other.@block
end

# Initializes `@entries` for a dup copy.
# Here we only need to duplicate the buffer.
private def initialize_dup_entries(other)
Expand All @@ -685,14 +691,13 @@ class Hash(K, V)
end
end

# Initializes all variables other than `@entries` for a copy.
# Initializes all variables other than `@entries` and `@block` for a copy.
private def initialize_copy_non_entries_vars(other)
@indices_bytesize = other.@indices_bytesize
@first = other.@first
@size = other.@size
@deleted_count = other.@deleted_count
@indices_size_pow2 = other.@indices_size_pow2
@block = other.@block

unless other.@indices.null?
@indices = malloc_indices(other.indices_size)
Expand Down

0 comments on commit 3f99d7d

Please sign in to comment.