Class: Foobara::WeakObjectSet
- Inherits:
-
Object
- Object
- Foobara::WeakObjectSet
- Includes:
- Enumerable
- Defined in:
- foobara-0.2.7/projects/weak_object_set/src/weak_object_set.rb,
foobara-0.2.7/projects/weak_object_set/lib/foobara/weak_object_set.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: GarbageCleaner
Instance Attribute Summary collapse
-
#closed ⇒ Object
Returns the value of attribute closed.
- #garbage_cleaner ⇒ Object
-
#key_method ⇒ Object
Returns the value of attribute key_method.
-
#key_to_object_id ⇒ Object
Returns the value of attribute key_to_object_id.
-
#monitor ⇒ Object
Returns the value of attribute monitor.
-
#object_id_to_key ⇒ Object
Returns the value of attribute object_id_to_key.
-
#objects ⇒ Object
Returns the value of attribute objects.
Instance Method Summary collapse
- #<<(object) ⇒ Object
- #[](object_or_object_id) ⇒ Object
- #clear ⇒ Object
- #close ⇒ Object
- #closed? ⇒ Boolean
- #delete(object_or_object_id) ⇒ Object
- #each ⇒ Object
- #empty? ⇒ Boolean
- #find_by_key(key) ⇒ Object
-
#initialize(key_method = nil) ⇒ WeakObjectSet
constructor
A new instance of WeakObjectSet.
- #ref_for(object_or_object_id) ⇒ Object
- #size ⇒ Object
- #stop_garbage_cleaner ⇒ Object
Constructor Details
#initialize(key_method = nil) ⇒ WeakObjectSet
Returns a new instance of WeakObjectSet.
90 91 92 93 94 |
# File 'projects/weak_object_set/src/weak_object_set.rb', line 90 def initialize(key_method = nil) self.key_method = key_method self.monitor = Monitor.new clear end |
Instance Attribute Details
#closed ⇒ Object
Returns the value of attribute closed.
87 88 89 |
# File 'projects/weak_object_set/src/weak_object_set.rb', line 87 def closed @closed end |
#garbage_cleaner ⇒ Object
152 153 154 155 156 157 158 |
# File 'projects/weak_object_set/src/weak_object_set.rb', line 152 def garbage_cleaner @garbage_cleaner ||= begin queue = Queue.new GarbageCleaner.new(self, queue) end end |
#key_method ⇒ Object
Returns the value of attribute key_method.
87 88 89 |
# File 'projects/weak_object_set/src/weak_object_set.rb', line 87 def key_method @key_method end |
#key_to_object_id ⇒ Object
Returns the value of attribute key_to_object_id.
87 88 89 |
# File 'projects/weak_object_set/src/weak_object_set.rb', line 87 def key_to_object_id @key_to_object_id end |
#monitor ⇒ Object
Returns the value of attribute monitor.
87 88 89 |
# File 'projects/weak_object_set/src/weak_object_set.rb', line 87 def monitor @monitor end |
#object_id_to_key ⇒ Object
Returns the value of attribute object_id_to_key.
87 88 89 |
# File 'projects/weak_object_set/src/weak_object_set.rb', line 87 def object_id_to_key @object_id_to_key end |
#objects ⇒ Object
Returns the value of attribute objects.
87 88 89 |
# File 'projects/weak_object_set/src/weak_object_set.rb', line 87 def objects @objects end |
Instance Method Details
#<<(object) ⇒ Object
160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 |
# File 'projects/weak_object_set/src/weak_object_set.rb', line 160 def <<(object) if closed? # :nocov: raise "Cannot add objects to a closed WeakObjectSet" # :nocov: end object_id = object.object_id monitor.synchronize do existing_object = self[object_id] if existing_object if key_method key = object.send(key_method) old_key = object_id_to_key[object_id] if key != old_key key_to_object_id.delete(old_key) if key key_to_object_id[key] = object_id object_id_to_key[object_id] = key else object_id_to_key.delete(object_id) end end end else garbage_cleaner.track(object) if key_method key = object.send(key_method) if key existing_record_object_id = key_to_object_id[key] if existing_record_object_id # Sometimes this path is hit in the test suite and sometimes not, depending on # non-deterministic behavior of the garbage collector # :nocov: delete(existing_record_object_id) # :nocov: end key_to_object_id[key] = object_id object_id_to_key[object_id] = key end end objects[object_id] = WeakRef.new(object) object end end end |
#[](object_or_object_id) ⇒ Object
96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 |
# File 'projects/weak_object_set/src/weak_object_set.rb', line 96 def [](object_or_object_id) monitor.synchronize do ref = ref_for(object_or_object_id) # TODO: is this necessary? Why not check weakref_alive? now that we're in a mutex? object = begin ref&.__getobj__ rescue WeakRef::RefError # :nocov: nil # :nocov: end if ref&.weakref_alive? object end end end |
#clear ⇒ Object
273 274 275 276 277 278 279 280 281 282 283 284 |
# File 'projects/weak_object_set/src/weak_object_set.rb', line 273 def clear monitor.synchronize do stop_garbage_cleaner self.objects = {} if key_method self.key_to_object_id = {} self.object_id_to_key = {} end end end |
#close ⇒ Object
253 254 255 256 257 258 |
# File 'projects/weak_object_set/src/weak_object_set.rb', line 253 def close raise if closed? self.closed = true stop_garbage_cleaner end |
#closed? ⇒ Boolean
286 287 288 |
# File 'projects/weak_object_set/src/weak_object_set.rb', line 286 def closed? closed end |
#delete(object_or_object_id) ⇒ Object
217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 |
# File 'projects/weak_object_set/src/weak_object_set.rb', line 217 def delete(object_or_object_id) object_id = if object_or_object_id.is_a?(::Integer) object_or_object_id else object_or_object_id.object_id end monitor.synchronize do if key_method key = object_id_to_key.delete(object_id) if key key_to_object_id.delete(key) end end objects.delete(object_id) end end |
#each ⇒ Object
125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 |
# File 'projects/weak_object_set/src/weak_object_set.rb', line 125 def each monitor.synchronize do objects.each_value do |ref| # Is this still necessary now that we're in a mutex? object = begin ref.__getobj__ rescue WeakRef::RefError nil end if ref.weakref_alive? yield object end end end end |
#empty? ⇒ Boolean
146 147 148 149 150 |
# File 'projects/weak_object_set/src/weak_object_set.rb', line 146 def empty? monitor.synchronize do objects.empty? || objects.values.none?(&:weakref_alive?) end end |
#find_by_key(key) ⇒ Object
237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 |
# File 'projects/weak_object_set/src/weak_object_set.rb', line 237 def find_by_key(key) monitor.synchronize do unless key_method # :nocov: raise "Cannot find by key if there was no key_method given." # :nocov: end object_id = key_to_object_id[key] if object_id self[object_id] end end end |
#ref_for(object_or_object_id) ⇒ Object
115 116 117 118 119 120 121 122 123 |
# File 'projects/weak_object_set/src/weak_object_set.rb', line 115 def ref_for(object_or_object_id) object_id = if object_or_object_id.is_a?(::Integer) object_or_object_id else object_or_object_id.object_id end objects[object_id] end |
#size ⇒ Object
142 143 144 |
# File 'projects/weak_object_set/src/weak_object_set.rb', line 142 def size count end |
#stop_garbage_cleaner ⇒ Object
260 261 262 263 264 265 266 267 268 269 270 271 |
# File 'projects/weak_object_set/src/weak_object_set.rb', line 260 def stop_garbage_cleaner gc = nil monitor.synchronize do if @garbage_cleaner gc = garbage_cleaner self.garbage_cleaner = nil end end gc&.deactivate end |