Class: Concurrent::Map
- Inherits:
-
Collection::MapImplementation
- Object
- Concurrent::Map
- Defined in:
- lib/concurrent-ruby/concurrent/map.rb
Overview
Concurrent::Map
is a hash-like object and should have much better performance
characteristics, especially under high concurrency, than Concurrent::Hash
.
However, Concurrent::Map
is not strictly semantically equivalent to a ruby Hash
-- for instance, it does not necessarily retain ordering by insertion time as Hash
does. For most uses it should do fine though, and we recommend you consider
Concurrent::Map
instead of Concurrent::Hash
for your concurrency-safe hash needs.
Instance Method Summary collapse
-
#[](key) ⇒ Object
(also: #get)
Get a value with key.
-
#[]=(key, value) ⇒ Object
(also: #put)
Set a value with key.
-
#compute(key) {|old_value| ... } ⇒ Object, nil
Compute and store new value for key.
-
#compute_if_absent(key) { ... } ⇒ Object
Compute and store new value for key if the key is absent.
-
#compute_if_present(key) {|old_value| ... } ⇒ Object, nil
Compute and store new value for key if the key is present.
-
#delete(key) ⇒ Object, nil
Delete key and its value.
-
#delete_pair(key, value) ⇒ true, false
Delete pair and its value if current value equals the provided value.
-
#each_key {|key| ... } ⇒ self
Iterates over each key.
-
#each_pair {|key, value| ... } ⇒ self
(also: #each)
Iterates over each key value pair.
-
#each_value {|value| ... } ⇒ self
Iterates over each value.
-
#empty? ⇒ true, false
Is map empty?.
-
#fetch(key, default_value = NULL) {|key| ... } ⇒ Object
Get a value with key, or default_value when key is absent, or fail when no default_value is given.
-
#fetch_or_store(key, default_value = NULL) {|key| ... } ⇒ Object
Fetch value with key, or store default value when key is absent, or fail when no default_value is given.
-
#get_and_set(key, value) ⇒ Object, nil
Get the current value under key and set new value.
-
#initialize(options = nil, &block) ⇒ Map
constructor
A new instance of Map.
-
#key(value) ⇒ Object, nil
Find key of a value.
-
#keys ⇒ ::Array<Object>
All keys.
-
#merge_pair(key, value) {|old_value| ... } ⇒ Object, nil
If the key is absent, the value is stored, otherwise new value is computed with a block.
-
#put_if_absent(key, value) ⇒ Object, nil
Insert value into map with key if key is absent in one atomic step.
-
#replace_if_exists(key, new_value) ⇒ Object, nil
Replaces current value with new_value if key exists This method is atomic.
-
#replace_pair(key, old_value, new_value) ⇒ true, false
Replaces old_value with new_value if key exists and current value matches old_value This method is atomic.
-
#size ⇒ Integer
The size of map.
-
#value?(value) ⇒ true, false
Is the value stored in the map.
-
#values ⇒ ::Array<Object>
All values.
Constructor Details
#initialize(options = nil, &block) ⇒ Map
Returns a new instance of Map.
121 122 123 124 125 126 127 128 129 130 |
# File 'lib/concurrent-ruby/concurrent/map.rb', line 121 def initialize( = nil, &block) if .kind_of?(::Hash) () else = nil end super() @default_proc = block end |
Instance Method Details
#[](key) ⇒ Object Also known as: get
Get a value with key
135 136 137 138 139 140 141 142 143 144 145 146 147 |
# File 'lib/concurrent-ruby/concurrent/map.rb', line 135 def [](key) if value = super # non-falsy value is an existing mapping, return it right away value # re-check is done with get_or_default(key, NULL) instead of a simple !key?(key) in order to avoid a race condition, whereby by the time the current thread gets to the key?(key) call # a key => value mapping might have already been created by a different thread (key?(key) would then return true, this elsif branch wouldn't be taken and an incorrent +nil+ value # would be returned) # note: nil == value check is not technically necessary elsif @default_proc && nil == value && NULL == (value = get_or_default(key, NULL)) @default_proc.call(self, key) else value end end |
#[]=(key, value) ⇒ Object Also known as: put
Set a value with key
153 154 155 |
# File 'lib/concurrent-ruby/concurrent/map.rb', line 153 def []=(key, value) super end |
#compute(key) {|old_value| ... } ⇒ Object, nil
Atomic methods taking a block do not allow the self
instance
to be used within the block. Doing so will cause a deadlock.
Compute and store new value for key. This method is atomic.
|
# File 'lib/concurrent-ruby/concurrent/map.rb', line 64
|
#compute_if_absent(key) { ... } ⇒ Object
Atomic methods taking a block do not allow the self
instance
to be used within the block. Doing so will cause a deadlock.
Compute and store new value for key if the key is absent. This method is atomic.
|
# File 'lib/concurrent-ruby/concurrent/map.rb', line 47
|
#compute_if_present(key) {|old_value| ... } ⇒ Object, nil
Atomic methods taking a block do not allow the self
instance
to be used within the block. Doing so will cause a deadlock.
Compute and store new value for key if the key is present. This method is atomic.
|
# File 'lib/concurrent-ruby/concurrent/map.rb', line 55
|
#delete(key) ⇒ Object, nil
Delete key and its value. This method is atomic.
|
# File 'lib/concurrent-ruby/concurrent/map.rb', line 107
|
#delete_pair(key, value) ⇒ true, false
Delete pair and its value if current value equals the provided value. This method is atomic.
|
# File 'lib/concurrent-ruby/concurrent/map.rb', line 113
|
#each_key {|key| ... } ⇒ self
Atomic methods taking a block do not allow the self
instance
to be used within the block. Doing so will cause a deadlock.
Iterates over each key. This method is atomic.
251 252 253 |
# File 'lib/concurrent-ruby/concurrent/map.rb', line 251 def each_key each_pair { |k, v| yield k } end |
#each_pair {|key, value| ... } ⇒ self Also known as: each
Atomic methods taking a block do not allow the self
instance
to be used within the block. Doing so will cause a deadlock.
Iterates over each key value pair. This method is atomic.
270 271 272 273 |
# File 'lib/concurrent-ruby/concurrent/map.rb', line 270 def each_pair return enum_for :each_pair unless block_given? super end |
#each_value {|value| ... } ⇒ self
Atomic methods taking a block do not allow the self
instance
to be used within the block. Doing so will cause a deadlock.
Iterates over each value. This method is atomic.
260 261 262 |
# File 'lib/concurrent-ruby/concurrent/map.rb', line 260 def each_value each_pair { |k, v| yield v } end |
#empty? ⇒ true, false
Is map empty?
287 288 289 290 |
# File 'lib/concurrent-ruby/concurrent/map.rb', line 287 def empty? each_pair { |k, v| return false } true end |
#fetch(key, default_value = NULL) {|key| ... } ⇒ Object
The "fetch-then-act" methods of Map
are not atomic. Map
is intended
to be use as a concurrency primitive with strong happens-before
guarantees. It is not intended to be used as a high-level abstraction
supporting complex operations. All read and write operations are
thread safe, but no guarantees are made regarding race conditions
between the fetch operation and yielding to the block. Additionally,
this method does not support recursion. This is due to internal
constraints that are very unlikely to change in the near future.
Get a value with key, or default_value when key is absent, or fail when no default_value is given.
178 179 180 181 182 183 184 185 186 187 188 |
# File 'lib/concurrent-ruby/concurrent/map.rb', line 178 def fetch(key, default_value = NULL) if NULL != (value = get_or_default(key, NULL)) value elsif block_given? yield key elsif NULL != default_value default_value else raise_fetch_no_key end end |
#fetch_or_store(key, default_value = NULL) {|key| ... } ⇒ Object
Atomic methods taking a block do not allow the self
instance
to be used within the block. Doing so will cause a deadlock.
Fetch value with key, or store default value when key is absent, or fail when no default_value is given. This is a two step operation, therefore not atomic. The store can overwrite other concurrently stored value. This method is atomic.
201 202 203 204 205 |
# File 'lib/concurrent-ruby/concurrent/map.rb', line 201 def fetch_or_store(key, default_value = NULL) fetch(key) do put(key, block_given? ? yield(key) : (NULL == default_value ? raise_fetch_no_key : default_value)) end end |
#get_and_set(key, value) ⇒ Object, nil
Get the current value under key and set new value. This method is atomic.
|
# File 'lib/concurrent-ruby/concurrent/map.rb', line 100
|
#key(value) ⇒ Object, nil
Find key of a value.
280 281 282 283 |
# File 'lib/concurrent-ruby/concurrent/map.rb', line 280 def key(value) each_pair { |k, v| return k if v == value } nil end |
#keys ⇒ ::Array<Object>
All keys
232 233 234 235 236 |
# File 'lib/concurrent-ruby/concurrent/map.rb', line 232 def keys arr = [] each_pair { |k, v| arr << k } arr end |
#merge_pair(key, value) {|old_value| ... } ⇒ Object, nil
Atomic methods taking a block do not allow the self
instance
to be used within the block. Doing so will cause a deadlock.
If the key is absent, the value is stored, otherwise new value is computed with a block. This method is atomic.
|
# File 'lib/concurrent-ruby/concurrent/map.rb', line 73
|
#put_if_absent(key, value) ⇒ Object, nil
Insert value into map with key if key is absent in one atomic step.
211 212 213 214 215 216 217 218 |
# File 'lib/concurrent-ruby/concurrent/map.rb', line 211 def put_if_absent(key, value) computed = false result = compute_if_absent(key) do computed = true value end computed ? nil : result end |
#replace_if_exists(key, new_value) ⇒ Object, nil
Replaces current value with new_value if key exists This method is atomic.
|
# File 'lib/concurrent-ruby/concurrent/map.rb', line 93
|
#replace_pair(key, old_value, new_value) ⇒ true, false
Replaces old_value with new_value if key exists and current value matches old_value This method is atomic.
|
# File 'lib/concurrent-ruby/concurrent/map.rb', line 84
|
#size ⇒ Integer
The size of map.
294 295 296 297 298 |
# File 'lib/concurrent-ruby/concurrent/map.rb', line 294 def size count = 0 each_pair { |k, v| count += 1 } count end |
#value?(value) ⇒ true, false
Is the value stored in the map. Iterates over all values.
223 224 225 226 227 228 |
# File 'lib/concurrent-ruby/concurrent/map.rb', line 223 def value?(value) each_value do |v| return true if value.equal?(v) end false end |
#values ⇒ ::Array<Object>
All values
240 241 242 243 244 |
# File 'lib/concurrent-ruby/concurrent/map.rb', line 240 def values arr = [] each_pair { |k, v| arr << v } arr end |