Guest User

Untitled

a guest
Jun 18th, 2018
107
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 2.82 KB | None | 0 0
  1. require "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)
  18. class 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
  90. end
  91.  
  92. if __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)
  100. end
Add Comment
Please, Sign In to add comment