Class: Farce::Abstract::ConcurrentMap Abstract
- Includes:
- DuplicableMap
- Defined in:
- lib/farce/abstract/concurrent_map.rb,
lib/farce/integrations/active_support/map.rb
Overview
Super class for maps with added concurrency features.
Direct Known Subclasses
WeakKeyMap, WeakMap, WeakValueMap, Local::Map, Map, Strict::Map, Transaction::Map, Unshared::Map
ActiveSupport Integration collapse
-
#compact_blank! ⇒ self
Remove blank values using per-key coordination.
-
#reverse_merge!(other) ⇒ self
(also: #with_defaults!)
Store each default only if its key is absent, preserving existing nil and false values.
Methods included from DuplicableMap
#compact_blank, #deep_dup, #duplicable?, #reverse_merge, #stringify_keys, #symbolize_keys, #with_indifferent_access
Methods inherited from Map
#as_json, #assert_valid_keys, #to_msgpack, #to_query
Instance Method Summary collapse
-
#[](key) ⇒ BasicObject?
abstract
Look up a key without waiting for atomic-update access.
-
#[]=(key, value) ⇒ BasicObject
abstract
Associate a value with a key without a timeout.
-
#clear ⇒ self
abstract
Remove all entries from the map.
-
#compact! ⇒ self?
Remove nil values using per-key update coordination.
-
#compare_and_set(key, expected, replacement, timeout: nil) ⇒ Boolean
Atomically replace a value if the key is present and its current value matches
expected. -
#compare_keys_by_identity? ⇒ Boolean
abstract
Whether keys are compared by identity instead of
hashandeql?. -
#compare_values_by_identity? ⇒ Boolean
abstract
Whether values are compared by identity instead of equality.
-
#delete(key) ⇒ BasicObject?
abstract
Remove a key and its associated value.
-
#delete_if {|key, value| ... } ⇒ self, Enumerator
Delete entries selected by the block and return self.
-
#each(&block) ⇒ BasicObject
(also: #each_pair)
Iterate over entries captured when iteration begins.
-
#each_key(&block) ⇒ BasicObject
abstract
Iterate over the keys currently stored in the map.
-
#each_value(&block) ⇒ BasicObject
abstract
Iterate over the values currently stored in the map.
-
#fetch(*arguments) ⇒ BasicObject
abstract
Fetch the value associated with a key, using the same missing-key behavior as Hash#fetch.
-
#get(key, timeout: nil) { ... } ⇒ BasicObject?
Read the value associated with a key, waiting for atomic-update access if necessary.
-
#getkey(key) ⇒ BasicObject?
abstract
Return the stored key that matches a lookup key.
-
#keep_if ⇒ self, Enumerator
Keep entries selected by the block.
-
#key?(key) ⇒ Boolean
abstract
Test whether a key is present, including when its associated value is nil.
-
#keys ⇒ Array<BasicObject>
abstract
Return the keys currently stored in the map.
-
#merge!(*others) {|key, old_value, new_value| ... } ⇒ self
Apply input maps in order.
-
#reject! ⇒ self, ...
Like #delete_if, but return nil when this operation deletes no entries.
-
#select! ⇒ self, ...
(also: #filter!)
Like #keep_if, but return nil when this operation deletes no entries.
-
#size ⇒ Integer
abstract
Return the number of entries currently in the map.
-
#store(key, value, timeout: nil) { ... } ⇒ BasicObject?
Associate a value with a key, waiting for atomic-update access if necessary.
-
#store_if_absent(key, timeout: nil) { ... } ⇒ BasicObject?
Atomically fetch an existing value or compute and store a value for an absent key.
-
#swap(key, replacement, timeout: nil) { ... } ⇒ BasicObject?
Replace the value associated with a key and return its previous value.
-
#transform_values! {|value| ... } ⇒ self, Enumerator
Replace each existing value with the block result using atomic-update coordination.
-
#update(key, timeout: nil) {|value| ... } ⇒ BasicObject?
Atomically replace the value associated with a key with the block result.
-
#upsert(key, initial, timeout: nil) {|value| ... } ⇒ BasicObject?
Atomically insert
initialfor an absent key or replace an existing value with the block result. -
#values ⇒ Array<BasicObject>
Return the values currently stored in the map.
-
#wait_until(key, timeout: nil) {|value| ... } ⇒ BasicObject?
Wait until a block condition matches the current value.
-
#wait_until_changed(key, expected, timeout: nil) { ... } ⇒ BasicObject?
Wait until the value associated with a key no longer matches
expected. -
#wait_until_match(key, object, timeout: nil) ⇒ BasicObject?
Wait until
object === valueis true. -
#wait_until_non_nil(key, timeout: nil) { ... } ⇒ BasicObject?
Wait until a key is associated with a non-nil value.
-
#wait_until_value(key, object, timeout: nil) ⇒ BasicObject?
Wait until the current value equals an object using the configured comparison mode.
-
#wait_while(key, timeout: nil) {|value| ... } ⇒ BasicObject?
Wait while the block returns a truthy value.
-
#wait_while_match(key, object, timeout: nil) ⇒ BasicObject?
Wait while
object === valueis true. -
#wait_while_value { ... } ⇒ BasicObject?
Wait until the value associated with a key no longer matches
expected.
Methods included from DuplicableMap
#compact, #except, #flatten, #invert, #merge, #reject, #select, #slice, #to_proc, #transform_keys, #transform_values
Methods inherited from Map
#as_extended_json, #assoc, #bson_type, #compare_by_identity?, #deconstruct_keys, #dig, #empty?, #fetch_values, #has_key?, #key, #length, #rassoc, #shareable_keys?, #shareable_values?, #to_a, #to_bson, #to_bson_normalized_value, #to_cbor, #to_h, #to_hash, #to_json, #to_s, #value?, #values_at, #weak_keys?, #weak_values?
Instance Method Details
#[](key) ⇒ BasicObject?
Look up a key without waiting for atomic-update access.
15 |
# File 'lib/farce/abstract/concurrent_map.rb', line 15 def [](key) = internal_map[key] |
#[]=(key, value) ⇒ BasicObject
Associate a value with a key without a timeout.
18 19 20 |
# File 'lib/farce/abstract/concurrent_map.rb', line 18 def []=(key, value) internal_map[key] = value end |
#clear ⇒ self
Remove all entries from the map.
247 248 249 250 |
# File 'lib/farce/abstract/concurrent_map.rb', line 247 def clear internal_map.clear self end |
#compact! ⇒ self?
Remove nil values using per-key update coordination. False values are retained. The whole operation is not atomic, as with #delete_if.
280 |
# File 'lib/farce/abstract/concurrent_map.rb', line 280 def compact! = reject! { |_, value| nil.equal?(value) } |
#compact_blank! ⇒ self
This methods is only available if ActiveSupport has been loaded.
Remove blank values using per-key coordination. Always return self. The operation is not atomic across keys.
131 |
# File 'lib/farce/integrations/active_support/map.rb', line 131 def compact_blank! = delete_if { |_, value| value.blank? } |
#compare_and_set(key, expected, replacement, timeout: nil) ⇒ Boolean
Atomically replace a value if the key is present and its current value matches expected.
The configured value-comparison mode determines whether matching uses equality or identity.
81 82 83 |
# File 'lib/farce/abstract/concurrent_map.rb', line 81 def compare_and_set(key, expected, replacement, timeout: nil) internal_map.compare_and_set(key, expected, replacement, timeout:) end |
#compare_keys_by_identity? ⇒ Boolean
Returns Whether keys are compared by identity instead of hash and eql?.
190 |
# File 'lib/farce/abstract/concurrent_map.rb', line 190 def compare_keys_by_identity? = internal_map.compare_keys_by_identity? |
#compare_values_by_identity? ⇒ Boolean
Returns Whether values are compared by identity instead of equality.
193 |
# File 'lib/farce/abstract/concurrent_map.rb', line 193 def compare_values_by_identity? = internal_map.compare_values_by_identity? |
#delete(key) ⇒ BasicObject?
Remove a key and its associated value.
244 |
# File 'lib/farce/abstract/concurrent_map.rb', line 244 def delete(key) = internal_map.delete(key) |
#delete_if {|key, value| ... } ⇒ self, Enumerator
Delete entries selected by the block and return self.
Keys are captured before iteration. Each block and its decision use the existing atomic-update coordination. Blocks see the current value, and keys deleted before their turn are skipped. The whole operation is not atomic. Exceptions leave earlier changes in place. The same reentrancy restrictions as #update apply inside each block.
262 263 264 265 266 267 |
# File 'lib/farce/abstract/concurrent_map.rb', line 262 def delete_if(&) return enum_for(__method__) { size } unless block_given? check_frozen! if respond_to?(:check_frozen!, true) filter_entries(&) self end |
#each(&block) ⇒ BasicObject Also known as: each_pair
Iterate over entries captured when iteration begins. The map can be modified safely from the block. (see Map#each)
205 206 207 208 209 210 |
# File 'lib/farce/abstract/concurrent_map.rb', line 205 def each(&block) return enum_for(__callee__) { size } unless block internal_map.each(&block) self end |
#each_key {|key| ... } ⇒ self #each_key ⇒ Enumerator
Iterate over the keys currently stored in the map. Keys are not guaranteed to be yielded in insertion order.
228 229 230 231 232 233 |
# File 'lib/farce/abstract/concurrent_map.rb', line 228 def each_key(&block) return enum_for(__callee__) { size } unless block internal_map.each_key(&block) self end |
#each_value {|value| ... } ⇒ self #each_value ⇒ Enumerator
Iterate over the values currently stored in the map. Values are not guaranteed to be yielded in insertion order.
236 237 238 239 240 241 |
# File 'lib/farce/abstract/concurrent_map.rb', line 236 def each_value(&block) return enum_for(__callee__) { size } unless block internal_map.each_value(&block) self end |
#fetch(key) ⇒ BasicObject #fetch(key, default) ⇒ BasicObject #fetch(key) {|key| ... } ⇒ BasicObject
Fetch the value associated with a key, using the same missing-key behavior as Hash#fetch. If both a default and a block are provided, the block takes precedence and a warning is emitted.
23 24 25 26 27 28 29 30 31 32 33 34 35 |
# File 'lib/farce/abstract/concurrent_map.rb', line 23 def fetch(*arguments) unless arguments.length.between?(1, 2) raise ArgumentError, "wrong number of arguments (given #{arguments.length}, expected 1..2)" end key, default = arguments warn "block supersedes default value argument", uplevel: 1 if block_given? && arguments.length == 2 internal_map.fetch(key) do return yield(key) if block_given? return default if arguments.length == 2 raise KeyError.new("key not found: #{key.inspect}", receiver: self, key: key) end end |
#get(key, timeout: nil) { ... } ⇒ BasicObject?
Read the value associated with a key, waiting for atomic-update access if necessary.
44 |
# File 'lib/farce/abstract/concurrent_map.rb', line 44 def get(key, timeout: nil, &) = internal_map.get(key, timeout:, &) |
#getkey(key) ⇒ BasicObject?
Return the stored key that matches a lookup key.
184 |
# File 'lib/farce/abstract/concurrent_map.rb', line 184 def getkey(key) = internal_map.getkey(key) |
#keep_if ⇒ self, Enumerator
Keep entries selected by the block. Uses the same coordination as #delete_if.
284 285 286 287 288 289 |
# File 'lib/farce/abstract/concurrent_map.rb', line 284 def keep_if return enum_for(__method__) { size } unless block_given? check_frozen! if respond_to?(:check_frozen!, true) filter_entries { |key, value| !yield(key, value) } self end |
#key?(key) ⇒ Boolean
Test whether a key is present, including when its associated value is nil.
181 |
# File 'lib/farce/abstract/concurrent_map.rb', line 181 def key?(key) = internal_map.key?(key) |
#keys ⇒ Array<BasicObject>
Return the keys currently stored in the map. The returned keys are not guaranteed to be in insertion order.
196 |
# File 'lib/farce/abstract/concurrent_map.rb', line 196 def keys = internal_map.keys |
#merge!(*others) {|key, old_value, new_value| ... } ⇒ self
Apply input maps in order. A block resolves each collision under atomic-update coordination.
Incoming keys use normal lookup rules. Values use this map's transfer mode, including move semantics. The operation is not atomic across keys. Exceptions leave earlier changes in place.
328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 |
# File 'lib/farce/abstract/concurrent_map.rb', line 328 def merge!(*others) check_frozen! if respond_to?(:check_frozen!, true) others.each do |other| unless Map === other other = Hash.try_convert(other) || raise(TypeError, "input must be a Map, Hash, or respond to #to_hash") end other.each_pair do |key, value| if block_given? modify_entry(key) { |present, old| present ? yield(key, old, value) : value } else self[key] = value end end end self end |
#reject! ⇒ self, ...
Like #delete_if, but return nil when this operation deletes no entries.
271 272 273 274 275 |
# File 'lib/farce/abstract/concurrent_map.rb', line 271 def reject!(&) return enum_for(__method__) { size } unless block_given? check_frozen! if respond_to?(:check_frozen!, true) self if filter_entries(&) end |
#reverse_merge!(other) ⇒ self Also known as: with_defaults!
This methods is only available if ActiveSupport has been loaded.
Store each default only if its key is absent, preserving existing nil and false values. Each decision is atomic for its key. Earlier changes survive exceptions. Inserted values use the map's transfer mode, including move semantics.
139 140 141 142 143 144 145 |
# File 'lib/farce/integrations/active_support/map.rb', line 139 def reverse_merge!(other) unless Map === other other = Hash.try_convert(other) || raise(TypeError, "input must be a Map, Hash, or respond to #to_hash") end other.each_pair { |key, value| store_if_absent(key) { value } } self end |
#select! ⇒ self, ... Also known as: filter!
Like #keep_if, but return nil when this operation deletes no entries.
293 294 295 296 297 |
# File 'lib/farce/abstract/concurrent_map.rb', line 293 def select! return enum_for(__method__) { size } unless block_given? check_frozen! if respond_to?(:check_frozen!, true) self if filter_entries { |key, value| !yield(key, value) } end |
#size ⇒ Integer
Return the number of entries currently in the map.
187 |
# File 'lib/farce/abstract/concurrent_map.rb', line 187 def size = internal_map.size |
#store(key, value, timeout: nil) { ... } ⇒ BasicObject?
Associate a value with a key, waiting for atomic-update access if necessary.
53 |
# File 'lib/farce/abstract/concurrent_map.rb', line 53 def store(key, value, timeout: nil, &) = internal_map.store(key, value, timeout:, &) |
#store_if_absent(key, timeout: nil) { ... } ⇒ BasicObject?
Atomically fetch an existing value or compute and store a value for an absent key.
72 |
# File 'lib/farce/abstract/concurrent_map.rb', line 72 def store_if_absent(key, timeout: nil, &) = internal_map.store_if_absent(key, timeout:, &) |
#swap(key, replacement, timeout: nil) { ... } ⇒ BasicObject?
Replace the value associated with a key and return its previous value.
63 |
# File 'lib/farce/abstract/concurrent_map.rb', line 63 def swap(key, replacement, timeout: nil, &) = internal_map.swap(key, replacement, timeout:, &) |
#transform_values! {|value| ... } ⇒ self, Enumerator
Replace each existing value with the block result using atomic-update coordination.
Keys are captured before iteration. Missing keys are skipped and earlier changes survive exceptions. Results use this map's transfer mode. The same reentrancy restrictions as #update apply.
307 308 309 310 311 312 313 314 315 316 |
# File 'lib/farce/abstract/concurrent_map.rb', line 307 def transform_values! return enum_for(__method__) { size } unless block_given? check_frozen! if respond_to?(:check_frozen!, true) keys.each do |key| modify_entry(key, canonical: true) do |present, value| present ? yield(value) : Internal::MAP_KEEP end end self end |
#update(key, timeout: nil) {|value| ... } ⇒ BasicObject?
Atomically replace the value associated with a key with the block result. The block receives nil when the key is absent or its current value is nil.
94 |
# File 'lib/farce/abstract/concurrent_map.rb', line 94 def update(key, timeout: nil, &) = internal_map.update(key, timeout:, &) |
#upsert(key, initial, timeout: nil) {|value| ... } ⇒ BasicObject?
Atomically insert initial for an absent key or replace an existing value with the block result.
The block is not called when the key is absent.
106 |
# File 'lib/farce/abstract/concurrent_map.rb', line 106 def upsert(key, initial, timeout: nil, &) = internal_map.upsert(key, initial, timeout:, &) |
#values ⇒ Array<BasicObject>
Return the values currently stored in the map.
200 |
# File 'lib/farce/abstract/concurrent_map.rb', line 200 def values = each_value.to_a |
#wait_until(key, timeout: nil) {|value| ... } ⇒ BasicObject?
Wait until a block condition matches the current value. One timeout budget covers all checks and waits. The block is not interrupted. An absent key is observed as nil.
117 |
# File 'lib/farce/abstract/concurrent_map.rb', line 117 def wait_until(key, timeout: nil, &) = Internal.wait_until(self, key, timeout:, &) |
#wait_until_changed(key, expected, timeout: nil) { ... } ⇒ BasicObject?
Wait until the value associated with a key no longer matches expected.
An absent key is observed as nil. The configured value-comparison mode determines how values are matched.
168 169 170 |
# File 'lib/farce/abstract/concurrent_map.rb', line 168 def wait_until_changed(key, expected, timeout: nil, &) internal_map.wait_until_changed(key, expected, timeout:, &) end |
#wait_until_match(key, object, timeout: nil) ⇒ BasicObject?
Wait until object === value is true.
156 157 158 |
# File 'lib/farce/abstract/concurrent_map.rb', line 156 def wait_until_match(key, object, timeout: nil) wait_until(key, timeout:) { |value| object === value } # rubocop:disable Style/CaseEquality end |
#wait_until_non_nil(key, timeout: nil) { ... } ⇒ BasicObject?
Wait until a key is associated with a non-nil value.
178 |
# File 'lib/farce/abstract/concurrent_map.rb', line 178 def wait_until_non_nil(key, timeout: nil, &) = internal_map.wait_until_non_nil(key, timeout:, &) |
#wait_until_value(key, object, timeout: nil) ⇒ BasicObject?
Wait until the current value equals an object using the configured comparison mode.
148 149 150 |
# File 'lib/farce/abstract/concurrent_map.rb', line 148 def wait_until_value(key, object, timeout: nil) wait_until(key, timeout:) { |value| compare_values_by_identity? ? object.equal?(value) : object == value } end |
#wait_while(key, timeout: nil) {|value| ... } ⇒ BasicObject?
Wait while the block returns a truthy value.
126 127 128 129 |
# File 'lib/farce/abstract/concurrent_map.rb', line 126 def wait_while(key, timeout: nil) raise LocalJumpError, "no block given" unless block_given? wait_until(key, timeout:) { |value| !yield(value) } end |
#wait_while_match(key, object, timeout: nil) ⇒ BasicObject?
Wait while object === value is true.
136 137 138 |
# File 'lib/farce/abstract/concurrent_map.rb', line 136 def wait_while_match(key, object, timeout: nil) wait_while(key, timeout:) { |value| object === value } # rubocop:disable Style/CaseEquality end |
#wait_while_value { ... } ⇒ BasicObject?
Wait until the value associated with a key no longer matches expected.
An absent key is observed as nil. The configured value-comparison mode determines how values are matched.
141 |
# File 'lib/farce/abstract/concurrent_map.rb', line 141 def wait_while_value(...) = wait_until_changed(...) |