Created
June 13, 2010 15:47
-
-
Save gstark/436761 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| From a49caebabb688fc83b01a03e3e970a0228de6f8a Mon Sep 17 00:00:00 2001 | |
| From: Gavin Stark <[email protected]> | |
| Date: Sun, 13 Jun 2010 00:54:50 -0400 | |
| Subject: [PATCH 1/2] Fixing Hash constructor to not rehash keys. | |
| --- | |
| kernel/common/hash.rb | 48 ++++++++++++++++++++++++++++++++++++++---------- | |
| 1 files changed, 38 insertions(+), 10 deletions(-) | |
| diff --git a/kernel/common/hash.rb b/kernel/common/hash.rb | |
| index 3ee4100..2108852 100644 | |
| --- a/kernel/common/hash.rb | |
| +++ b/kernel/common/hash.rb | |
| @@ -78,10 +78,8 @@ class Hash | |
| def self.[](*args) | |
| if args.size == 1 | |
| obj = args.first | |
| - if obj.kind_of? Hash | |
| - return new.replace(obj) | |
| - elsif obj.respond_to? :to_hash | |
| - return new.replace(Type.coerce_to(obj, Hash, :to_hash)) | |
| + if obj.kind_of?(Hash) || obj.respond_to?(:to_hash) | |
| + return new.send(:replace_without_key_hashing,obj) | |
| elsif obj.is_a?(Array) # See redmine # 1385 | |
| h = {} | |
| args.first.each do |arr| | |
| @@ -190,12 +188,7 @@ class Hash | |
| end | |
| end | |
| - def []=(key, value) | |
| - Ruby.check_frozen | |
| - | |
| - redistribute @entries if @size > @max_entries | |
| - | |
| - key_hash = key.hash | |
| + def __store_with_precomputed_hash__(key, value, key_hash) | |
| index = key_hash & @mask # key_index key_hash | |
| entry = @entries[index] | |
| @@ -222,6 +215,17 @@ class Hash | |
| value | |
| end | |
| + private :__store_with_precomputed_hash__ | |
| + | |
| + def []=(key, value) | |
| + Ruby.check_frozen | |
| + | |
| + redistribute @entries if @size > @max_entries | |
| + | |
| + key_hash = key.hash | |
| + | |
| + __store_with_precomputed_hash__(key,value,key_hash) | |
| + end | |
| alias_method :store, :[]= | |
| @@ -586,6 +590,30 @@ class Hash | |
| end | |
| end | |
| + def replace_without_key_hashing(other) | |
| + Ruby.check_frozen | |
| + | |
| + other = Type.coerce_to other, Hash, :to_hash | |
| + return self if self.equal? other | |
| + | |
| + setup | |
| + i = other.to_iter | |
| + while entry = i.next(entry) | |
| + __store_with_precomputed_hash__ entry.key, entry.value, entry.key_hash | |
| + end | |
| + | |
| + if other.default_proc | |
| + @default = other.default_proc | |
| + @default_proc = true | |
| + else | |
| + @default = other.default | |
| + @default_proc = false | |
| + end | |
| + | |
| + self | |
| + end | |
| + private :replace_without_key_hashing | |
| + | |
| # packed! [:@capacity, :@mask, :@max_entries, :@size, :@entries] | |
| # Sets the underlying data structures. | |
| -- | |
| 1.7.1 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| From a9f3316af571b45511dfe1e8852ccef2c82f720c Mon Sep 17 00:00:00 2001 | |
| From: Gavin Stark <[email protected]> | |
| Date: Sun, 13 Jun 2010 00:55:02 -0400 | |
| Subject: [PATCH 2/2] Adding new Hash constructor specs | |
| --- | |
| spec/ruby/core/hash/constructor_spec.rb | 34 +++++++++++++++++++++++++++++++ | |
| 1 files changed, 34 insertions(+), 0 deletions(-) | |
| diff --git a/spec/ruby/core/hash/constructor_spec.rb b/spec/ruby/core/hash/constructor_spec.rb | |
| index 644b24a..9c2d727 100644 | |
| --- a/spec/ruby/core/hash/constructor_spec.rb | |
| +++ b/spec/ruby/core/hash/constructor_spec.rb | |
| @@ -2,6 +2,40 @@ require File.expand_path('../../../spec_helper', __FILE__) | |
| require File.expand_path('../fixtures/classes', __FILE__) | |
| describe "Hash.[]" do | |
| + it "does not call #hash on elements when provided a hash" do | |
| + x = mock('x') | |
| + y = mock('y') | |
| + | |
| + other = {x => 1, y => 2} | |
| + | |
| + x.should_not_receive(:hash) | |
| + y.should_not_receive(:hash) | |
| + | |
| + hash_class[other] | |
| + end | |
| + | |
| + it "does not call #hash on elements when provided a non-Hash object responding to to_hash" do | |
| + x = mock('x') | |
| + y = mock('y') | |
| + | |
| + existing_hash = {x => 1, y => 2} | |
| + | |
| + x.should_not_receive(:hash) | |
| + y.should_not_receive(:hash) | |
| + | |
| + class NotAHash | |
| + def initialize(existing_hash) | |
| + @existing_hash = existing_hash | |
| + end | |
| + | |
| + def to_hash | |
| + @existing_hash | |
| + end | |
| + end | |
| + | |
| + hash_class[NotAHash.new(existing_hash)] | |
| + end | |
| + | |
| it "creates a Hash; values can be provided as the argument list" do | |
| hash_class[:a, 1, :b, 2].should == new_hash(:a => 1, :b => 2) | |
| hash_class[].should == new_hash | |
| -- | |
| 1.7.1 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment