Class: Foobara::WeakObjectHash
- Inherits:
-
Object
- Object
- Foobara::WeakObjectHash
- Defined in:
- foobara-0.2.2/projects/weak_object_hash/src/weak_object_hash.rb,
foobara-0.2.2/projects/weak_object_hash/lib/foobara/weak_object_hash.rb
Overview
TODO: a possible optimization: have a certain number of records before the Weakref approach kicks in that way we don’t just immediately clear out useful information without any actual memory burden
Defined Under Namespace
Classes: ClosedError
Instance Method Summary collapse
- #[](object) ⇒ Object
- #[]=(object, value) ⇒ Object
- #clear ⇒ Object
- #close! ⇒ Object
- #closed? ⇒ Boolean
- #delete(object) ⇒ Object
- #each_pair ⇒ Object
- #empty? ⇒ Boolean
-
#initialize(skip_finalizer: false) ⇒ WeakObjectHash
constructor
A new instance of WeakObjectHash.
- #keys ⇒ Object
- #size ⇒ Object
- #skip_finalizer? ⇒ Boolean
- #values ⇒ Object
Constructor Details
#initialize(skip_finalizer: false) ⇒ WeakObjectHash
Returns a new instance of WeakObjectHash.
9 10 11 12 13 14 15 |
# File 'foobara-0.2.2/projects/weak_object_hash/src/weak_object_hash.rb', line 9 def initialize(skip_finalizer: false) if skip_finalizer self.skip_finalizer = true end self.monitor = Monitor.new self.object_ids_to_weak_refs_and_values = {} end |
Instance Method Details
#[](object) ⇒ Object
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 71 72 73 74 |
# File 'foobara-0.2.2/projects/weak_object_hash/src/weak_object_hash.rb', line 38 def [](object) object_id = object.object_id if closed? raise ClosedError, "Cannot retrieve objects from a closed WeakObjectHash" end monitor.synchronize do pair = object_ids_to_weak_refs_and_values[object_id] return nil unless pair weak_ref, value = pair if weak_ref.weakref_alive? if skip_finalizer? if weak_ref.__getobj__ == object value else # :nocov: object_ids_to_weak_refs_and_values.delete(object_id) nil # :nocov: end else value end else # Seems unreachable... if it's been garbage collected how could we have a reference to the object # to pass it in? # :nocov: object_ids_to_weak_refs_and_values.delete(object_id) nil # :nocov: end end end |
#[]=(object, value) ⇒ Object
17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 |
# File 'foobara-0.2.2/projects/weak_object_hash/src/weak_object_hash.rb', line 17 def []=(object, value) object_id = object.object_id weak_ref = WeakRef.new(object) if closed? raise ClosedError, "Cannot add objects to a closed WeakObjectHash" end monitor.synchronize do delete(object) object_ids_to_weak_refs_and_values[object_id] = [weak_ref, value] unless skip_finalizer? ObjectSpace.define_finalizer(object, finalizer_proc) end value end end |
#clear ⇒ Object
189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 |
# File 'foobara-0.2.2/projects/weak_object_hash/src/weak_object_hash.rb', line 189 def clear monitor.synchronize do unless skip_finalizer? object_ids_to_weak_refs_and_values.each_value do |pair| weak_ref = pair.first if weak_ref.weakref_alive? ObjectSpace.undefine_finalizer(weak_ref.__getobj__) end end end object_ids_to_weak_refs_and_values.clear end end |
#close! ⇒ Object
175 176 177 178 179 180 181 182 183 184 185 186 187 |
# File 'foobara-0.2.2/projects/weak_object_hash/src/weak_object_hash.rb', line 175 def close! if closed? raise ClosedError, "Already closed" end monitor.synchronize do self.closed = true clear @finalizer_proc = nil self.object_ids_to_weak_refs_and_values = nil self.monitor = nil end end |
#closed? ⇒ Boolean
205 206 207 |
# File 'foobara-0.2.2/projects/weak_object_hash/src/weak_object_hash.rb', line 205 def closed? closed end |
#delete(object) ⇒ Object
76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 |
# File 'foobara-0.2.2/projects/weak_object_hash/src/weak_object_hash.rb', line 76 def delete(object) object_id = object.object_id monitor.synchronize do pair = object_ids_to_weak_refs_and_values.delete(object_id) return nil unless pair weak_ref, value = pair if weak_ref.weakref_alive? if skip_finalizer? if weak_ref.__getobj__ == object value end else # Hmmm, there's seemingly no safe way to remove the finalizer for the previous entry # if it exists. This is because we can only remove all finalizers on object. Not only # the ones we've created. # We will just do this anyway with that caveat and maybe make this configuratble in the future. unless skip_finalizer? ObjectSpace.undefine_finalizer(object) end value end end end end |
#each_pair ⇒ Object
107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 |
# File 'foobara-0.2.2/projects/weak_object_hash/src/weak_object_hash.rb', line 107 def each_pair monitor.synchronize do object_ids_to_weak_refs_and_values.each_pair do |object_id, pair| weak_ref, value = pair if weak_ref.weakref_alive? yield weak_ref.__getobj__, value else object_ids_to_weak_refs_and_values.delete(object_id) end end end self end |
#empty? ⇒ Boolean
171 172 173 |
# File 'foobara-0.2.2/projects/weak_object_hash/src/weak_object_hash.rb', line 171 def empty? size == 0 end |
#keys ⇒ Object
135 136 137 138 139 140 141 142 143 144 145 |
# File 'foobara-0.2.2/projects/weak_object_hash/src/weak_object_hash.rb', line 135 def keys keys = [] monitor.synchronize do each_pair do |key, _value| keys << key end end keys end |
#size ⇒ Object
147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 |
# File 'foobara-0.2.2/projects/weak_object_hash/src/weak_object_hash.rb', line 147 def size size = 0 to_delete = nil monitor.synchronize do object_ids_to_weak_refs_and_values.each_pair do |object_id, pair| weak_ref = pair.first if weak_ref.weakref_alive? size += 1 else to_delete ||= [] to_delete << object_id end end to_delete&.each do |object_id| object_ids_to_weak_refs_and_values.delete(object_id) end end size end |
#skip_finalizer? ⇒ Boolean
209 210 211 |
# File 'foobara-0.2.2/projects/weak_object_hash/src/weak_object_hash.rb', line 209 def skip_finalizer? @skip_finalizer end |
#values ⇒ Object
123 124 125 126 127 128 129 130 131 132 133 |
# File 'foobara-0.2.2/projects/weak_object_hash/src/weak_object_hash.rb', line 123 def values values = [] monitor.synchronize do each_pair do |_key, value| values << value end end values end |