1 # depends on: enumerable.rb misc.rb class.rb
6 # The result of #hash is not allowed to be larger than this.
14 if args.first.kind_of? Hash and args.length == 1
15 return new.replace(args.first)
18 raise ArgumentError, "Expected an even number, got #{args.length}" if args.length % 2 == 1
21 while args.length >= 2
29 def initialize(default = Undefined, &block)
30 if !default.equal?(Undefined) and block
31 raise ArgumentError, "Specify a default or a block, not both"
37 elsif !default.equal?(Undefined)
44 def initialize_copy(other)
47 private :initialize_copy
50 return true if self.equal? other
51 return false unless other.kind_of? Hash or other.respond_to? :to_hash
52 other = Type.coerce_to(other, Hash, :to_hash)
53 return false unless other.size == size
54 # Pickaxe claims that defaults are compared, but MRI 1.8.[46] doesn't actually do that
55 # return false unless other.default == default
57 return false unless other[k] == self[k]
63 # looks for a key in a bin found by hash_entry
65 def search_bin(entry,hash,key)
67 cur_hash, cur_key, cur_val, nxt = *entry
69 if cur_hash == hash and key.eql?(cur_key)
79 def fetch(key, default = Undefined)
80 entry, hash, = hash_entry key
81 entry = search_bin(entry,hash,key)
82 return entry[2] if(entry != Undefined)
84 return yield(key) if block_given?
85 return default if !default.equal?(Undefined)
86 raise IndexError, 'Key not found'
90 entry, hash, = hash_entry key
91 entry = search_bin(entry,hash,key)
92 return entry[2] if(entry != Undefined)
97 def set_key_cv(key, val)
98 key = key.dup if key.kind_of?(String)
102 entry, hash, bin = hash_entry key
106 cur_hash, cur_key, cur_val, nxt = *entry
108 # Check if this entry is for the key in question
109 if cur_hash == hash and key.eql?(cur_key)
127 @values.put bin, entry
133 alias_method :store, :set_key_cv
135 def self.after_loaded()
136 alias_method :[], :get_key_cv
137 alias_method :[]=, :set_key_cv
146 new_hash.freeze if self.frozen?
150 def default(key = Undefined)
151 # current MRI documentation comment is wrong. Actual behavior is:
152 # Hash.new { 1 }.default #=> nil
154 return key.equal?(Undefined) ? nil : @default.call(self, key)
161 @default_proc = false
166 return @default if @default_proc
171 entry, hash, bin = hash_entry key
175 cur_hash, cur_key, val, nxt = *entry
177 # Check if this entry is for the key in question
178 if cur_hash == hash and key.eql?(cur_key)
180 # Ok, relink the other entries, leaving this one out.
187 @entries = @entries - 1
196 return yield(key) if block_given?
201 raise LocalJumpError, "no block given" unless block_given? or empty?
203 # Do this in 2 steps, so we're not altering the structure while we walk it.
204 # TODO: I'd like to write it like this:
205 # select(&block).each { |k, v| delete k }
207 each_pair { |k, v| to_del << k if yield(k, v) }
208 to_del.each { |k| delete k }
213 new_hash = self.class.new
214 new_hash.send :initialize_copy, self
215 new_hash.taint if self.tainted?
225 raise LocalJumpError, "no block given" unless block_given? or empty?
227 @values.each do |tup|
229 yield([tup.at(1), tup.at(2)])
237 raise LocalJumpError, "no block given" unless block_given? or empty?
239 @values.each do |tup|
241 yield(tup.at(1), tup.at(2))
248 def each_value(&block)
258 each_pair { |k, v| return k if v == val }
263 # recursively_inspect
264 return '{...}' if RecursionGuard.inspecting?(self)
267 RecursionGuard.inspect(self) do
268 each_pair do |key, val|
281 each_pair { |k, v| out[v] = k }
286 entry, hash, = hash_entry key
288 while entry do # REFACTOR this loop is duplicated many times
289 cur_hash, cur_key, cur_val, nxt = *entry
291 return true if cur_hash == hash and key.eql?(cur_key)
299 alias_method :has_key?, :key?
300 alias_method :include?, :key?
301 alias_method :member?, :key?
305 @values.each do |tup|
314 def merge(other, &block)
315 dup.merge!(other, &block)
319 other = Type.coerce_to(other, Hash, :to_hash)
320 other.each_pair do |k, v|
321 if block_given? and self.key? k
322 self[k] = yield(k, self[k], v)
329 alias_method :update, :merge!
331 # TODO: Improve the performance of this. NOTE, however
332 # that #rehash is fundamentally impossible to do via a
333 # primitive because classes (e.g. Array) can and do
334 # redefine the #hash method. That method is not available
335 # to primitive C code because we do not call back to Ruby
338 each_pair { |k, v| out[k] = v }
343 dup.delete_if(&block)
349 return nil if old_size == size
354 other = Type.coerce_to(other, Hash, :to_hash)
355 return self if self.equal? other
357 other.each_pair { |k, v| self[k] = v }
358 if other.default_proc
359 @default = other.default_proc
362 @default = other.default
363 @default_proc = false
369 raise LocalJumpError, "no block given" unless block_given? or empty?
372 each_pair { |k, v| out << [k, v] if yield(k, v) }
377 return default(nil) if empty?
379 # TODO: keep around for efficiency? It's not much faster though.
383 # tup = @values.at(i)
387 # out = [key, self[key]]
392 out = [key, self[key]]
400 alias_method :length, :size
421 alias_method :has_value?, :value?
425 @values.each do |tup|
435 args.collect { |key| self[key] }
437 alias_method :indexes, :values_at
438 alias_method :indices, :values_at
442 hash = hash % HASH_MAX unless hash.kind_of? Fixnum
444 bin = hash & (@bins - 1)
446 entry = @values.at bin
448 return entry, hash, bin