On Wed, Jan 25, 2006 at 12:58:04AM +0900, Jeffrey Schwab wrote:
> >   def reclaim_value(value_id)
> >     @cache.delete @rev_cache[value_id]
> >     @rev_cache.delete value_id
> >   end
> >
> >   def []=( key, value )
> >      @rev_cache[value.object_id] = key
> >      @cache[key] = value.object_id
> >      ObjectSpace.define_finalizer(value, @reclaim_method)
> >   end
> >end
[...] 
> I like your technique, but suppose the same value is stored for more 
> than one key in a WeakCache?  When the value is finalized, only the last 
> key will be removed from the cache.  I think it might be better to let 
> the reverse cache hold more than one key per value.

You're very right, I should have written something like

class WeakCache
   attr_reader :cache
   def initialize( cache = Hash.new )
      @cache = cache
      @rev_cache = Hash.new{|h,k| h[k] = {}}
      @reclaim_lambda = lambda do |value_id| 
        if @rev_cache.has_key? value_id
          @rev_cache[value_id].each_key{|key| @cache.delete key}
          @rev_cache.delete value_id
        end
      end
   end

   def []( key )
      value_id = @cache[key]
      return ObjectSpace._id2ref(value_id) unless value_id.nil?
      nil
   end

   def []=( key, value )
      @rev_cache[value.object_id][key] = true
      @cache[key] = value.object_id
      ObjectSpace.define_finalizer(value, @reclaim_lambda)
   end
end


puts "=" * 20
c = WeakCache.new
puts c.cache.size
100000.times{|i| c[i] = (i % 1000).to_s}
GC.start
puts c.cache.size
puts "=" * 20
# >> ====================
# >> 0
# >> 3
# >> ====================



(not thread-safe yet though)

-- 
Mauricio Fernandez