mirror of
				https://github.com/ruby/ruby.git
				synced 2022-11-09 12:17:21 -05:00 
			
		
		
		
	 173f1e1563
			
		
	
	
		173f1e1563
		
	
	
	
	
		
			
			change "illegal" to "invalid" in a context which doesn' t against a law. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@14736 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
		
			
				
	
	
		
			80 lines
		
	
	
	
		
			1.8 KiB
		
	
	
	
		
			Ruby
		
	
	
	
	
	
			
		
		
	
	
			80 lines
		
	
	
	
		
			1.8 KiB
		
	
	
	
		
			Ruby
		
	
	
	
	
	
| # 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
 |