Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Merge remote-tracking branch 'carlosgaldino/hash-refactor'

  • Loading branch information...
commit 31f9bbb4d52f8b8c4d6f994b20c130a5e215264d 2 parents 95e66cc + bba2d2e
Brian Shirai brixen authored
335 kernel/common/hash.rb
View
@@ -0,0 +1,335 @@
+# -*- encoding: us-ascii -*-
+
+class Hash
+ attr_reader :size
+ attr_reader :capacity
+ attr_reader :max_entries
+
+ alias_method :length, :size
+
+ Entries = Rubinius::Tuple
+
+ # Initial size of Hash. MUST be a power of 2.
+ MIN_SIZE = 16
+
+ # Allocate more storage when this full. This value grows with
+ # the size of the Hash so that the max load factor is 0.75.
+ MAX_ENTRIES = 12
+
+ def self.new_from_literal(size)
+ new
+ end
+
+ # Creates a fully-formed instance of Hash.
+ def self.allocate
+ hash = super()
+ Rubinius.privately { hash.__setup__ }
+ hash
+ end
+
+ # #entries is a method provided by Enumerable which calls #to_a,
+ # so we have to not collide with that.
+ attr_reader_specific :entries, :__entries__
+
+ def self.[](*args)
+ if args.size == 1
+ obj = args.first
+ if hash = Rubinius::Type.check_convert_type(obj, Hash, :to_hash)
+ return allocate.replace(hash)
+ elsif array = Rubinius::Type.check_convert_type(obj, Array, :to_ary)
+ h = new
+ array.each do |arr|
+ next unless arr.respond_to? :to_ary
+ arr = arr.to_ary
+ next unless (1..2).include? arr.size
+ h[arr.at(0)] = arr.at(1)
+ end
+ return h
+ end
+ end
+
+ return new if args.empty?
+
+ if args.size & 1 == 1
+ raise ArgumentError, "Expected an even number, got #{args.length}"
+ end
+
+ hash = new
+ i = 0
+ total = args.size
+
+ while i < total
+ hash[args[i]] = args[i+1]
+ i += 2
+ end
+
+ hash
+ end
+
+ def ==(other)
+ return true if self.equal? other
+ unless other.kind_of? Hash
+ return false unless other.respond_to? :to_hash
+ return other == self
+ end
+
+ return false unless other.size == size
+
+ Thread.detect_recursion self, other do
+ each_item do |item|
+ other_item = other.find_item(item.key)
+
+ # Other doesn't even have this key
+ return false unless other_item
+
+ # Order of the comparison matters! We must compare our value with
+ # the other Hash's value and not the other way around.
+ unless Rubinius::Type::object_equal(item.value, other_item.value) or
+ item.value == other_item.value
+ return false
+ end
+ end
+ end
+ true
+ end
+
+ def eql?(other)
+ # Just like ==, but uses eql? to compare values.
+ return true if self.equal? other
+ unless other.kind_of? Hash
+ return false unless other.respond_to? :to_hash
+ return other.eql?(self)
+ end
+
+ return false unless other.size == size
+
+ Thread.detect_recursion self, other do
+ each_item do |item|
+ other_item = other.find_item(item.key)
+
+ # Other doesn't even have this key
+ return false unless other_item
+
+ # Order of the comparison matters! We must compare our value with
+ # the other Hash's value and not the other way around.
+ unless Rubinius::Type::object_equal(item.value, other_item.value) or
+ item.value.eql?(other_item.value)
+ return false
+ end
+ end
+ end
+ true
+ end
+
+ def hash
+ val = size
+ Thread.detect_outermost_recursion self do
+ each_item do |item|
+ val ^= item.key.hash
+ val ^= item.value.hash
+ end
+ end
+
+ val
+ end
+
+ def [](key)
+ if item = find_item(key)
+ item.value
+ else
+ default key
+ end
+ end
+
+ def clear
+ Rubinius.check_frozen
+ __setup__
+ self
+ end
+
+ def default=(value)
+ @default_proc = nil
+ @default = value
+ end
+
+ def delete_if(&block)
+ return to_enum(:delete_if) unless block_given?
+
+ Rubinius.check_frozen
+
+ select(&block).each { |k, v| delete k }
+ self
+ end
+
+ def each_key
+ return to_enum(:each_key) unless block_given?
+
+ each_item { |item| yield item.key }
+ self
+ end
+
+ def each_value
+ return to_enum(:each_value) unless block_given?
+
+ each_item { |item| yield item.value }
+ self
+ end
+
+ # Returns true if there are no entries.
+ def empty?
+ @size == 0
+ end
+
+ def index(value)
+ each_item do |item|
+ return item.key if item.value == value
+ end
+ end
+
+ def inspect
+ out = []
+ return '{...}' if Thread.detect_recursion self do
+ each_item do |item|
+ str = item.key.inspect
+ str << '=>'
+ str << item.value.inspect
+ out << str
+ end
+ end
+ "{#{out.join ', '}}"
+ end
+
+ def invert
+ inverted = {}
+ each_item do |item|
+ inverted[item.value] = item.key
+ end
+ inverted
+ end
+
+ def key?(key)
+ find_item(key) != nil
+ end
+
+ alias_method :has_key?, :key?
+ alias_method :include?, :key?
+ alias_method :member?, :key?
+
+ # Calculates the +@entries+ slot given a key_hash value.
+ def key_index(key_hash)
+ key_hash & @mask
+ end
+ private :key_index
+
+ def keys
+ ary = []
+ each_item do |item|
+ ary << item.key
+ end
+ ary
+ end
+
+ def merge(other, &block)
+ dup.merge!(other, &block)
+ end
+
+ # Recalculates the cached key_hash values and reorders the entries
+ # into a new +@entries+ vector. Does NOT change the size of the
+ # hash. See +#redistribute+.
+ def rehash
+ capacity = @capacity
+ entries = @entries
+
+ @entries = Entries.new @capacity
+
+ i = -1
+ while (i += 1) < capacity
+ next unless old = entries[i]
+ while old
+ old.link = nil if nxt = old.link
+
+ index = key_index(old.key_hash = old.key.hash)
+ if item = @entries[index]
+ old.link = item
+ end
+ @entries[index] = old
+
+ old = nxt
+ end
+ end
+
+ self
+ end
+
+ def reject(&block)
+ return to_enum(:reject) unless block_given?
+
+ hsh = dup.delete_if(&block)
+ hsh.taint if tainted?
+ hsh
+ end
+
+ def reject!(&block)
+ Rubinius.check_frozen
+
+ return to_enum(:reject!) unless block_given?
+
+ unless empty?
+ size = @size
+ delete_if(&block)
+ return self if size != @size
+ end
+
+ nil
+ end
+
+ def sort(&block)
+ to_a.sort(&block)
+ end
+
+ def to_a
+ ary = []
+
+ each_item do |item|
+ ary << [item.key, item.value]
+ end
+
+ ary
+ end
+
+ def to_hash
+ self
+ end
+
+ def value?(value)
+ each_item do |item|
+ return true if item.value == value
+ end
+ false
+ end
+
+ alias_method :has_value?, :value?
+
+ def values
+ ary = []
+
+ each_item do |item|
+ ary << item.value
+ end
+
+ ary
+ end
+
+ def values_at(*args)
+ args.map do |key|
+ if item = find_item(key)
+ item.value
+ else
+ default key
+ end
+ end
+ end
+
+ alias_method :indices, :values_at
+ alias_method :indexes, :values_at
+end
340 kernel/common/hash18.rb
View
@@ -62,150 +62,6 @@ def next(item)
# Hash methods
- attr_reader :size
-
- # #entries is a method provided by Enumerable which calls #to_a,
- # so we have to not collide with that.
- attr_reader_specific :entries, :__entries__
-
- attr_reader :capacity
- attr_reader :max_entries
-
- alias_method :length, :size
-
- Entries = Rubinius::Tuple
-
- # Initial size of Hash. MUST be a power of 2.
- MIN_SIZE = 16
-
- # Allocate more storage when this full. This value grows with
- # the size of the Hash so that the max load factor is 0.75.
- MAX_ENTRIES = 12
-
- # Overridden in lib/1.8.7 or lib/1.9
- def self.[](*args)
- if args.size == 1
- obj = args.first
- if obj.kind_of? Hash
- return allocate.replace(obj)
- elsif obj.respond_to? :to_hash
- return allocate.replace(Rubinius::Type.coerce_to(obj, Hash, :to_hash))
- elsif obj.is_a?(Array) # See redmine # 1385
- h = new
- args.first.each do |arr|
- next unless arr.respond_to? :to_ary
- arr = arr.to_ary
- next unless (1..2).include? arr.size
- h[arr.at(0)] = arr.at(1)
- end
- return h
- end
- end
-
- return new if args.empty?
-
- if args.size & 1 == 1
- raise ArgumentError, "Expected an even number, got #{args.length}"
- end
-
- hash = new
- i = 0
- total = args.size
-
- while i < total
- hash[args[i]] = args[i+1]
- i += 2
- end
-
- hash
- end
-
- def self.new_from_literal(size)
- new
- end
-
- # Creates a fully-formed instance of Hash.
- def self.allocate
- hash = super()
- Rubinius.privately { hash.__setup__ }
- hash
- end
-
- def ==(other)
- return true if self.equal? other
- unless other.kind_of? Hash
- return false unless other.respond_to? :to_hash
- return other == self
- end
-
- return false unless other.size == size
-
- Thread.detect_recursion self, other do
- each_item do |item|
- other_item = other.find_item(item.key)
-
- # Other doesn't even have this key
- return false unless other_item
-
- # Order of the comparison matters! We must compare our value with
- # the other Hash's value and not the other way around.
- unless Rubinius::Type::object_equal(item.value, other_item.value) or
- item.value == other_item.value
- return false
- end
- end
- end
- true
- end
-
- def eql?(other)
- # Just like ==, but uses eql? to compare values.
- return true if self.equal? other
- unless other.kind_of? Hash
- return false unless other.respond_to? :to_hash
- return other.eql?(self)
- end
-
- return false unless other.size == size
-
- Thread.detect_recursion self, other do
- each_item do |item|
- other_item = other.find_item(item.key)
-
- # Other doesn't even have this key
- return false unless other_item
-
- # Order of the comparison matters! We must compare our value with
- # the other Hash's value and not the other way around.
- unless Rubinius::Type::object_equal(item.value, other_item.value) or
- item.value.eql?(other_item.value)
- return false
- end
- end
- end
- true
- end
-
- def hash
- val = size
- Thread.detect_outermost_recursion self do
- each_item do |item|
- val ^= item.key.hash
- val ^= item.value.hash
- end
- end
-
- return val
- end
-
- def [](key)
- if item = find_item(key)
- item.value
- else
- default key
- end
- end
-
def []=(key, value)
Rubinius.check_frozen
@@ -244,12 +100,6 @@ def []=(key, value)
# Used internally to get around subclasses redefining #[]=
alias_method :__store__, :[]=
- def clear
- Rubinius.check_frozen
- __setup__
- self
- end
-
def default(key = undefined)
# current MRI documentation comment is wrong. Actual behavior is:
# Hash.new { 1 }.default # => nil
@@ -260,11 +110,6 @@ def default(key = undefined)
end
end
- def default=(value)
- @default_proc = false
- @default = value
- end
-
def default_proc
@default if @default_proc
end
@@ -298,15 +143,6 @@ def delete(key)
return yield(key) if block_given?
end
- def delete_if(&block)
- return to_enum(:delete_if) unless block_given?
-
- Rubinius.check_frozen
-
- select(&block).each { |k, v| delete k }
- self
- end
-
def each_item
idx = 0
cap = @capacity
@@ -343,22 +179,6 @@ def each
self
end
- def each_key
- return to_enum(:each_key) unless block_given?
-
- each_item { |e| yield e.key }
- self
- end
-
- def each_value
- return to_enum(:each_value) unless block_given?
-
- each_item do |item|
- yield item.value
- end
- self
- end
-
def each_pair
return to_enum(:each_pair) unless block_given?
@@ -368,11 +188,6 @@ def each_pair
self
end
- # Returns true if there are no entries.
- def empty?
- @size == 0
- end
-
def fetch(key, default=undefined)
if item = find_item(key)
return item.value
@@ -397,13 +212,6 @@ def find_item(key)
end
end
- def index(value)
- each_item do |item|
- return item.key if item.value == value
- end
- nil
- end
-
def initialize(default=undefined, &block)
Rubinius.check_frozen
@@ -423,53 +231,6 @@ def initialize(default=undefined, &block)
end
private :initialize
- def inspect
- out = []
- return '{...}' if Thread.detect_recursion self do
- each_item do |item|
- str = item.key.inspect
- str << '=>'
- str << item.value.inspect
- out << str
- end
- end
- "{#{out.join ', '}}"
- end
-
- def invert
- inverted = {}
- each_item do |item|
- inverted[item.value] = item.key
- end
- inverted
- end
-
- def key?(key)
- find_item(key) != nil
- end
-
- alias_method :has_key?, :key?
- alias_method :include?, :key?
- alias_method :member?, :key?
-
- # Calculates the +@entries+ slot given a key_hash value.
- def key_index(key_hash)
- key_hash & @mask
- end
- private :key_index
-
- def keys
- ary = []
- each_item do |item|
- ary << item.key
- end
- ary
- end
-
- def merge(other, &block)
- dup.merge!(other, &block)
- end
-
def merge!(other)
other = Rubinius::Type.coerce_to other, Hash, :to_hash
@@ -534,57 +295,6 @@ def redistribute(entries)
end
end
- # Recalculates the cached key_hash values and reorders the entries
- # into a new +@entries+ vector. Does NOT change the size of the
- # hash. See +#redistribute+.
- def rehash
- capacity = @capacity
- entries = @entries
-
- @entries = Entries.new @capacity
-
- i = -1
- while (i += 1) < capacity
- next unless old = entries[i]
- while old
- old.link = nil if nxt = old.link
-
- index = key_index(old.key_hash = old.key.hash)
- if item = @entries[index]
- old.link = item
- end
- @entries[index] = old
-
- old = nxt
- end
- end
-
- self
- end
-
- def reject
- return to_enum(:reject) unless block_given?
-
- hsh = self.class.new
- hsh.taint if self.tainted?
- self.each { |k, v| hsh[k] = v unless yield(k, v) }
- hsh
- end
-
- def reject!(&block)
- Rubinius.check_frozen
-
- return to_enum(:reject!) unless block_given?
-
- unless empty?
- size = @size
- delete_if(&block)
- return self if size != @size
- end
-
- nil
- end
-
def replace(other)
Rubinius.check_frozen
@@ -693,62 +403,12 @@ def __setup__(capacity=MIN_SIZE, max=MAX_ENTRIES, size=0)
end
private :__setup__
- def sort(&block)
- to_a.sort(&block)
- end
-
- def to_a
- ary = []
-
- each_item do |item|
- ary << [item.key, item.value]
- end
-
- ary
- end
-
# Returns an external iterator for the bins. See +Iterator+
def to_iter
Iterator.new @entries, @capacity
end
- def to_hash
- self
- end
-
def to_s
to_a.join
end
-
- def value?(value)
- each_item do |item|
- return true if item.value == value
- end
- false
- end
-
- alias_method :has_value?, :value?
-
- def values
- ary = []
-
- each_item do |item|
- ary << item.value
- end
-
- ary
- end
-
- def values_at(*args)
- args.map do |key|
- if item = find_item(key)
- item.value
- else
- default key
- end
- end
- end
-
- alias_method :indexes, :values_at
- alias_method :indices, :values_at
end
352 kernel/common/hash19.rb
View
@@ -113,154 +113,10 @@ def next(item)
# Hash methods
- attr_reader :size
-
- # #entries is a method provided by Enumerable which calls #to_a,
- # so we have to not collide with that.
- def __entries__
- @entries
- end
-
- attr_reader :capacity
- attr_reader :max_entries
-
- alias_method :length, :size
-
- Entries = Rubinius::Tuple
-
- # Initial size of Hash. MUST be a power of 2.
- MIN_SIZE = 16
-
- # Allocate more storage when this full. This value grows with
- # the size of the Hash so that the max load factor is 0.75.
- MAX_ENTRIES = 12
-
- # Overridden in lib/1.8.7 or lib/1.9
- def self.[](*args)
- if args.size == 1
- obj = args.first
- if hash = Rubinius::Type.check_convert_type(obj, Hash, :to_hash)
- return allocate.replace(hash)
- elsif array = Rubinius::Type.check_convert_type(obj, Array, :to_ary)
- h = new
- array.each do |arr|
- next unless arr.respond_to? :to_ary
- arr = arr.to_ary
- next unless (1..2).include? arr.size
- h[arr.at(0)] = arr.at(1)
- end
- return h
- end
- end
-
- return new if args.empty?
-
- if args.size & 1 == 1
- raise ArgumentError, "Expected an even number, got #{args.length}"
- end
-
- hash = new
- i = 0
- total = args.size
-
- while i < total
- hash[args[i]] = args[i+1]
- i += 2
- end
-
- hash
- end
-
def self.try_convert(obj)
Rubinius::Type.try_convert obj, Hash, :to_hash
end
- def self.new_from_literal(size)
- new
- end
-
- # Creates a fully-formed instance of Hash.
- def self.allocate
- hash = super()
- Rubinius.privately { hash.__setup__ }
- hash
- end
-
- def ==(other)
- return true if self.equal? other
- unless other.kind_of? Hash
- return false unless other.respond_to? :to_hash
- return other == self
- end
-
- return false unless other.size == size
-
- Thread.detect_recursion self, other do
- each_item do |item|
- other_item = other.find_item(item.key)
-
- # Other doesn't even have this key
- return false unless other_item
-
- # Order of the comparison matters! We must compare our value with
- # the other Hash's value and not the other way around.
- unless Rubinius::Type::object_equal(item.value, other_item.value) or
- item.value == other_item.value
- return false
- end
- end
- end
- true
- end
-
- def eql?(other)
- # Just like ==, but uses eql? to compare values.
- return true if self.equal? other
- unless other.kind_of? Hash
- return false unless other.respond_to? :to_hash
- return other.eql?(self)
- end
-
- return false unless other.size == size
-
- Thread.detect_recursion self, other do
- each_item do |item|
- other_item = other.find_item(item.key)
-
- # Other doesn't even have this key
- return false unless other_item
-
- # Order of the comparison matters! We must compare our value with
- # the other Hash's value and not the other way around.
- unless Rubinius::Type::object_equal(item.value, other_item.value) or
- item.value.eql?(other_item.value)
- return false
- end
- end
- end
- true
- end
-
- def hash
- val = size
- Thread.detect_outermost_recursion self do
- each_item do |item|
- val ^= item.key.hash
- val ^= item.value.hash
- end
- end
-
- return val
- end
-
- def [](key)
- if item = find_item(key)
- item.value
- else
- default key
- end
- end
-
def []=(key, value)
Rubinius.check_frozen
@@ -301,14 +157,6 @@ def []=(key, value)
def assoc(key)
each_item { |e| return e.key, e.value if key == e.key }
- nil
- end
-
- def clear
- Rubinius.check_frozen
-
- __setup__
- self
end
def compare_by_identity
@@ -332,11 +180,6 @@ def default(key=undefined)
end
end
- def default=(value)
- @default_proc = nil
- @default = value
- end
-
def default_proc
@default_proc
end
@@ -380,15 +223,6 @@ def delete(key)
return yield(key) if block_given?
end
- def delete_if(&block)
- return to_enum(:delete_if) unless block_given?
-
- Rubinius.check_frozen
-
- select(&block).each { |k, v| delete k }
- self
- end
-
def each_item
return unless @state
@@ -415,27 +249,6 @@ def each
alias_method :each_pair, :each
- def each_key
- return to_enum(:each_key) unless block_given?
-
- each_item { |e| yield e.key }
- self
- end
-
- def each_value
- return to_enum(:each_value) unless block_given?
-
- each_item do |item|
- yield item.value
- end
- self
- end
-
- # Returns true if there are no entries.
- def empty?
- @size == 0
- end
-
def fetch(key, default=undefined)
if item = find_item(key)
return item.value
@@ -464,14 +277,7 @@ def flatten(level=1)
to_a.flatten(level)
end
- def key(value)
- each_item do |item|
- return item.key if item.value == value
- end
- nil
- end
-
- alias_method :index, :key
+ alias_method :key, :index
def keep_if(&block)
return to_enum(:keep_if) unless block_given?
@@ -502,60 +308,8 @@ def initialize(default=undefined, &block)
end
private :initialize
- def initialize_copy(other)
- replace other
- end
- private :initialize_copy
-
- def inspect
- out = []
- return '{...}' if Thread.detect_recursion self do
- each_item do |item|
- str = item.key.inspect
- str << '=>'
- str << item.value.inspect
- out << str
- end
- end
- "{#{out.join ', '}}"
- end
-
alias_method :to_s, :inspect
- def invert
- inverted = {}
- each_item do |item|
- inverted[item.value] = item.key
- end
- inverted
- end
-
- def key?(key)
- find_item(key) != nil
- end
-
- alias_method :has_key?, :key?
- alias_method :include?, :key?
- alias_method :member?, :key?
-
- # Calculates the +@entries+ slot given a key_hash value.
- def key_index(key_hash)
- key_hash & @mask
- end
- private :key_index
-
- def keys
- ary = []
- each_item do |item|
- ary << item.key
- end
- ary
- end
-
- def merge(other, &block)
- dup.merge!(other, &block)
- end
-
def merge!(other)
Rubinius.check_frozen
@@ -627,57 +381,6 @@ def redistribute(entries)
def rassoc(value)
each_item { |e| return e.key, e.value if value == e.value }
- nil
- end
-
- # Recalculates the cached key_hash values and reorders the entries
- # into a new +@entries+ vector. Does NOT change the size of the
- # hash. See +#redistribute+.
- def rehash
- capacity = @capacity
- entries = @entries
-
- @entries = Entries.new @capacity
-
- i = -1
- while (i += 1) < capacity
- next unless old = entries[i]
- while old
- old.link = nil if nxt = old.link
-
- index = key_index(old.key_hash = old.key.hash)
- if item = @entries[index]
- old.link = item
- end
- @entries[index] = old
-
- old = nxt
- end
- end
-
- self
- end
-
- def reject(&block)
- return to_enum(:reject) unless block_given?
-
- hsh = dup.delete_if(&block)
- hsh.taint if tainted?
- hsh
- end
-
- def reject!(&block)
- Rubinius.check_frozen
-
- return to_enum(:reject!) unless block_given?
-
- unless empty?
- size = @size
- delete_if(&block)
- return self if size != @size
- end
-
- nil
end
def replace(other)
@@ -707,6 +410,9 @@ def replace(other)
self
end
+ alias_method :initialize_copy, :replace
+ private :initialize_copy
+
def select
return to_enum(:select) unless block_given?
@@ -762,59 +468,9 @@ def __setup__(capacity=MIN_SIZE, max=MAX_ENTRIES, size=0)
end
private :__setup__
- def sort(&block)
- to_a.sort(&block)
- end
-
- def to_a
- ary = []
-
- each_item do |item|
- ary << [item.key, item.value]
- end
-
- ary
- end
-
# Returns an external iterator for the bins. See +Iterator+
def to_iter
Iterator.new @state
end
-
- def to_hash
- self
- end
-
- def value?(value)
- each_item do |item|
- return true if value == item.value
- end
- false
- end
-
- alias_method :has_value?, :value?
-
- def values
- ary = []
-
- each_item do |item|
- ary << item.value
- end
-
- ary
- end
-
- def values_at(*args)
- args.map do |key|
- if item = find_item(key)
- item.value
- else
- default key
- end
- end
- end
-
- alias_method :indexes, :values_at
- alias_method :indices, :values_at
end
end
1  kernel/common/load_order18.txt
View
@@ -17,6 +17,7 @@ tuple.rbc
exception.rbc
exception18.rbc
undefined.rbc
+hash.rbc
hash18.rbc
type.rbc
type18.rbc
1  kernel/common/load_order19.txt
View
@@ -18,6 +18,7 @@ tuple.rbc
exception.rbc
exception19.rbc
undefined.rbc
+hash.rbc
hash19.rbc
hash_hamt.rbc
type.rbc
Please sign in to comment.
Something went wrong with that request. Please try again.