From 11dbedfaad4a9a9521ece2198a8dc491678b1902 Mon Sep 17 00:00:00 2001 From: shyouhei Date: Wed, 29 Aug 2007 04:06:12 +0000 Subject: add tag v1_8_6_5001 git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/tags/v1_8_6_5001@13304 b2dd03c8-39d4-4d8f-98ff-823fe69b080e --- ruby_1_8_6/lib/weakref.rb | 100 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 100 insertions(+) create mode 100644 ruby_1_8_6/lib/weakref.rb (limited to 'ruby_1_8_6/lib/weakref.rb') diff --git a/ruby_1_8_6/lib/weakref.rb b/ruby_1_8_6/lib/weakref.rb new file mode 100644 index 0000000000..591819c948 --- /dev/null +++ b/ruby_1_8_6/lib/weakref.rb @@ -0,0 +1,100 @@ +require "delegate" + +# WeakRef is a class to represent a reference to an object that is not seen by +# the tracing phase of the garbage collector. This allows the referenced +# object to be garbage collected as if nothing is referring to it. Because +# WeakRef delegates method calls to the referenced object, it may be used in +# place of that object, i.e. it is of the same duck type. +# +# 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) +class WeakRef [ref,...] + @@id_rev_map = {} # ref -> obj + @@final = lambda{|id| + __old_status = Thread.critical + Thread.critical = true + begin + 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 + ensure + Thread.critical = __old_status + end + } + + # Create a new WeakRef from +orig+. + def initialize(orig) + super + __setobj__(orig) + end + + # Return the object this WeakRef references. Raises RefError if the object + # has been garbage collected. The object returned is the object to which + # method calls are delegated (see Delegator). + def __getobj__ + unless @@id_rev_map[self.__id__] == @__id + raise RefError, "Illegal Reference - probably recycled", caller(2) + end + begin + ObjectSpace._id2ref(@__id) + rescue RangeError + raise RefError, "Illegal Reference - probably recycled", caller(2) + end + end + + def __setobj__(obj) + @__id = obj.__id__ + __old_status = Thread.critical + begin + Thread.critical = true + unless @@id_rev_map.key?(self) + ObjectSpace.define_finalizer obj, @@final + ObjectSpace.define_finalizer self, @@final + end + @@id_map[@__id] = [] unless @@id_map[@__id] + ensure + Thread.critical = __old_status + end + @@id_map[@__id].push self.__id__ + @@id_rev_map[self.__id__] = @__id + end + + # Returns true if the referenced object still exists, and false if it has + # been garbage collected. + def weakref_alive? + @@id_rev_map[self.__id__] == @__id + 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 + p foo.to_s # should raise exception (recycled) +end -- cgit v1.2.3