core/lookup_table.rb
##
# A LookupTable is similar to a Hash in that keys are used to set and
# reference values. However, unlike Hash, whether a key matches an
# entry in LookupTable is determined by using the == comparison operator
# in C code. In effect, two keys are equal if they are the same pointer.
#
# NOTE: the value used to determine the bin is the "pointer" value of
# key >> 2. This makes it possible to calculate the bin from Ruby with
# the same result as in C. For example:
#
# l = LookupTable.new
# loc = :a.hash & (l.bins - 1) # => 12
# class LookupTable
# def show
# @values
# end
# end
#
# l[:a] = 1
# l.show # => #<Tuple: nil, ..., nil, #<Bucket: @key=>:a, @value=>1,
# @next=>nil>, nil, nil, nil>
#
# where ... is ten "nil, " entries.
#
# LookupTable is intended to be used with Symbol or Fixnum keys because
# it is a strict identity map. Usage of Strings as keys will likely result
# in strange behavior.
# LookupTable is NOT intended to be used generally like Hash.
module Rubinius
class LookupTable
include Enumerable
class Bucket
attr_reader :key
attr_reader :value
attr_reader :next
end
attr_reader :values
attr_reader :bins
attr_reader_specific :entries, :size
alias_method :length, :size
def self.allocate
Rubinius.primitive :lookuptable_allocate
raise PrimitiveFailure, "LookupTable.allocate primitive failed"
end
def initialize(hash=nil)
return unless hash
hash.each do |k, v|
self[k] = v
end
end
private :initialize
def duplicate
Rubinius.primitive :lookuptable_duplicate
raise PrimitiveFailure, "LookupTable#duplicate primitive failed"
end
def dup
copy = duplicate
Rubinius.privately do
copy.initialize_copy self
end
copy
end
alias_method :clone, :dup
def fetch(key, return_on_failure)
Rubinius.primitive :lookuptable_fetch
raise PrimitiveFailure, "LookupTable#fetch primitive failed"
end
def key?(key)
Rubinius.primitive :lookuptable_has_key
raise PrimitiveFailure, "LookupTable#key? primitive failed"
end
alias_method :has_key?, :key?
alias_method :include?, :key?
alias_method :member?, :key?
def delete(key)
Rubinius.primitive :lookuptable_delete
raise PrimitiveFailure, "LookupTable#delete primitive failed"
end
def keys
Rubinius.primitive :lookuptable_keys
raise PrimitiveFailure, "LookupTable#keys primitive failed"
end
def values
Rubinius.primitive :lookuptable_values
raise PrimitiveFailure, "LookupTable#values primitive failed"
end
def each
max = @bins
i = 0
vals = @values
while i < max
entry = vals.at(i)
while entry
yield entry.key, entry.value
entry = entry.next
end
i += 1
end
self
end
def empty?
@entries == 0
end
def to_s
"#<#{self.class}:0x#{object_id.to_s(16)} #{entries} entries>"
end
def inspect
ents = collect { |k, v| " #{k.inspect}=>#{v.inspect}" }.join(",")
"#<#{self.class}#{ents}>"
end
end
end