concurrent-ruby 1.1.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (143) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +478 -0
  3. data/Gemfile +41 -0
  4. data/LICENSE.md +23 -0
  5. data/README.md +381 -0
  6. data/Rakefile +327 -0
  7. data/ext/concurrent-ruby/ConcurrentRubyService.java +17 -0
  8. data/ext/concurrent-ruby/com/concurrent_ruby/ext/AtomicReferenceLibrary.java +175 -0
  9. data/ext/concurrent-ruby/com/concurrent_ruby/ext/JRubyMapBackendLibrary.java +248 -0
  10. data/ext/concurrent-ruby/com/concurrent_ruby/ext/JavaAtomicBooleanLibrary.java +93 -0
  11. data/ext/concurrent-ruby/com/concurrent_ruby/ext/JavaAtomicFixnumLibrary.java +113 -0
  12. data/ext/concurrent-ruby/com/concurrent_ruby/ext/JavaSemaphoreLibrary.java +159 -0
  13. data/ext/concurrent-ruby/com/concurrent_ruby/ext/SynchronizationLibrary.java +307 -0
  14. data/ext/concurrent-ruby/com/concurrent_ruby/ext/jsr166e/ConcurrentHashMap.java +31 -0
  15. data/ext/concurrent-ruby/com/concurrent_ruby/ext/jsr166e/ConcurrentHashMapV8.java +3863 -0
  16. data/ext/concurrent-ruby/com/concurrent_ruby/ext/jsr166e/LongAdder.java +203 -0
  17. data/ext/concurrent-ruby/com/concurrent_ruby/ext/jsr166e/Striped64.java +342 -0
  18. data/ext/concurrent-ruby/com/concurrent_ruby/ext/jsr166e/nounsafe/ConcurrentHashMapV8.java +3800 -0
  19. data/ext/concurrent-ruby/com/concurrent_ruby/ext/jsr166e/nounsafe/LongAdder.java +204 -0
  20. data/ext/concurrent-ruby/com/concurrent_ruby/ext/jsr166e/nounsafe/Striped64.java +291 -0
  21. data/ext/concurrent-ruby/com/concurrent_ruby/ext/jsr166y/ThreadLocalRandom.java +199 -0
  22. data/lib/concurrent-ruby.rb +1 -0
  23. data/lib/concurrent.rb +134 -0
  24. data/lib/concurrent/agent.rb +587 -0
  25. data/lib/concurrent/array.rb +66 -0
  26. data/lib/concurrent/async.rb +459 -0
  27. data/lib/concurrent/atom.rb +222 -0
  28. data/lib/concurrent/atomic/abstract_thread_local_var.rb +66 -0
  29. data/lib/concurrent/atomic/atomic_boolean.rb +126 -0
  30. data/lib/concurrent/atomic/atomic_fixnum.rb +143 -0
  31. data/lib/concurrent/atomic/atomic_markable_reference.rb +164 -0
  32. data/lib/concurrent/atomic/atomic_reference.rb +204 -0
  33. data/lib/concurrent/atomic/count_down_latch.rb +100 -0
  34. data/lib/concurrent/atomic/cyclic_barrier.rb +128 -0
  35. data/lib/concurrent/atomic/event.rb +109 -0
  36. data/lib/concurrent/atomic/java_count_down_latch.rb +42 -0
  37. data/lib/concurrent/atomic/java_thread_local_var.rb +37 -0
  38. data/lib/concurrent/atomic/mutex_atomic_boolean.rb +62 -0
  39. data/lib/concurrent/atomic/mutex_atomic_fixnum.rb +75 -0
  40. data/lib/concurrent/atomic/mutex_count_down_latch.rb +44 -0
  41. data/lib/concurrent/atomic/mutex_semaphore.rb +115 -0
  42. data/lib/concurrent/atomic/read_write_lock.rb +254 -0
  43. data/lib/concurrent/atomic/reentrant_read_write_lock.rb +379 -0
  44. data/lib/concurrent/atomic/ruby_thread_local_var.rb +161 -0
  45. data/lib/concurrent/atomic/semaphore.rb +145 -0
  46. data/lib/concurrent/atomic/thread_local_var.rb +104 -0
  47. data/lib/concurrent/atomic_reference/mutex_atomic.rb +56 -0
  48. data/lib/concurrent/atomic_reference/numeric_cas_wrapper.rb +28 -0
  49. data/lib/concurrent/atomics.rb +10 -0
  50. data/lib/concurrent/collection/copy_on_notify_observer_set.rb +107 -0
  51. data/lib/concurrent/collection/copy_on_write_observer_set.rb +111 -0
  52. data/lib/concurrent/collection/java_non_concurrent_priority_queue.rb +84 -0
  53. data/lib/concurrent/collection/lock_free_stack.rb +158 -0
  54. data/lib/concurrent/collection/map/atomic_reference_map_backend.rb +927 -0
  55. data/lib/concurrent/collection/map/mri_map_backend.rb +66 -0
  56. data/lib/concurrent/collection/map/non_concurrent_map_backend.rb +140 -0
  57. data/lib/concurrent/collection/map/synchronized_map_backend.rb +82 -0
  58. data/lib/concurrent/collection/non_concurrent_priority_queue.rb +143 -0
  59. data/lib/concurrent/collection/ruby_non_concurrent_priority_queue.rb +150 -0
  60. data/lib/concurrent/concern/deprecation.rb +34 -0
  61. data/lib/concurrent/concern/dereferenceable.rb +73 -0
  62. data/lib/concurrent/concern/logging.rb +32 -0
  63. data/lib/concurrent/concern/obligation.rb +220 -0
  64. data/lib/concurrent/concern/observable.rb +110 -0
  65. data/lib/concurrent/concurrent_ruby.jar +0 -0
  66. data/lib/concurrent/configuration.rb +184 -0
  67. data/lib/concurrent/constants.rb +8 -0
  68. data/lib/concurrent/dataflow.rb +81 -0
  69. data/lib/concurrent/delay.rb +199 -0
  70. data/lib/concurrent/errors.rb +69 -0
  71. data/lib/concurrent/exchanger.rb +352 -0
  72. data/lib/concurrent/executor/abstract_executor_service.rb +134 -0
  73. data/lib/concurrent/executor/cached_thread_pool.rb +62 -0
  74. data/lib/concurrent/executor/executor_service.rb +185 -0
  75. data/lib/concurrent/executor/fixed_thread_pool.rb +206 -0
  76. data/lib/concurrent/executor/immediate_executor.rb +66 -0
  77. data/lib/concurrent/executor/indirect_immediate_executor.rb +44 -0
  78. data/lib/concurrent/executor/java_executor_service.rb +91 -0
  79. data/lib/concurrent/executor/java_single_thread_executor.rb +29 -0
  80. data/lib/concurrent/executor/java_thread_pool_executor.rb +123 -0
  81. data/lib/concurrent/executor/ruby_executor_service.rb +78 -0
  82. data/lib/concurrent/executor/ruby_single_thread_executor.rb +22 -0
  83. data/lib/concurrent/executor/ruby_thread_pool_executor.rb +362 -0
  84. data/lib/concurrent/executor/safe_task_executor.rb +35 -0
  85. data/lib/concurrent/executor/serial_executor_service.rb +34 -0
  86. data/lib/concurrent/executor/serialized_execution.rb +107 -0
  87. data/lib/concurrent/executor/serialized_execution_delegator.rb +28 -0
  88. data/lib/concurrent/executor/simple_executor_service.rb +100 -0
  89. data/lib/concurrent/executor/single_thread_executor.rb +56 -0
  90. data/lib/concurrent/executor/thread_pool_executor.rb +87 -0
  91. data/lib/concurrent/executor/timer_set.rb +173 -0
  92. data/lib/concurrent/executors.rb +20 -0
  93. data/lib/concurrent/future.rb +141 -0
  94. data/lib/concurrent/hash.rb +59 -0
  95. data/lib/concurrent/immutable_struct.rb +93 -0
  96. data/lib/concurrent/ivar.rb +207 -0
  97. data/lib/concurrent/map.rb +337 -0
  98. data/lib/concurrent/maybe.rb +229 -0
  99. data/lib/concurrent/mutable_struct.rb +229 -0
  100. data/lib/concurrent/mvar.rb +242 -0
  101. data/lib/concurrent/options.rb +42 -0
  102. data/lib/concurrent/promise.rb +579 -0
  103. data/lib/concurrent/promises.rb +2167 -0
  104. data/lib/concurrent/re_include.rb +58 -0
  105. data/lib/concurrent/scheduled_task.rb +318 -0
  106. data/lib/concurrent/set.rb +66 -0
  107. data/lib/concurrent/settable_struct.rb +129 -0
  108. data/lib/concurrent/synchronization.rb +30 -0
  109. data/lib/concurrent/synchronization/abstract_lockable_object.rb +98 -0
  110. data/lib/concurrent/synchronization/abstract_object.rb +24 -0
  111. data/lib/concurrent/synchronization/abstract_struct.rb +160 -0
  112. data/lib/concurrent/synchronization/condition.rb +60 -0
  113. data/lib/concurrent/synchronization/jruby_lockable_object.rb +13 -0
  114. data/lib/concurrent/synchronization/jruby_object.rb +45 -0
  115. data/lib/concurrent/synchronization/lock.rb +36 -0
  116. data/lib/concurrent/synchronization/lockable_object.rb +74 -0
  117. data/lib/concurrent/synchronization/mri_object.rb +44 -0
  118. data/lib/concurrent/synchronization/mutex_lockable_object.rb +76 -0
  119. data/lib/concurrent/synchronization/object.rb +183 -0
  120. data/lib/concurrent/synchronization/rbx_lockable_object.rb +65 -0
  121. data/lib/concurrent/synchronization/rbx_object.rb +49 -0
  122. data/lib/concurrent/synchronization/truffleruby_object.rb +47 -0
  123. data/lib/concurrent/synchronization/volatile.rb +36 -0
  124. data/lib/concurrent/thread_safe/synchronized_delegator.rb +50 -0
  125. data/lib/concurrent/thread_safe/util.rb +16 -0
  126. data/lib/concurrent/thread_safe/util/adder.rb +74 -0
  127. data/lib/concurrent/thread_safe/util/cheap_lockable.rb +118 -0
  128. data/lib/concurrent/thread_safe/util/data_structures.rb +63 -0
  129. data/lib/concurrent/thread_safe/util/power_of_two_tuple.rb +38 -0
  130. data/lib/concurrent/thread_safe/util/striped64.rb +246 -0
  131. data/lib/concurrent/thread_safe/util/volatile.rb +75 -0
  132. data/lib/concurrent/thread_safe/util/xor_shift_random.rb +50 -0
  133. data/lib/concurrent/timer_task.rb +334 -0
  134. data/lib/concurrent/tuple.rb +86 -0
  135. data/lib/concurrent/tvar.rb +258 -0
  136. data/lib/concurrent/utility/at_exit.rb +97 -0
  137. data/lib/concurrent/utility/engine.rb +56 -0
  138. data/lib/concurrent/utility/monotonic_time.rb +58 -0
  139. data/lib/concurrent/utility/native_extension_loader.rb +79 -0
  140. data/lib/concurrent/utility/native_integer.rb +53 -0
  141. data/lib/concurrent/utility/processor_counter.rb +158 -0
  142. data/lib/concurrent/version.rb +3 -0
  143. metadata +193 -0
@@ -0,0 +1,47 @@
1
+ module Concurrent
2
+ module Synchronization
3
+
4
+ # @!visibility private
5
+ module TruffleRubyAttrVolatile
6
+ def self.included(base)
7
+ base.extend(ClassMethods)
8
+ end
9
+
10
+ module ClassMethods
11
+ def attr_volatile(*names)
12
+ names.each do |name|
13
+ ivar = :"@volatile_#{name}"
14
+
15
+ class_eval <<-RUBY, __FILE__, __LINE__ + 1
16
+ def #{name}
17
+ full_memory_barrier
18
+ #{ivar}
19
+ end
20
+
21
+ def #{name}=(value)
22
+ #{ivar} = value
23
+ full_memory_barrier
24
+ end
25
+ RUBY
26
+ end
27
+
28
+ names.map { |n| [n, :"#{n}="] }.flatten
29
+ end
30
+ end
31
+
32
+ def full_memory_barrier
33
+ TruffleRuby.full_memory_barrier
34
+ end
35
+ end
36
+
37
+ # @!visibility private
38
+ # @!macro internal_implementation_note
39
+ class TruffleRubyObject < AbstractObject
40
+ include TruffleRubyAttrVolatile
41
+
42
+ def initialize
43
+ # nothing to do
44
+ end
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,36 @@
1
+ module Concurrent
2
+ module Synchronization
3
+
4
+ # Volatile adds the attr_volatile class method when included.
5
+ #
6
+ # @example
7
+ # class Foo
8
+ # include Concurrent::Synchronization::Volatile
9
+ #
10
+ # attr_volatile :bar
11
+ #
12
+ # def initialize
13
+ # self.bar = 1
14
+ # end
15
+ # end
16
+ #
17
+ # foo = Foo.new
18
+ # foo.bar
19
+ # => 1
20
+ # foo.bar = 2
21
+ # => 2
22
+
23
+ Volatile = case
24
+ when Concurrent.on_cruby?
25
+ MriAttrVolatile
26
+ when Concurrent.on_jruby?
27
+ JRubyAttrVolatile
28
+ when Concurrent.on_rbx?
29
+ RbxAttrVolatile
30
+ when Concurrent.on_truffleruby?
31
+ TruffleRubyAttrVolatile
32
+ else
33
+ MriAttrVolatile
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,50 @@
1
+ require 'delegate'
2
+ require 'monitor'
3
+
4
+ module Concurrent
5
+ unless defined?(SynchronizedDelegator)
6
+
7
+ # This class provides a trivial way to synchronize all calls to a given object
8
+ # by wrapping it with a `Delegator` that performs `Monitor#enter/exit` calls
9
+ # around the delegated `#send`. Example:
10
+ #
11
+ # array = [] # not thread-safe on many impls
12
+ # array = SynchronizedDelegator.new([]) # thread-safe
13
+ #
14
+ # A simple `Monitor` provides a very coarse-grained way to synchronize a given
15
+ # object, in that it will cause synchronization for methods that have no need
16
+ # for it, but this is a trivial way to get thread-safety where none may exist
17
+ # currently on some implementations.
18
+ #
19
+ # This class is currently being considered for inclusion into stdlib, via
20
+ # https://bugs.ruby-lang.org/issues/8556
21
+ #
22
+ # @!visibility private
23
+ class SynchronizedDelegator < SimpleDelegator
24
+ def setup
25
+ @old_abort = Thread.abort_on_exception
26
+ Thread.abort_on_exception = true
27
+ end
28
+
29
+ def teardown
30
+ Thread.abort_on_exception = @old_abort
31
+ end
32
+
33
+ def initialize(obj)
34
+ __setobj__(obj)
35
+ @monitor = Monitor.new
36
+ end
37
+
38
+ def method_missing(method, *args, &block)
39
+ monitor = @monitor
40
+ begin
41
+ monitor.enter
42
+ super
43
+ ensure
44
+ monitor.exit
45
+ end
46
+ end
47
+
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,16 @@
1
+ module Concurrent
2
+
3
+ # @!visibility private
4
+ module ThreadSafe
5
+
6
+ # @!visibility private
7
+ module Util
8
+
9
+ # TODO (pitr-ch 15-Oct-2016): migrate to Utility::NativeInteger
10
+ FIXNUM_BIT_SIZE = (0.size * 8) - 2
11
+ MAX_INT = (2 ** FIXNUM_BIT_SIZE) - 1
12
+ # TODO (pitr-ch 15-Oct-2016): migrate to Utility::ProcessorCounter
13
+ CPU_COUNT = 16 # is there a way to determine this?
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,74 @@
1
+ require 'concurrent/thread_safe/util'
2
+ require 'concurrent/thread_safe/util/striped64'
3
+
4
+ module Concurrent
5
+
6
+ # @!visibility private
7
+ module ThreadSafe
8
+
9
+ # @!visibility private
10
+ module Util
11
+
12
+ # A Ruby port of the Doug Lea's jsr166e.LondAdder class version 1.8
13
+ # available in public domain.
14
+ #
15
+ # Original source code available here:
16
+ # http://gee.cs.oswego.edu/cgi-bin/viewcvs.cgi/jsr166/src/jsr166e/LongAdder.java?revision=1.8
17
+ #
18
+ # One or more variables that together maintain an initially zero
19
+ # sum. When updates (method +add+) are contended across threads,
20
+ # the set of variables may grow dynamically to reduce contention.
21
+ # Method +sum+ returns the current total combined across the
22
+ # variables maintaining the sum.
23
+ #
24
+ # This class is usually preferable to single +Atomic+ reference when
25
+ # multiple threads update a common sum that is used for purposes such
26
+ # as collecting statistics, not for fine-grained synchronization
27
+ # control. Under low update contention, the two classes have similar
28
+ # characteristics. But under high contention, expected throughput of
29
+ # this class is significantly higher, at the expense of higher space
30
+ # consumption.
31
+ #
32
+ # @!visibility private
33
+ class Adder < Striped64
34
+ # Adds the given value.
35
+ def add(x)
36
+ if (current_cells = cells) || !cas_base_computed {|current_base| current_base + x}
37
+ was_uncontended = true
38
+ hash = hash_code
39
+ unless current_cells && (cell = current_cells.volatile_get_by_hash(hash)) && (was_uncontended = cell.cas_computed {|current_value| current_value + x})
40
+ retry_update(x, hash, was_uncontended) {|current_value| current_value + x}
41
+ end
42
+ end
43
+ end
44
+
45
+ def increment
46
+ add(1)
47
+ end
48
+
49
+ def decrement
50
+ add(-1)
51
+ end
52
+
53
+ # Returns the current sum. The returned value is _NOT_ an
54
+ # atomic snapshot: Invocation in the absence of concurrent
55
+ # updates returns an accurate result, but concurrent updates that
56
+ # occur while the sum is being calculated might not be
57
+ # incorporated.
58
+ def sum
59
+ x = base
60
+ if current_cells = cells
61
+ current_cells.each do |cell|
62
+ x += cell.value if cell
63
+ end
64
+ end
65
+ x
66
+ end
67
+
68
+ def reset
69
+ internal_reset(0)
70
+ end
71
+ end
72
+ end
73
+ end
74
+ end
@@ -0,0 +1,118 @@
1
+ require 'concurrent/thread_safe/util'
2
+ require 'concurrent/thread_safe/util/volatile'
3
+
4
+ module Concurrent
5
+
6
+ # @!visibility private
7
+ module ThreadSafe
8
+
9
+ # @!visibility private
10
+ module Util
11
+
12
+ # Provides a cheapest possible (mainly in terms of memory usage) +Mutex+
13
+ # with the +ConditionVariable+ bundled in.
14
+ #
15
+ # Usage:
16
+ # class A
17
+ # include CheapLockable
18
+ #
19
+ # def do_exlusively
20
+ # cheap_synchronize { yield }
21
+ # end
22
+ #
23
+ # def wait_for_something
24
+ # cheap_synchronize do
25
+ # cheap_wait until resource_available?
26
+ # do_something
27
+ # cheap_broadcast # wake up others
28
+ # end
29
+ # end
30
+ # end
31
+ #
32
+ # @!visibility private
33
+ module CheapLockable
34
+ private
35
+ engine = defined?(RUBY_ENGINE) && RUBY_ENGINE
36
+ if engine == 'rbx'
37
+ # Making use of the Rubinius' ability to lock via object headers to avoid the overhead of the extra Mutex objects.
38
+ def cheap_synchronize
39
+ Rubinius.lock(self)
40
+ begin
41
+ yield
42
+ ensure
43
+ Rubinius.unlock(self)
44
+ end
45
+ end
46
+
47
+ def cheap_wait
48
+ wchan = Rubinius::Channel.new
49
+
50
+ begin
51
+ waiters = @waiters ||= []
52
+ waiters.push wchan
53
+ Rubinius.unlock(self)
54
+ signaled = wchan.receive_timeout nil
55
+ ensure
56
+ Rubinius.lock(self)
57
+
58
+ unless signaled or waiters.delete(wchan)
59
+ # we timed out, but got signaled afterwards (e.g. while waiting to
60
+ # acquire @lock), so pass that signal on to the next waiter
61
+ waiters.shift << true unless waiters.empty?
62
+ end
63
+ end
64
+
65
+ self
66
+ end
67
+
68
+ def cheap_broadcast
69
+ waiters = @waiters ||= []
70
+ waiters.shift << true until waiters.empty?
71
+ self
72
+ end
73
+ elsif engine == 'jruby'
74
+ # Use Java's native synchronized (this) { wait(); notifyAll(); } to avoid the overhead of the extra Mutex objects
75
+ require 'jruby'
76
+
77
+ def cheap_synchronize
78
+ JRuby.reference0(self).synchronized { yield }
79
+ end
80
+
81
+ def cheap_wait
82
+ JRuby.reference0(self).wait
83
+ end
84
+
85
+ def cheap_broadcast
86
+ JRuby.reference0(self).notify_all
87
+ end
88
+ else
89
+ require 'thread'
90
+
91
+ extend Volatile
92
+ attr_volatile :mutex
93
+
94
+ # Non-reentrant Mutex#syncrhonize
95
+ def cheap_synchronize
96
+ true until (my_mutex = mutex) || cas_mutex(nil, my_mutex = Mutex.new)
97
+ my_mutex.synchronize { yield }
98
+ end
99
+
100
+ # Releases this object's +cheap_synchronize+ lock and goes to sleep waiting for other threads to +cheap_broadcast+, reacquires the lock on wakeup.
101
+ # Must only be called in +cheap_broadcast+'s block.
102
+ def cheap_wait
103
+ conditional_variable = @conditional_variable ||= ConditionVariable.new
104
+ conditional_variable.wait(mutex)
105
+ end
106
+
107
+ # Wakes up all threads waiting for this object's +cheap_synchronize+ lock.
108
+ # Must only be called in +cheap_broadcast+'s block.
109
+ def cheap_broadcast
110
+ if conditional_variable = @conditional_variable
111
+ conditional_variable.broadcast
112
+ end
113
+ end
114
+ end
115
+ end
116
+ end
117
+ end
118
+ end
@@ -0,0 +1,63 @@
1
+ require 'concurrent/thread_safe/util'
2
+
3
+ # Shim for TruffleRuby.synchronized
4
+ if Concurrent.on_truffleruby? && !TruffleRuby.respond_to?(:synchronized)
5
+ module TruffleRuby
6
+ def self.synchronized(object, &block)
7
+ Truffle::System.synchronized(object, &block)
8
+ end
9
+ end
10
+ end
11
+
12
+ module Concurrent
13
+ module ThreadSafe
14
+ module Util
15
+ def self.make_synchronized_on_rbx(klass)
16
+ klass.class_eval do
17
+ private
18
+
19
+ def _mon_initialize
20
+ @_monitor = Monitor.new unless @_monitor # avoid double initialisation
21
+ end
22
+
23
+ def self.new(*args)
24
+ obj = super(*args)
25
+ obj.send(:_mon_initialize)
26
+ obj
27
+ end
28
+ end
29
+
30
+ klass.superclass.instance_methods(false).each do |method|
31
+ case method
32
+ when :new_range, :new_reserved
33
+ klass.class_eval <<-RUBY, __FILE__, __LINE__ + 1
34
+ def #{method}(*args)
35
+ obj = super
36
+ obj.send(:_mon_initialize)
37
+ obj
38
+ end
39
+ RUBY
40
+ else
41
+ klass.class_eval <<-RUBY, __FILE__, __LINE__ + 1
42
+ def #{method}(*args)
43
+ monitor = @_monitor
44
+ monitor or raise("BUG: Internal monitor was not properly initialized. Please report this to the concurrent-ruby developers.")
45
+ monitor.synchronize { super }
46
+ end
47
+ RUBY
48
+ end
49
+ end
50
+ end
51
+
52
+ def self.make_synchronized_on_truffleruby(klass)
53
+ klass.superclass.instance_methods(false).each do |method|
54
+ klass.class_eval <<-RUBY, __FILE__, __LINE__ + 1
55
+ def #{method}(*args, &block)
56
+ TruffleRuby.synchronized(self) { super(*args, &block) }
57
+ end
58
+ RUBY
59
+ end
60
+ end
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,38 @@
1
+ require 'concurrent/thread_safe/util'
2
+ require 'concurrent/tuple'
3
+
4
+ module Concurrent
5
+
6
+ # @!visibility private
7
+ module ThreadSafe
8
+
9
+ # @!visibility private
10
+ module Util
11
+
12
+ # @!visibility private
13
+ class PowerOfTwoTuple < Concurrent::Tuple
14
+
15
+ def initialize(size)
16
+ raise ArgumentError, "size must be a power of 2 (#{size.inspect} provided)" unless size > 0 && size & (size - 1) == 0
17
+ super(size)
18
+ end
19
+
20
+ def hash_to_index(hash)
21
+ (size - 1) & hash
22
+ end
23
+
24
+ def volatile_get_by_hash(hash)
25
+ volatile_get(hash_to_index(hash))
26
+ end
27
+
28
+ def volatile_set_by_hash(hash, value)
29
+ volatile_set(hash_to_index(hash), value)
30
+ end
31
+
32
+ def next_in_size_table
33
+ self.class.new(size << 1)
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end