From 73bdb7d9cd5e5748ac66676cae7e07eb8785b404 Mon Sep 17 00:00:00 2001 From: Quinton Miller Date: Wed, 3 Apr 2024 21:05:49 +0800 Subject: [PATCH] Fix `Hash#put_if_absent` putting duplicate keys --- spec/std/hash_spec.cr | 6 +++++ src/hash.cr | 54 +------------------------------------------ 2 files changed, 7 insertions(+), 53 deletions(-) diff --git a/spec/std/hash_spec.cr b/spec/std/hash_spec.cr index ed8b9931cd82..d098c8f7bf11 100644 --- a/spec/std/hash_spec.cr +++ b/spec/std/hash_spec.cr @@ -216,6 +216,12 @@ describe "Hash" do h.should eq({1 => v, 2 => ["2"]}) h[1].should be(v) end + + it "doesn't put duplicate keys (#14425)" do + h = {1 => 2} + h.put_if_absent(3) { h[3] = 4 }.should eq(4) + h.should eq({1 => 2, 3 => 4}) + end end describe "update" do diff --git a/src/hash.cr b/src/hash.cr index 1a40a36f2107..b245a201ae95 100644 --- a/src/hash.cr +++ b/src/hash.cr @@ -419,56 +419,6 @@ class Hash(K, V) end end - # Inserts a key-value pair. Assumes that the given key doesn't exist. - private def insert_new(key, value) - # Unless otherwise noted, this body should be identical to `#upsert` - - if @entries.null? - @indices_size_pow2 = 3 - @entries = malloc_entries(4) - end - - hash = key_hash(key) - - if @indices.null? - # don't call `#update_linear_scan` here - - if !entries_full? - add_entry_and_increment_size(hash, key, value) - return - end - - resize - - if @indices.null? - add_entry_and_increment_size(hash, key, value) - return - end - end - - index = fit_in_indices(hash) - - while true - entry_index = get_index(index) - - if entry_index == -1 - if entries_full? - resize - index = fit_in_indices(hash) - next - end - - set_index(index, entries_size) - add_entry_and_increment_size(hash, key, value) - return - end - - # don't call `#get_entry` and `#entry_matches?` here - - index = next_index(index) - end - end - # Tries to update a key-value-hash triplet by doing a linear scan. # Returns an old `Entry` if it was updated, otherwise `nil`. private def update_linear_scan(key, value, hash) : Entry(K, V)? @@ -1126,7 +1076,7 @@ class Hash(K, V) entry.value else value = yield key - insert_new(key, value) + upsert(key, value) value end end @@ -1163,8 +1113,6 @@ class Hash(K, V) entry.value elsif block = @block default_value = block.call(self, key) - - # NOTE: can't use `#insert_new` as `block` might add arbitrary keys upsert(key, yield default_value) default_value else