source: extensions/gsdl-video/trunk/installed/cmdline/lib/ruby/1.8/weakref.rb@ 18425

Last change on this file since 18425 was 18425, checked in by davidb, 15 years ago

Video extension to Greenstone

File size: 2.7 KB
Line 
1require "delegate"
2
3# WeakRef is a class to represent a reference to an object that is not seen by
4# the tracing phase of the garbage collector. This allows the referenced
5# object to be garbage collected as if nothing is referring to it. Because
6# WeakRef delegates method calls to the referenced object, it may be used in
7# place of that object, i.e. it is of the same duck type.
8#
9# Usage:
10#
11# foo = Object.new
12# foo = Object.new
13# p foo.to_s # original's class
14# foo = WeakRef.new(foo)
15# p foo.to_s # should be same class
16# ObjectSpace.garbage_collect
17# p foo.to_s # should raise exception (recycled)
18class WeakRef<Delegator
19
20 # RefError is raised if an object cannot be referenced by a WeakRef.
21 class RefError<StandardError
22 end
23
24 @@id_map = {} # obj -> [ref,...]
25 @@id_rev_map = {} # ref -> obj
26 @@final = lambda{|id|
27 __old_status = Thread.critical
28 Thread.critical = true
29 begin
30 rids = @@id_map[id]
31 if rids
32 for rid in rids
33 @@id_rev_map.delete(rid)
34 end
35 @@id_map.delete(id)
36 end
37 rid = @@id_rev_map[id]
38 if rid
39 @@id_rev_map.delete(id)
40 @@id_map[rid].delete(id)
41 @@id_map.delete(rid) if @@id_map[rid].empty?
42 end
43 ensure
44 Thread.critical = __old_status
45 end
46 }
47
48 # Create a new WeakRef from +orig+.
49 def initialize(orig)
50 super
51 __setobj__(orig)
52 end
53
54 # Return the object this WeakRef references. Raises RefError if the object
55 # has been garbage collected. The object returned is the object to which
56 # method calls are delegated (see Delegator).
57 def __getobj__
58 unless @@id_rev_map[self.__id__] == @__id
59 raise RefError, "Illegal Reference - probably recycled", caller(2)
60 end
61 begin
62 ObjectSpace._id2ref(@__id)
63 rescue RangeError
64 raise RefError, "Illegal Reference - probably recycled", caller(2)
65 end
66 end
67
68 def __setobj__(obj)
69 @__id = obj.__id__
70 __old_status = Thread.critical
71 begin
72 Thread.critical = true
73 unless @@id_rev_map.key?(self)
74 ObjectSpace.define_finalizer obj, @@final
75 ObjectSpace.define_finalizer self, @@final
76 end
77 @@id_map[@__id] = [] unless @@id_map[@__id]
78 ensure
79 Thread.critical = __old_status
80 end
81 @@id_map[@__id].push self.__id__
82 @@id_rev_map[self.__id__] = @__id
83 end
84
85 # Returns true if the referenced object still exists, and false if it has
86 # been garbage collected.
87 def weakref_alive?
88 @@id_rev_map[self.__id__] == @__id
89 end
90end
91
92if __FILE__ == $0
93 require 'thread'
94 foo = Object.new
95 p foo.to_s # original's class
96 foo = WeakRef.new(foo)
97 p foo.to_s # should be same class
98 ObjectSpace.garbage_collect
99 p foo.to_s # should raise exception (recycled)
100end
Note: See TracBrowser for help on using the repository browser.