Class: Concurrent::Map
Relationships & Source Files | |
Inherits: |
Concurrent::Collection::MapImplementation
|
Defined in: | lib/concurrent-ruby/concurrent/map.rb |
Overview
Map
is a hash-like object and should have much better performance characteristics, especially under high concurrency, than 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 Map
instead of Hash
for your concurrency-safe hash needs.
Class Method Summary
- .new(options = nil, &default_proc) ⇒ Map constructor
Instance Attribute Summary
-
#empty? ⇒ true, false
readonly
Is map empty?
Instance Method Summary
-
#[](key) ⇒ Object
(also: #get)
Get a value with key.
-
#[]=(key, value) ⇒ Object
(also: #put)
Set
a value with key. -
#compute(key) {|old_value| ... } ⇒ Object?
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?
Compute and store new value for key if the key is present.
-
#delete(key) ⇒ Object?
Delete key and its value.
-
#delete_pair(key, value) ⇒ true, false
Delete pair and its value if current value equals the provided value.
-
#each
Alias for #each_pair.
-
#each_key {|key| ... } ⇒ self
Iterates over each key.
-
#each_pair {|key, value| ... } ⇒ self
(also: #each, #each)
Iterates over each key value pair.
-
#each_value {|value| ... } ⇒ self
Iterates over each value.
-
#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(key)
Alias for #[].
-
#get_and_set(key, value) ⇒ Object?
Get the current value under key and set new value.
-
#key(value) ⇒ Object?
Find key of a value.
-
#keys ⇒ ::Array<Object>
All keys.
-
#merge_pair(key, value) {|old_value| ... } ⇒ Object?
If the key is absent, the value is stored, otherwise new value is computed with a block.
-
#put(key, value)
Alias for #[]=.
-
#put_if_absent(key, value) ⇒ Object?
Insert value into map with key if key is absent in one atomic step.
-
#replace_if_exists(key, new_value) ⇒ Object?
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.
- #initialize_copy(other) private
- #inspect private
- #marshal_dump private
- #marshal_load(hash) private
- #populate_from(hash) private
- #raise_fetch_no_key private
- #validate_options_hash!(options) private
Constructor Details
.new(options = nil, &default_proc) ⇒ Map
# File 'lib/concurrent-ruby/concurrent/map.rb', line 133
def initialize( = nil, &default_proc) if .kind_of?(::Hash) ( ) else = nil end super( ) @default_proc = default_proc end
Instance Attribute Details
#empty? ⇒ true
, false
(readonly)
Is map empty?
# File 'lib/concurrent-ruby/concurrent/map.rb', line 291
def empty? each_pair { |k, v| return false } true end
Instance Method Details
#[](key) ⇒ Object Also known as: #get
Get a value with key
# File 'lib/concurrent-ruby/concurrent/map.rb', line 147
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
#compute(key) {|old_value| ... } ⇒ 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. This method is atomic.
#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.
#compute_if_present(key) {|old_value| ... } ⇒ 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 present. This method is atomic.
#delete(key) ⇒ Object?
Delete key and its value. This method is atomic.
#delete_pair(key, value) ⇒ true
, false
Delete pair and its value if current value equals the provided value. This method is atomic.
#each
Alias for #each_pair.
# File 'lib/concurrent-ruby/concurrent/map.rb', line 279
alias_method :each, :each_pair unless method_defined?(:each)
#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.
# File 'lib/concurrent-ruby/concurrent/map.rb', line 255
def each_key each_pair { |k, v| yield k } end
#each_pair {|key, value| ... } ⇒ self
Also known as: #each, #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.
# File 'lib/concurrent-ruby/concurrent/map.rb', line 274
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.
# File 'lib/concurrent-ruby/concurrent/map.rb', line 264
def each_value each_pair { |k, v| yield v } 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.
#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. This is a two step operation, therefore not atomic. The store can overwrite other concurrently stored value.
#get(key)
Alias for #[].
# File 'lib/concurrent-ruby/concurrent/map.rb', line 162
alias_method :get, :[]
#get_and_set(key, value) ⇒ Object?
Get the current value under key and set new value. This method is atomic.
#initialize_copy(other) (private)
[ GitHub ]# File 'lib/concurrent-ruby/concurrent/map.rb', line 331
def initialize_copy(other) super populate_from(other) end
#inspect (private)
[ GitHub ]# File 'lib/concurrent-ruby/concurrent/map.rb', line 321
def inspect format '%s entries=%d default_proc=%s>', to_s[0..-2], size.to_s, @default_proc.inspect end
#key(value) ⇒ Object?
Find key of a value.
# File 'lib/concurrent-ruby/concurrent/map.rb', line 284
def key(value) each_pair { |k, v| return k if v == value } nil end
#keys ⇒ ::Array
<Object>
All keys
# File 'lib/concurrent-ruby/concurrent/map.rb', line 236
def keys arr = [] each_pair { |k, v| arr << k } arr end
#marshal_dump (private)
# File 'lib/concurrent-ruby/concurrent/map.rb', line 305
def marshal_dump raise TypeError, "can't dump hash with default proc" if @default_proc h = {} each_pair { |k, v| h[k] = v } h end
#marshal_load(hash) (private)
[ GitHub ]# File 'lib/concurrent-ruby/concurrent/map.rb', line 313
def marshal_load(hash) initialize populate_from(hash) end
#merge_pair(key, value) {|old_value| ... } ⇒ Object?
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.
#populate_from(hash) (private)
[ GitHub ]# File 'lib/concurrent-ruby/concurrent/map.rb', line 336
def populate_from(hash) hash.each_pair { |k, v| self[k] = v } self end
#put(key, value)
Alias for #[]=.
# File 'lib/concurrent-ruby/concurrent/map.rb', line 163
alias_method :put, :[]=
#put_if_absent(key, value) ⇒ Object?
Insert value into map with key if key is absent in one atomic step.
# File 'lib/concurrent-ruby/concurrent/map.rb', line 215
def put_if_absent(key, value) computed = false result = compute_if_absent(key) do computed = true value end computed ? nil : result end
#raise_fetch_no_key (private)
# File 'lib/concurrent-ruby/concurrent/map.rb', line 327
def raise_fetch_no_key raise KeyError, 'key not found' end
#replace_if_exists(key, new_value) ⇒ Object?
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.
# File 'lib/concurrent-ruby/concurrent/map.rb', line 298
def size count = 0 each_pair { |k, v| count += 1 } count end
#validate_options_hash!(options) (private)
[ GitHub ]# File 'lib/concurrent-ruby/concurrent/map.rb', line 341
def ( ) if (initial_capacity = [:initial_capacity]) && (!initial_capacity.kind_of?(Integer) || initial_capacity < 0) raise ArgumentError, ":initial_capacity must be a positive Integer" end if (load_factor = [:load_factor]) && (!load_factor.kind_of?(Numeric) || load_factor <= 0 || load_factor > 1) raise ArgumentError, ":load_factor must be a number between 0 and 1" end end
#value?(value) ⇒ true
, false
Is the value stored in the map. Iterates over all values.
# File 'lib/concurrent-ruby/concurrent/map.rb', line 227
def value?(value) each_value do |v| return true if value.equal?(v) end false end
#values ⇒ ::Array
<Object>
All values
# File 'lib/concurrent-ruby/concurrent/map.rb', line 244
def values arr = [] each_pair { |k, v| arr << v } arr end