Class List Method List File List

# Class: Concurrent::Map

Inherits:
  Collection::MapImplementation
  - Object
  - Concurrent::Map
  show all
Defined in:
  lib/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.

> require 'concurrent'

> map = Concurrent::Map.new

## Constant Summary

## Instance Method Summary (collapse)

- - (undocumented) [](key) (also: #get)
- - (undocumented) compute

  This method is atomic.

- - (undocumented) compute_if_absent

  This method is atomic.

- - (undocumented) compute_if_present

  This method is atomic.

- - (undocumented) delete

  This method is atomic.

- - (undocumented) delete_pair

  This method is atomic.

- - (undocumented) each_key
- - (undocumented) each_value
- - (Boolean) empty?
- - (undocumented) fetch(key, default_value = NULL)

  The "fetch-then-act" methods of `Map` are not atomic.

- - (undocumented) fetch_or_store(key, default_value = NULL)

  The "fetch-then-act" methods of `Map` are not atomic.

- - (undocumented) get_and_set

  This method is atomic.

- - (Map) initialize(options = nil, &block) constructor

  A new instance of Map.

- - (undocumented) inspect

  override default #inspect() method: firstly, we don't want to be spilling our guts (i-vars), secondly, MRI backend's #inspect() call on its @backend i-var will bump @backend's iter level while possibly yielding GVL.

- - (undocumented) key(value) (also: #index)
- - (undocumented) keys
- - (undocumented) marshal_dump
- - (undocumented) marshal_load(hash)
- - (undocumented) merge_pair

  This method is atomic.

- - (undocumented) put_if_absent(key, value)

  This method is atomic.

- - (undocumented) replace_if_exists

  This method is atomic.

- - (undocumented) replace_pair

  This method is atomic.

- - (undocumented) size
- - (Boolean) value?(value)
- - (undocumented) values

## Constructor Details

### - (`Map`) initialize(options = nil, &block)

Returns a new instance of Map

    81
    82
    83
    84
    85
    86
    87
    88
    89
    90

    # File 'lib/concurrent/map.rb', line 81

    def initialize(options = nil, &block)
      if options.kind_of?(::Hash)
        validate_options_hash!(options)
      else
        options = nil
      end

      super(options)
      @default_proc = block
    end

## Instance Method Details

### - (`undocumented`) [](key) Also known as: get

    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104

    # File 'lib/concurrent/map.rb', line 92

    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

### - (`undocumented`) compute

This method is atomic. Atomic methods of `Map` which accept a block do not allow the `self` instance to be used within the block. Doing so will cause a deadlock.

    # File 'lib/concurrent/map.rb', line 60

### - (`undocumented`) compute_if_absent

This method is atomic. Atomic methods of `Map` which accept a block do not allow the `self` instance to be used within the block. Doing so will cause a deadlock.

    # File 'lib/concurrent/map.rb', line 54

### - (`undocumented`) compute_if_present

This method is atomic. Atomic methods of `Map` which accept a block do not allow the `self` instance to be used within the block. Doing so will cause a deadlock.

    # File 'lib/concurrent/map.rb', line 57

### - (`undocumented`) delete

This method is atomic. Atomic methods of `Map` which accept a block do not allow the `self` instance to be used within the block. Doing so will cause a deadlock.

    # File 'lib/concurrent/map.rb', line 75

### - (`undocumented`) delete_pair

This method is atomic. Atomic methods of `Map` which accept a block do not allow the `self` instance to be used within the block. Doing so will cause a deadlock.

    81
    82
    83
    84
    85
    86
    87
    88
    89
    90

    # File 'lib/concurrent/map.rb', line 81

    def initialize(options = nil, &block)
      if options.kind_of?(::Hash)
        validate_options_hash!(options)
      else
        options = nil
      end

      super(options)
      @default_proc = block
    end

### - (`undocumented`) each_key

    166
    167
    168

    # File 'lib/concurrent/map.rb', line 166

    def each_key
      each_pair {|k, v| yield k}
    end

### - (`undocumented`) each_value

    170
    171
    172

    # File 'lib/concurrent/map.rb', line 170

    def each_value
      each_pair {|k, v| yield v}
    end

### - (`Boolean`) empty?

Returns:

- (`Boolean`)

    182
    183
    184
    185

    # File 'lib/concurrent/map.rb', line 182

    def empty?
      each_pair {|k, v| return false}
      true
    end

### - (`undocumented`) fetch(key, default_value = NULL)

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.

    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128

    # File 'lib/concurrent/map.rb', line 118

    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

### - (`undocumented`) fetch_or_store(key, default_value = NULL)

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.

    131
    132
    133
    134
    135

    # File 'lib/concurrent/map.rb', line 131

    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

### - (`undocumented`) get_and_set

This method is atomic. Atomic methods of `Map` which accept a block do not allow the `self` instance to be used within the block. Doing so will cause a deadlock.

    # File 'lib/concurrent/map.rb', line 72

### - (`undocumented`) inspect

override default #inspect() method: firstly, we don't want to be spilling our guts (i-vars), secondly, MRI backend's

# inspect() call on its @backend i-var will bump @backend's iter level while possibly yielding GVL

    211
    212
    213
    214

    # File 'lib/concurrent/map.rb', line 211

    def inspect
      id_str = (object_id << 1).to_s(16).rjust(DEFAULT_OBJ_ID_STR_WIDTH, '0')
      "#<#{self.class.name}:0x#{id_str} entries=#{size} default_proc=#{@default_proc.inspect}>"
    end

### - (`undocumented`) key(value) Also known as: index

    176
    177
    178
    179

    # File 'lib/concurrent/map.rb', line 176

    def key(value)
      each_pair {|k, v| return k if v == value}
      nil
    end

### - (`undocumented`) keys

    154
    155
    156
    157
    158

    # File 'lib/concurrent/map.rb', line 154

    def keys
      arr = []
      each_pair {|k, v| arr << k}
      arr
    end

### - (`undocumented`) marshal_dump

Raises:

- (`TypeError`)

    193
    194
    195
    196
    197
    198

    # File 'lib/concurrent/map.rb', line 193

    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

### - (`undocumented`) marshal_load(hash)

    200
    201
    202
    203

    # File 'lib/concurrent/map.rb', line 200

    def marshal_load(hash)
      initialize
      populate_from(hash)
    end

### - (`undocumented`) merge_pair

This method is atomic. Atomic methods of `Map` which accept a block do not allow the `self` instance to be used within the block. Doing so will cause a deadlock.

    # File 'lib/concurrent/map.rb', line 63

### - (`undocumented`) put_if_absent(key, value)

This method is atomic. Atomic methods of `Map` which accept a block do not allow the `self` instance to be used within the block. Doing so will cause a deadlock.

    # File 'lib/concurrent/map.rb', line 51

### - (`undocumented`) replace_if_exists

This method is atomic. Atomic methods of `Map` which accept a block do not allow the `self` instance to be used within the block. Doing so will cause a deadlock.

    # File 'lib/concurrent/map.rb', line 69

### - (`undocumented`) replace_pair

This method is atomic. Atomic methods of `Map` which accept a block do not allow the `self` instance to be used within the block. Doing so will cause a deadlock.

    # File 'lib/concurrent/map.rb', line 66

### - (`undocumented`) size

    187
    188
    189
    190
    191

    # File 'lib/concurrent/map.rb', line 187

    def size
      count = 0
      each_pair {|k, v| count += 1}
      count
    end

### - (`Boolean`) value?(value)

Returns:

- (`Boolean`)

    147
    148
    149
    150
    151
    152

    # File 'lib/concurrent/map.rb', line 147

    def value?(value)
      each_value do |v|
        return true if value.equal?(v)
      end
      false
    end

### - (`undocumented`) values

    160
    161
    162
    163
    164

    # File 'lib/concurrent/map.rb', line 160

    def values
      arr = []
      each_pair {|k, v| arr << v}
      arr
    end