mirror of
https://github.com/mistergibson/gxg-web-client.git
synced 2026-08-15 11:34:29 -07:00
134 lines
3.2 KiB
Ruby
134 lines
3.2 KiB
Ruby
##
|
|
# 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
|