summaryrefslogtreecommitdiff
path: root/trunk/lib/weakref.rb
diff options
context:
space:
mode:
authoryugui <yugui@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2008-08-25 15:02:05 +0000
committeryugui <yugui@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2008-08-25 15:02:05 +0000
commit0dc342de848a642ecce8db697b8fecd83a63e117 (patch)
tree2b7ed4724aff1f86073e4740134bda9c4aac1a39 /trunk/lib/weakref.rb
parentef70cf7138ab8034b5b806f466e4b484b24f0f88 (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.rb80
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