This commit is contained in:
+66
@@ -0,0 +1,66 @@
|
||||
require 'thread'
|
||||
require 'concurrent/collection/map/non_concurrent_map_backend'
|
||||
|
||||
module Concurrent
|
||||
|
||||
# @!visibility private
|
||||
module Collection
|
||||
|
||||
# @!visibility private
|
||||
class MriMapBackend < NonConcurrentMapBackend
|
||||
|
||||
def initialize(options = nil, &default_proc)
|
||||
super(options, &default_proc)
|
||||
@write_lock = Mutex.new
|
||||
end
|
||||
|
||||
def []=(key, value)
|
||||
@write_lock.synchronize { super }
|
||||
end
|
||||
|
||||
def compute_if_absent(key)
|
||||
if NULL != (stored_value = @backend.fetch(key, NULL)) # fast non-blocking path for the most likely case
|
||||
stored_value
|
||||
else
|
||||
@write_lock.synchronize { super }
|
||||
end
|
||||
end
|
||||
|
||||
def compute_if_present(key)
|
||||
@write_lock.synchronize { super }
|
||||
end
|
||||
|
||||
def compute(key)
|
||||
@write_lock.synchronize { super }
|
||||
end
|
||||
|
||||
def merge_pair(key, value)
|
||||
@write_lock.synchronize { super }
|
||||
end
|
||||
|
||||
def replace_pair(key, old_value, new_value)
|
||||
@write_lock.synchronize { super }
|
||||
end
|
||||
|
||||
def replace_if_exists(key, new_value)
|
||||
@write_lock.synchronize { super }
|
||||
end
|
||||
|
||||
def get_and_set(key, value)
|
||||
@write_lock.synchronize { super }
|
||||
end
|
||||
|
||||
def delete(key)
|
||||
@write_lock.synchronize { super }
|
||||
end
|
||||
|
||||
def delete_pair(key, value)
|
||||
@write_lock.synchronize { super }
|
||||
end
|
||||
|
||||
def clear
|
||||
@write_lock.synchronize { super }
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
+148
@@ -0,0 +1,148 @@
|
||||
require 'concurrent/constants'
|
||||
|
||||
module Concurrent
|
||||
|
||||
# @!visibility private
|
||||
module Collection
|
||||
|
||||
# @!visibility private
|
||||
class NonConcurrentMapBackend
|
||||
|
||||
# WARNING: all public methods of the class must operate on the @backend
|
||||
# directly without calling each other. This is important because of the
|
||||
# SynchronizedMapBackend which uses a non-reentrant mutex for performance
|
||||
# reasons.
|
||||
def initialize(options = nil, &default_proc)
|
||||
validate_options_hash!(options) if options.kind_of?(::Hash)
|
||||
set_backend(default_proc)
|
||||
@default_proc = default_proc
|
||||
end
|
||||
|
||||
def [](key)
|
||||
@backend[key]
|
||||
end
|
||||
|
||||
def []=(key, value)
|
||||
@backend[key] = value
|
||||
end
|
||||
|
||||
def compute_if_absent(key)
|
||||
if NULL != (stored_value = @backend.fetch(key, NULL))
|
||||
stored_value
|
||||
else
|
||||
@backend[key] = yield
|
||||
end
|
||||
end
|
||||
|
||||
def replace_pair(key, old_value, new_value)
|
||||
if pair?(key, old_value)
|
||||
@backend[key] = new_value
|
||||
true
|
||||
else
|
||||
false
|
||||
end
|
||||
end
|
||||
|
||||
def replace_if_exists(key, new_value)
|
||||
if NULL != (stored_value = @backend.fetch(key, NULL))
|
||||
@backend[key] = new_value
|
||||
stored_value
|
||||
end
|
||||
end
|
||||
|
||||
def compute_if_present(key)
|
||||
if NULL != (stored_value = @backend.fetch(key, NULL))
|
||||
store_computed_value(key, yield(stored_value))
|
||||
end
|
||||
end
|
||||
|
||||
def compute(key)
|
||||
store_computed_value(key, yield(get_or_default(key, nil)))
|
||||
end
|
||||
|
||||
def merge_pair(key, value)
|
||||
if NULL == (stored_value = @backend.fetch(key, NULL))
|
||||
@backend[key] = value
|
||||
else
|
||||
store_computed_value(key, yield(stored_value))
|
||||
end
|
||||
end
|
||||
|
||||
def get_and_set(key, value)
|
||||
stored_value = get_or_default(key, nil)
|
||||
@backend[key] = value
|
||||
stored_value
|
||||
end
|
||||
|
||||
def key?(key)
|
||||
@backend.key?(key)
|
||||
end
|
||||
|
||||
def delete(key)
|
||||
@backend.delete(key)
|
||||
end
|
||||
|
||||
def delete_pair(key, value)
|
||||
if pair?(key, value)
|
||||
@backend.delete(key)
|
||||
true
|
||||
else
|
||||
false
|
||||
end
|
||||
end
|
||||
|
||||
def clear
|
||||
@backend.clear
|
||||
self
|
||||
end
|
||||
|
||||
def each_pair
|
||||
dupped_backend.each_pair do |k, v|
|
||||
yield k, v
|
||||
end
|
||||
self
|
||||
end
|
||||
|
||||
def size
|
||||
@backend.size
|
||||
end
|
||||
|
||||
def get_or_default(key, default_value)
|
||||
@backend.fetch(key, default_value)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def set_backend(default_proc)
|
||||
if default_proc
|
||||
@backend = ::Hash.new { |_h, key| default_proc.call(self, key) }
|
||||
else
|
||||
@backend = {}
|
||||
end
|
||||
end
|
||||
|
||||
def initialize_copy(other)
|
||||
super
|
||||
set_backend(@default_proc)
|
||||
self
|
||||
end
|
||||
|
||||
def dupped_backend
|
||||
@backend.dup
|
||||
end
|
||||
|
||||
def pair?(key, expected_value)
|
||||
NULL != (stored_value = @backend.fetch(key, NULL)) && expected_value.equal?(stored_value)
|
||||
end
|
||||
|
||||
def store_computed_value(key, new_value)
|
||||
if new_value.nil?
|
||||
@backend.delete(key)
|
||||
nil
|
||||
else
|
||||
@backend[key] = new_value
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
+85
@@ -0,0 +1,85 @@
|
||||
require 'concurrent/collection/map/non_concurrent_map_backend'
|
||||
|
||||
module Concurrent
|
||||
|
||||
# @!visibility private
|
||||
module Collection
|
||||
|
||||
# @!visibility private
|
||||
class SynchronizedMapBackend < NonConcurrentMapBackend
|
||||
|
||||
def initialize(*args, &block)
|
||||
super
|
||||
|
||||
# WARNING: Mutex is a non-reentrant lock, so the synchronized methods are
|
||||
# not allowed to call each other.
|
||||
@mutex = Mutex.new
|
||||
end
|
||||
|
||||
def [](key)
|
||||
@mutex.synchronize { super }
|
||||
end
|
||||
|
||||
def []=(key, value)
|
||||
@mutex.synchronize { super }
|
||||
end
|
||||
|
||||
def compute_if_absent(key)
|
||||
@mutex.synchronize { super }
|
||||
end
|
||||
|
||||
def compute_if_present(key)
|
||||
@mutex.synchronize { super }
|
||||
end
|
||||
|
||||
def compute(key)
|
||||
@mutex.synchronize { super }
|
||||
end
|
||||
|
||||
def merge_pair(key, value)
|
||||
@mutex.synchronize { super }
|
||||
end
|
||||
|
||||
def replace_pair(key, old_value, new_value)
|
||||
@mutex.synchronize { super }
|
||||
end
|
||||
|
||||
def replace_if_exists(key, new_value)
|
||||
@mutex.synchronize { super }
|
||||
end
|
||||
|
||||
def get_and_set(key, value)
|
||||
@mutex.synchronize { super }
|
||||
end
|
||||
|
||||
def key?(key)
|
||||
@mutex.synchronize { super }
|
||||
end
|
||||
|
||||
def delete(key)
|
||||
@mutex.synchronize { super }
|
||||
end
|
||||
|
||||
def delete_pair(key, value)
|
||||
@mutex.synchronize { super }
|
||||
end
|
||||
|
||||
def clear
|
||||
@mutex.synchronize { super }
|
||||
end
|
||||
|
||||
def size
|
||||
@mutex.synchronize { super }
|
||||
end
|
||||
|
||||
def get_or_default(key, default_value)
|
||||
@mutex.synchronize { super }
|
||||
end
|
||||
|
||||
private
|
||||
def dupped_backend
|
||||
@mutex.synchronize { super }
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
module Concurrent
|
||||
|
||||
# @!visibility private
|
||||
module Collection
|
||||
|
||||
# @!visibility private
|
||||
class TruffleRubyMapBackend < TruffleRuby::ConcurrentMap
|
||||
def initialize(options = nil)
|
||||
options ||= {}
|
||||
super(initial_capacity: options[:initial_capacity], load_factor: options[:load_factor])
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
Reference in New Issue
Block a user