lib/weakref.rb
DEFINITIONS
This source file includes following functions.
1 # Weak Reference class that does not bother GCing.
2 #
3 # Usage:
4 # foo = Object.new
5 # foo = Object.new
6 # p foo.to_s # original's class
7 # foo = WeakRef.new(foo)
8 # p foo.to_s # should be same class
9 # ObjectSpace.garbage_collect
10 # p foo.to_s # should raise exception (recycled)
11
12 require "delegate"
13
14 class WeakRef<Delegator
15
16 class RefError<StandardError
17 end
18
19 ID_MAP = {} # obj -> [ref,...]
20 ID_REV_MAP = {} # ref -> obj
21 @@final = lambda{|id|
22 __old_status = Thread.critical
23 Thread.critical = true
24 begin
25 rids = ID_MAP[id]
26 if rids
27 for rid in rids
28 ID_REV_MAP[rid] = nil
29 end
30 ID_MAP[id] = nil
31 end
32 rid = ID_REV_MAP[id]
33 if rid
34 ID_REV_MAP[id] = nil
35 ID_MAP[rid].delete(id)
36 ID_MAP[rid] = nil if ID_MAP[rid].empty?
37 end
38 ensure
39 Thread.critical = __old_status
40 end
41 }
42
43 def initialize(orig)
44 super
45 @__id = orig.__id__
46 ObjectSpace.define_finalizer orig, @@final
47 ObjectSpace.define_finalizer self, @@final
48 __old_status = Thread.critical
49 begin
50 Thread.critical = true
51 ID_MAP[@__id] = [] unless ID_MAP[@__id]
52 ensure
53 Thread.critical = __old_status
54 end
55 ID_MAP[@__id].push self.__id__
56 ID_REV_MAP[self.id] = @__id
57 end
58
59 def __getobj__
60 unless ID_MAP[@__id]
61 raise RefError, "Illegal Reference - probably recycled", caller(2)
62 end
63 begin
64 ObjectSpace._id2ref(@__id)
65 rescue RangeError
66 raise RefError, "Illegal Reference - probably recycled", caller(2)
67 end
68 end
69
70 def weakref_alive?
71 if ID_MAP[@__id]
72 true
73 else
74 false
75 end
76 end
77 end
78
79 if __FILE__ == $0
80 require 'thread'
81 foo = Object.new
82 p foo.to_s # original's class
83 foo = WeakRef.new(foo)
84 p foo.to_s # should be same class
85 ObjectSpace.garbage_collect
86 p foo.to_s # should raise exception (recycled)
87 end