diff options
Diffstat (limited to 'lib/weakref.rb')
| -rw-r--r-- | lib/weakref.rb | 101 |
1 files changed, 40 insertions, 61 deletions
diff --git a/lib/weakref.rb b/lib/weakref.rb index 3b5bcd1b8e..c7274f9664 100644 --- a/lib/weakref.rb +++ b/lib/weakref.rb @@ -1,80 +1,59 @@ -# Weak Reference class that does not bother GCing. +# frozen_string_literal: true +require "delegate" + +# Weak Reference class that allows a referenced object to be +# garbage-collected. +# +# A WeakRef may be used exactly like the object it references. # # Usage: -# foo = Object.new -# foo = Object.new -# p foo.to_s # original's class -# foo = WeakRef.new(foo) -# p foo.to_s # should be same class -# ObjectSpace.garbage_collect -# p foo.to_s # should raise exception (recycled) - -require "delegate" -require 'thread' +# +# foo = Object.new # create a new object instance +# p foo.to_s # original's class +# foo = WeakRef.new(foo) # reassign foo with WeakRef instance +# p foo.to_s # should be same class +# GC.start # start the garbage collector +# p foo.to_s # should raise exception (recycled) +# class WeakRef < Delegator + # The version string + VERSION = "0.1.4" + + ## + # RefError is raised when a referenced object has been recycled by the + # garbage collector class RefError < StandardError end - @@id_map = {} # obj -> [ref,...] - @@id_rev_map = {} # ref -> obj - @@mutex = Mutex.new - @@final = lambda {|id| - @@mutex.synchronize { - rids = @@id_map[id] - if rids - for rid in rids - @@id_rev_map.delete(rid) - end - @@id_map.delete(id) - end - rid = @@id_rev_map[id] - if rid - @@id_rev_map.delete(id) - @@id_map[rid].delete(id) - @@id_map.delete(rid) if @@id_map[rid].empty? - end - } - } + @@__map = ::ObjectSpace::WeakMap.new + + ## + # Creates a weak reference to +orig+ def initialize(orig) - @__id = orig.object_id - ObjectSpace.define_finalizer orig, @@final - ObjectSpace.define_finalizer self, @@final - @@mutex.synchronize { - @@id_map[@__id] = [] unless @@id_map[@__id] - } - @@id_map[@__id].push self.object_id - @@id_rev_map[self.object_id] = @__id + case orig + when true, false, nil + @delegate_sd_obj = orig + else + @@__map[self] = orig + end super end - def __getobj__ - unless @@id_rev_map[self.object_id] == @__id - Kernel::raise RefError, "Illegal Reference - probably recycled", Kernel::caller(2) - end - begin - ObjectSpace._id2ref(@__id) - rescue RangeError - Kernel::raise RefError, "Illegal Reference - probably recycled", Kernel::caller(2) - end + def __getobj__(&_block) # :nodoc: + @@__map[self] or defined?(@delegate_sd_obj) ? @delegate_sd_obj : + Kernel::raise(RefError, "Invalid Reference - probably recycled", Kernel::caller(2)) end - def __setobj__(obj) + + def __setobj__(obj) # :nodoc: end + ## + # Returns true if the referenced object is still alive. + def weakref_alive? - @@id_rev_map[self.object_id] == @__id + @@__map.key?(self) or defined?(@delegate_sd_obj) end end - -if __FILE__ == $0 -# require 'thread' - foo = Object.new - p foo.to_s # original's class - foo = WeakRef.new(foo) - p foo.to_s # should be same class - ObjectSpace.garbage_collect - ObjectSpace.garbage_collect - p foo.to_s # should raise exception (recycled) -end |
