blob: 93b2c65ecd1bd17ef502c96c785a4fad5f5a28f7 (
plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
|
# Weak Reference class that does not bother GCing.
#
# Usage:
# foo = Object.new
# foo.hash
# foo = WeakRef.new(foo)
# foo.hash
# ObjectSpace.garbage_collect
# foo.hash # => Raises WeakRef::RefError (because original GC'ed)
require "delegate"
class WeakRef<Delegater
Exception :RefError
ID_MAP = {}
ID_REV_MAP = {}
ObjectSpace.add_finalizer(lambda{|id|
rid = ID_MAP[id]
if rid
ID_REV_MAP[rid] = nil
ID_MAP[id] = nil
end
rid = ID_REV_MAP[id]
if rid
ID_REV_MAP[id] = nil
ID_MAP[rid] = nil
end
})
def initialize(orig)
super
@id = orig.id
ObjectSpace.call_finalizer orig
ID_MAP[@id] = self.id
ID_REV_MAP[self.id] = @id
end
def __getobj__
unless ID_MAP[@id]
$@ = caller(1)
$! = RefError.new("Illegal Reference - probably recycled")
raise
end
ObjectSpace.id2ref(@id)
# ObjectSpace.each_object do |obj|
# return obj if obj.id == @id
# end
end
def weakref_alive?
if ID_MAP[@id]
true
else
false
end
end
def []
__getobj__
end
end
foo = Object.new
p foo.hash
foo = WeakRef.new(foo)
p foo.hash
ObjectSpace.garbage_collect
p foo.hash
|