diff options
author | yugui <yugui@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 2008-08-25 15:02:05 +0000 |
---|---|---|
committer | yugui <yugui@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 2008-08-25 15:02:05 +0000 |
commit | 0dc342de848a642ecce8db697b8fecd83a63e117 (patch) | |
tree | 2b7ed4724aff1f86073e4740134bda9c4aac1a39 /trunk/lib/weakref.rb | |
parent | ef70cf7138ab8034b5b806f466e4b484b24f0f88 (diff) |
added tag v1_9_0_4
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/tags/v1_9_0_4@18845 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
Diffstat (limited to 'trunk/lib/weakref.rb')
-rw-r--r-- | trunk/lib/weakref.rb | 80 |
1 files changed, 80 insertions, 0 deletions
diff --git a/trunk/lib/weakref.rb b/trunk/lib/weakref.rb new file mode 100644 index 0000000000..ba39242445 --- /dev/null +++ b/trunk/lib/weakref.rb @@ -0,0 +1,80 @@ +# Weak Reference class that does not bother GCing. +# +# 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' + +class WeakRef < Delegator + + 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 + } + } + + 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 + super + end + + def __getobj__ + unless @@id_rev_map[self.object_id] == @__id + Kernel::raise RefError, "Invalid Reference - probably recycled", Kernel::caller(2) + end + begin + ObjectSpace._id2ref(@__id) + rescue RangeError + Kernel::raise RefError, "Invalid Reference - probably recycled", Kernel::caller(2) + end + end + def __setobj__(obj) + end + + def weakref_alive? + @@id_rev_map[self.object_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 + ObjectSpace.garbage_collect + p foo.to_s # should raise exception (recycled) +end |