Advertisement
Iavra

[Ace] Weak Reference

Jun 5th, 2015
352
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Ruby 5.54 KB | None | 0 0
  1. #==============================================================================
  2. # Iavra Weak Reference 1.01
  3. # -----------------------------------------------------------------------------
  4. # Description:
  5. # Allows access to objects without holding a direct reference. If an object is
  6. # only referenced by weak references, it may be garbage collected at any time.
  7. # -----------------------------------------------------------------------------
  8. # Prerequisites:
  9. # None
  10. # -----------------------------------------------------------------------------
  11. # How to Use:
  12. # A weak reference to <object> is created and accessed like this:
  13. #
  14. # weakref = IAVRA::WeakRef.new(<object>)
  15. # weakref.object
  16. #
  17. # The object method will return nil if <object> is no longer accessible. Objects
  18. # keep a list of backreferences to WeakRef objects referencing them. When a
  19. # WeakRef is garbage collected, it will remove itself from the backreferences
  20. # of the object it was referencing.
  21. #
  22. # Note: WeakRefs should NOT be stored in savefiles. The finalizers might not be
  23. # serializable and the list of references is not stored in a persistant way.
  24. # Also, finalizers are not threadsafe, so if you are insane enough to attempt
  25. # any kind of multithreading, you would need to extend the methods with some
  26. # kind of lock or mutex.
  27. # -----------------------------------------------------------------------------
  28. # Terms of Use:
  29. # Free to use for both commercial and non-commercial games. Please give credit.
  30. # -----------------------------------------------------------------------------
  31. # Credits:
  32. # Iavra
  33. # -----------------------------------------------------------------------------
  34. # Changelog:
  35. # - 1.00: First version.
  36. # - 1.01: Added a hash method to ensure equality in hashs.
  37. #==============================================================================
  38.  
  39. ($imported ||= {})[:iavra_weakref] = true
  40.  
  41. module IAVRA
  42.    
  43.     #============================================================================
  44.     # ▼ IAVRA::WeakRef
  45.     #============================================================================
  46.    
  47.     class WeakRef
  48.        
  49.         #==========================================================================
  50.         # A class variable, that is used to keep track of active WeakRef objects
  51.         # and the objects they are referencing.
  52.         #==========================================================================
  53.        
  54.         @@refs = {}
  55.        
  56.         #==========================================================================
  57.         # This will be registered as a finalizer for every new WeakRef instance.
  58.         #==========================================================================
  59.        
  60.         @@finalizer = lambda {|object_id| cleanup(object_id)}
  61.        
  62.         #==========================================================================
  63.         # When a WeakRef instance is garbage collected, we remove it from our list.
  64.         # Also, we lookup the object it was referencing to and remove the reference
  65.         # from its backreferences.
  66.         #==========================================================================
  67.        
  68.         def self.cleanup(object_id)
  69.             return if (ref_object_id = @@refs.delete(object_id)).nil?
  70.             ref_object = ObjectSpace._id2ref(ref_object_id) rescue return
  71.             (ref_object.__iavra_backrefs__ || return).delete(object_id)
  72.         end
  73.        
  74.         #==========================================================================
  75.         # We only store the object id of the referenced object. Also, we store our
  76.         # own object id in its backreferences. Finally, we keep track by updating
  77.         # the class variable and set our finalizer.
  78.         #==========================================================================
  79.        
  80.         def initialize(ref_object)
  81.             @ref_object_id = ref_object.__id__
  82.             (ref_object.__iavra_backrefs__ ||= []) << object_id
  83.             @@refs[object_id] = @ref_object_id
  84.             ObjectSpace.define_finalizer(self, @@finalizer)
  85.         end
  86.        
  87.         #==========================================================================
  88.         # We make a lookup on the referenced object and check its backreferences,
  89.         # to make sure that it's still the same. This is done, because object ids
  90.         # may be re-used after an object got garbage collected.
  91.         #==========================================================================
  92.        
  93.         def object
  94.             obj = ObjectSpace._id2ref(@ref_object_id)
  95.             obj if (obj.__iavra_backrefs__ || []).include?(object_id)
  96.         rescue RangeError
  97.             nil
  98.         end
  99.        
  100.         #==========================================================================
  101.         # This is mainly for debugging and shows, that we are a reference and what
  102.         # object we are pointing to.
  103.         #==========================================================================
  104.        
  105.         def inspect
  106.             "<##{self.class.name}: #{(obj = object) ? obj.inspect : "##{@ref_object_id} (not accessible)"}>"
  107.         end
  108.  
  109.         #==========================================================================
  110.         # Overridden hash method to check for equality when used as a hash key.
  111.         #==========================================================================
  112.        
  113.         def hash
  114.             object.hash
  115.         end
  116.  
  117.     end
  118.        
  119. end
  120.  
  121. #==============================================================================
  122. # ▼ Object
  123. # -----------------------------------------------------------------------------
  124. # I admit, this is lazy, but the cleaner way would be more performance heavy,
  125. # as i would need to dynamically add instance variable to referenced objects
  126. # via instance_variable_set and read them via instance_variable_get.
  127. #==============================================================================
  128.  
  129. class Object
  130.     attr_accessor :__iavra_backrefs__
  131. end
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement