concurrent-ruby 1.1.0.pre2 → 1.1.1
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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +21 -0
- data/Gemfile +2 -2
- data/README.md +6 -2
- data/Rakefile +51 -16
- data/ext/concurrent-ruby/com/concurrent_ruby/ext/SynchronizationLibrary.java +13 -11
- data/lib/concurrent.rb +2 -0
- data/lib/concurrent/atomic/atomic_reference.rb +11 -1
- data/lib/concurrent/atomic/java_count_down_latch.rb +4 -2
- data/lib/concurrent/atomic/mutex_atomic_boolean.rb +2 -0
- data/lib/concurrent/concurrent_ruby.jar +0 -0
- data/lib/concurrent/exchanger.rb +10 -6
- data/lib/concurrent/map.rb +159 -57
- data/lib/concurrent/thread_safe/util/data_structures.rb +10 -2
- data/lib/concurrent/utility/193.rb +17 -0
- data/lib/concurrent/utility/engine.rb +2 -2
- data/lib/concurrent/version.rb +2 -2
- metadata +6 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 8d042c846e692138ba0eea6efbabb53794abbaae207477dc5e549abac9fab266
|
4
|
+
data.tar.gz: 34678c0ec6d519d5beac0b12a8c6116d4eb1ff29dd620ba03df851d086b04adc
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9b75559855ce216316a81bb68a9fcb1e74dceed4baa8e816d2e02cd12af50745e88f9afba7470681a8f47297a297fe9fd79e82ace4b5f63410197469eab45523
|
7
|
+
data.tar.gz: 79e63eb2ef9ab15e9fd5d1d777ae027e68b399ec885d85bc8156f9edad741ecf4eb20fc063357068018ef932c18e7263466ef64cee7592bf50b39433e83b94a7
|
data/CHANGELOG.md
CHANGED
@@ -1,9 +1,30 @@
|
|
1
1
|
## Current
|
2
2
|
|
3
|
+
## Release v1.1.1, edge v0.4.1 (1 Nov 2018)
|
4
|
+
|
5
|
+
* (#768) add support for 1.9.3 back
|
6
|
+
|
7
|
+
## Release v1.1.0, edge v0.4.0 (31 OCt 2018) (yanked)
|
8
|
+
|
9
|
+
* (#768) yanked because of issues with removed 1.9.3 support
|
10
|
+
|
11
|
+
## Release v1.1.0.pre2, edge v0.4.0.pre2 (18 Sep 2018)
|
12
|
+
|
13
|
+
concurrent-ruby:
|
14
|
+
|
15
|
+
* fixed documentation and README links
|
16
|
+
* fix Set for TruffleRuby and Rubinius
|
17
|
+
* use properly supported TruffleRuby APIs
|
18
|
+
|
19
|
+
concurrent-ruby-edge:
|
20
|
+
|
21
|
+
* add Promises.zip_futures_over_on
|
22
|
+
|
3
23
|
## Release v1.1.0.pre1, edge v0.4.0.pre1 (15 Aug 2018)
|
4
24
|
|
5
25
|
concurrent-ruby:
|
6
26
|
|
27
|
+
* requires at least Ruby 2.0
|
7
28
|
* [Promises](http://ruby-concurrency.github.io/concurrent-ruby/1.1.0/Concurrent/Promises.html)
|
8
29
|
are moved from `concurrent-ruby-edge` to `concurrent-ruby`
|
9
30
|
* Add support for TruffleRuby
|
data/Gemfile
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
source 'https://rubygems.org'
|
2
2
|
|
3
|
-
|
3
|
+
require File.join(File.dirname(__FILE__ ), 'lib/concurrent/version')
|
4
4
|
|
5
5
|
no_path = ENV['NO_PATH']
|
6
6
|
options = no_path ? {} : { path: '.' }
|
@@ -19,7 +19,7 @@ end
|
|
19
19
|
group :documentation, optional: true do
|
20
20
|
gem 'yard', '~> 0.9.0', :require => false
|
21
21
|
gem 'redcarpet', '~> 3.0', platforms: :mri # understands github markdown
|
22
|
-
gem 'md-ruby-eval', '~> 0.
|
22
|
+
gem 'md-ruby-eval', '~> 0.3'
|
23
23
|
end
|
24
24
|
|
25
25
|
group :testing do
|
data/README.md
CHANGED
@@ -227,8 +227,12 @@ be obeyed though. Features developed in `concurrent-ruby-edge` are expected to m
|
|
227
227
|
|
228
228
|
## Supported Ruby versions
|
229
229
|
|
230
|
-
MRI 2.0 and above
|
231
|
-
|
230
|
+
* MRI 2.0 and above
|
231
|
+
* JRuby 9000
|
232
|
+
* TruffleRuby are supported.
|
233
|
+
* Any Ruby interpreter that is compliant with Ruby 2.0 or newer.
|
234
|
+
|
235
|
+
Actually we still support mri 1.9.3 and jruby 1.7.27 but we are looking at ways how to drop the support.
|
232
236
|
Java 8 is preferred for JRuby but every Java version on which JRuby 9000 runs is supported.
|
233
237
|
|
234
238
|
The legacy support for Rubinius is kept but it is no longer maintained, if you would like to help
|
data/Rakefile
CHANGED
@@ -2,6 +2,7 @@
|
|
2
2
|
|
3
3
|
require_relative 'lib/concurrent/version'
|
4
4
|
require_relative 'lib/concurrent/utility/engine'
|
5
|
+
require_relative 'lib/concurrent/utility/193'
|
5
6
|
|
6
7
|
core_gemspec = Gem::Specification.load File.join(__dir__, 'concurrent-ruby.gemspec')
|
7
8
|
ext_gemspec = Gem::Specification.load File.join(__dir__, 'concurrent-ruby-ext.gemspec')
|
@@ -9,7 +10,29 @@ edge_gemspec = Gem::Specification.load File.join(__dir__, 'concurrent-ruby-edge.
|
|
9
10
|
|
10
11
|
require 'rake/javaextensiontask'
|
11
12
|
|
12
|
-
|
13
|
+
JRUBY_JAR_PATH = '/usr/local/opt/rbenv/versions/jruby-9.1.17.0/lib/jruby.jar'
|
14
|
+
|
15
|
+
class ConcurrentRubyJavaExtensionTask < Rake::JavaExtensionTask
|
16
|
+
def java_classpath_arg(*args)
|
17
|
+
jruby_cpath = nil
|
18
|
+
if RUBY_PLATFORM =~ /java/
|
19
|
+
begin
|
20
|
+
cpath = Java::java.lang.System.getProperty('java.class.path').split(File::PATH_SEPARATOR)
|
21
|
+
cpath += Java::java.lang.System.getProperty('sun.boot.class.path').split(File::PATH_SEPARATOR)
|
22
|
+
jruby_cpath = cpath.compact.join(File::PATH_SEPARATOR)
|
23
|
+
rescue => e
|
24
|
+
end
|
25
|
+
end
|
26
|
+
unless jruby_cpath
|
27
|
+
jruby_cpath = JRUBY_JAR_PATH
|
28
|
+
raise "#{jruby_cpath} does not exist" unless File.exist? jruby_cpath
|
29
|
+
end
|
30
|
+
jruby_cpath += File::PATH_SEPARATOR + args.join(File::PATH_SEPARATOR) unless args.empty?
|
31
|
+
jruby_cpath ? "-cp \"#{jruby_cpath}\"" : ""
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
ConcurrentRubyJavaExtensionTask.new('concurrent_ruby', core_gemspec) do |ext|
|
13
36
|
ext.ext_dir = 'ext/concurrent-ruby'
|
14
37
|
ext.lib_dir = 'lib/concurrent'
|
15
38
|
end
|
@@ -70,9 +93,9 @@ begin
|
|
70
93
|
desc '* test packaged and installed gems instead of local files'
|
71
94
|
task :installed do
|
72
95
|
Dir.chdir(__dir__) do
|
73
|
-
sh
|
74
|
-
sh
|
75
|
-
sh
|
96
|
+
sh "gem install pkg/concurrent-ruby-#{Concurrent::VERSION}.gem"
|
97
|
+
sh "gem install pkg/concurrent-ruby-ext-#{Concurrent::VERSION}.gem" if Concurrent.on_cruby?
|
98
|
+
sh "gem install pkg/concurrent-ruby-edge-#{Concurrent::EDGE_VERSION}.gem"
|
76
99
|
ENV['NO_PATH'] = 'true'
|
77
100
|
sh 'bundle update'
|
78
101
|
sh 'bundle exec rake spec:ci'
|
@@ -132,6 +155,7 @@ begin
|
|
132
155
|
"{Concurrent::#{$1} #{$1}}"
|
133
156
|
end
|
134
157
|
end
|
158
|
+
FileUtils.mkpath 'tmp'
|
135
159
|
File.write 'tmp/README.md', content
|
136
160
|
end
|
137
161
|
end
|
@@ -199,18 +223,29 @@ namespace :release do
|
|
199
223
|
# Depends on environment of @pitr-ch
|
200
224
|
|
201
225
|
mri_version = '2.5.1'
|
202
|
-
jruby_version = 'jruby-9.1.17.
|
226
|
+
jruby_version = 'jruby-9.1.17.1'
|
203
227
|
|
204
228
|
task :checks => "yard:#{current_yard_version_name}:uptodate" do
|
205
229
|
Dir.chdir(__dir__) do
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
230
|
+
sh 'test -z "$(git status --porcelain)"' do |ok, res|
|
231
|
+
unless ok
|
232
|
+
begin
|
233
|
+
STDOUT.puts 'Command failed. Continue? (y/n)'
|
234
|
+
input = STDIN.gets.strip.downcase
|
235
|
+
end until %w(y n).include?(input)
|
236
|
+
exit 1 if input == 'n'
|
237
|
+
end
|
238
|
+
end
|
239
|
+
sh 'git fetch'
|
240
|
+
sh 'test $(git show-ref --verify --hash refs/heads/master) = ' +
|
241
|
+
'$(git show-ref --verify --hash refs/remotes/origin/master)' do |ok, res|
|
242
|
+
unless ok
|
243
|
+
begin
|
244
|
+
STDOUT.puts 'Command failed. Continue? (y/n)'
|
245
|
+
input = STDIN.gets.strip.downcase
|
246
|
+
end until %w(y n).include?(input)
|
247
|
+
exit 1 if input == 'n'
|
248
|
+
end
|
214
249
|
end
|
215
250
|
end
|
216
251
|
end
|
@@ -243,10 +278,10 @@ namespace :release do
|
|
243
278
|
namespace :publish do
|
244
279
|
task :ask do
|
245
280
|
begin
|
246
|
-
STDOUT.puts
|
281
|
+
STDOUT.puts 'Do you want to publish? (y/n)'
|
247
282
|
input = STDIN.gets.strip.downcase
|
248
283
|
end until %w(y n).include?(input)
|
249
|
-
|
284
|
+
exit 1 if input == 'n'
|
250
285
|
end
|
251
286
|
|
252
287
|
desc '** tag HEAD with current version and push to github'
|
@@ -254,7 +289,7 @@ namespace :release do
|
|
254
289
|
Dir.chdir(__dir__) do
|
255
290
|
sh "git tag v#{Concurrent::VERSION}"
|
256
291
|
sh "git tag edge-v#{Concurrent::EDGE_VERSION}"
|
257
|
-
sh "git push
|
292
|
+
sh "git push origin v#{Concurrent::VERSION} edge-v#{Concurrent::EDGE_VERSION}"
|
258
293
|
end
|
259
294
|
end
|
260
295
|
|
@@ -284,21 +284,23 @@ public class SynchronizationLibrary implements Library {
|
|
284
284
|
}
|
285
285
|
|
286
286
|
@JRubyMethod(name = "sleep_interruptibly", visibility = Visibility.PUBLIC, module = true)
|
287
|
-
public static IRubyObject sleepInterruptibly(ThreadContext context, IRubyObject receiver, Block block) {
|
287
|
+
public static IRubyObject sleepInterruptibly(final ThreadContext context, IRubyObject receiver, final Block block) {
|
288
288
|
try {
|
289
|
-
|
290
|
-
|
291
|
-
|
292
|
-
|
293
|
-
|
294
|
-
|
295
|
-
|
296
|
-
|
297
|
-
|
298
|
-
|
289
|
+
context.getThread().executeBlockingTask(new RubyThread.BlockingTask() {
|
290
|
+
@Override
|
291
|
+
public void run() throws InterruptedException {
|
292
|
+
block.call(context);
|
293
|
+
}
|
294
|
+
|
295
|
+
@Override
|
296
|
+
public void wakeup() {
|
297
|
+
context.getThread().getNativeThread().interrupt();
|
298
|
+
}
|
299
|
+
});
|
299
300
|
} catch (InterruptedException e) {
|
300
301
|
throw context.runtime.newThreadError("interrupted in Concurrent::Synchronization::JRuby.sleep_interruptibly");
|
301
302
|
}
|
303
|
+
return context.nil;
|
302
304
|
}
|
303
305
|
}
|
304
306
|
}
|
data/lib/concurrent.rb
CHANGED
@@ -2,6 +2,14 @@ require 'concurrent/synchronization'
|
|
2
2
|
require 'concurrent/utility/engine'
|
3
3
|
require 'concurrent/atomic_reference/numeric_cas_wrapper'
|
4
4
|
|
5
|
+
# Shim for TruffleRuby::AtomicReference
|
6
|
+
if Concurrent.on_truffleruby? && !defined?(TruffleRuby::AtomicReference)
|
7
|
+
# @!visibility private
|
8
|
+
module TruffleRuby
|
9
|
+
AtomicReference = Truffle::AtomicReference
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
5
13
|
module Concurrent
|
6
14
|
|
7
15
|
# Define update methods that use direct paths
|
@@ -155,8 +163,10 @@ module Concurrent
|
|
155
163
|
end
|
156
164
|
JavaAtomicReference
|
157
165
|
when Concurrent.on_truffleruby?
|
158
|
-
class TruffleRubyAtomicReference <
|
166
|
+
class TruffleRubyAtomicReference < TruffleRuby::AtomicReference
|
159
167
|
include AtomicDirectUpdate
|
168
|
+
alias_method :value, :get
|
169
|
+
alias_method :value=, :set
|
160
170
|
alias_method :compare_and_swap, :compare_and_set
|
161
171
|
alias_method :swap, :get_and_set
|
162
172
|
end
|
@@ -16,14 +16,16 @@ if Concurrent.on_jruby?
|
|
16
16
|
|
17
17
|
# @!macro count_down_latch_method_wait
|
18
18
|
def wait(timeout = nil)
|
19
|
+
result = nil
|
19
20
|
if timeout.nil?
|
20
21
|
Synchronization::JRuby.sleep_interruptibly { @latch.await }
|
21
|
-
true
|
22
|
+
result = true
|
22
23
|
else
|
23
24
|
Synchronization::JRuby.sleep_interruptibly do
|
24
|
-
@latch.await(1000 * timeout, java.util.concurrent.TimeUnit::MILLISECONDS)
|
25
|
+
result = @latch.await(1000 * timeout, java.util.concurrent.TimeUnit::MILLISECONDS)
|
25
26
|
end
|
26
27
|
end
|
28
|
+
result
|
27
29
|
end
|
28
30
|
|
29
31
|
# @!macro count_down_latch_method_count_down
|
Binary file
|
data/lib/concurrent/exchanger.rb
CHANGED
@@ -141,8 +141,8 @@ module Concurrent
|
|
141
141
|
|
142
142
|
def initialize(item)
|
143
143
|
super()
|
144
|
-
@Item
|
145
|
-
@Latch
|
144
|
+
@Item = item
|
145
|
+
@Latch = Concurrent::CountDownLatch.new
|
146
146
|
self.value = nil
|
147
147
|
end
|
148
148
|
|
@@ -252,8 +252,8 @@ module Concurrent
|
|
252
252
|
# - Wake the sleeping occupier
|
253
253
|
# - Return the occupier's item
|
254
254
|
|
255
|
-
value
|
256
|
-
me
|
255
|
+
value = NULL if value.nil? # The sentinel allows nil to be a valid value
|
256
|
+
me = Node.new(value) # create my node in case I need to occupy
|
257
257
|
end_at = Concurrent.monotonic_time + timeout.to_f # The time to give up
|
258
258
|
|
259
259
|
result = loop do
|
@@ -304,13 +304,17 @@ module Concurrent
|
|
304
304
|
#
|
305
305
|
# @return [Object, CANCEL] the value exchanged by the other thread; {CANCEL} on timeout
|
306
306
|
def do_exchange(value, timeout)
|
307
|
+
result = nil
|
307
308
|
if timeout.nil?
|
308
|
-
Synchronization::JRuby.sleep_interruptibly
|
309
|
+
Synchronization::JRuby.sleep_interruptibly do
|
310
|
+
result = @exchanger.exchange(value)
|
311
|
+
end
|
309
312
|
else
|
310
313
|
Synchronization::JRuby.sleep_interruptibly do
|
311
|
-
@exchanger.exchange(value, 1000 * timeout, java.util.concurrent.TimeUnit::MILLISECONDS)
|
314
|
+
result = @exchanger.exchange(value, 1000 * timeout, java.util.concurrent.TimeUnit::MILLISECONDS)
|
312
315
|
end
|
313
316
|
end
|
317
|
+
result
|
314
318
|
rescue java.util.concurrent.TimeoutException
|
315
319
|
CANCEL
|
316
320
|
end
|
data/lib/concurrent/map.rb
CHANGED
@@ -31,46 +31,89 @@ module Concurrent
|
|
31
31
|
# -- for instance, it does not necessarily retain ordering by insertion time as `Hash`
|
32
32
|
# does. For most uses it should do fine though, and we recommend you consider
|
33
33
|
# `Concurrent::Map` instead of `Concurrent::Hash` for your concurrency-safe hash needs.
|
34
|
-
#
|
35
|
-
# > require 'concurrent'
|
36
|
-
# >
|
37
|
-
# > map = Concurrent::Map.new
|
38
34
|
class Map < Collection::MapImplementation
|
39
35
|
|
40
|
-
# @!macro
|
41
|
-
# This method is atomic.
|
42
|
-
|
43
|
-
#
|
36
|
+
# @!macro map.atomic_method
|
37
|
+
# This method is atomic.
|
38
|
+
|
39
|
+
# @!macro map.atomic_method_with_block
|
40
|
+
# This method is atomic.
|
41
|
+
# @note Atomic methods taking a block do not allow the `self` instance
|
42
|
+
# to be used within the block. Doing so will cause a deadlock.
|
43
|
+
|
44
|
+
# @!method compute_if_absent(key)
|
45
|
+
# Compute and store new value for key if the key is absent.
|
46
|
+
# @param [Object] key
|
47
|
+
# @yield new value
|
48
|
+
# @yieldreturn [Object] new value
|
49
|
+
# @return [Object] new value or current value
|
50
|
+
# @!macro map.atomic_method_with_block
|
51
|
+
|
52
|
+
# @!method compute_if_present(key)
|
53
|
+
# Compute and store new value for key if the key is present.
|
54
|
+
# @param [Object] key
|
55
|
+
# @yield new value
|
56
|
+
# @yieldparam old_value [Object]
|
57
|
+
# @yieldreturn [Object, nil] new value, when nil the key is removed
|
58
|
+
# @return [Object, nil] new value or nil
|
59
|
+
# @!macro map.atomic_method_with_block
|
60
|
+
|
61
|
+
# @!method compute(key)
|
62
|
+
# Compute and store new value for key.
|
63
|
+
# @param [Object] key
|
64
|
+
# @yield compute new value from old one
|
65
|
+
# @yieldparam old_value [Object, nil] old_value, or nil when key is absent
|
66
|
+
# @yieldreturn [Object, nil] new value, when nil the key is removed
|
67
|
+
# @return [Object, nil] new value or nil
|
68
|
+
# @!macro map.atomic_method_with_block
|
69
|
+
|
70
|
+
# @!method merge_pair(key, value)
|
71
|
+
# If the key is absent, the value is stored, otherwise new value is
|
72
|
+
# computed with a block.
|
73
|
+
# @param [Object] key
|
74
|
+
# @param [Object] value
|
75
|
+
# @yield compute new value from old one
|
76
|
+
# @yieldparam old_value [Object] old value
|
77
|
+
# @yieldreturn [Object, nil] new value, when nil the key is removed
|
78
|
+
# @return [Object, nil] new value or nil
|
79
|
+
# @!macro map.atomic_method_with_block
|
80
|
+
|
81
|
+
# @!method replace_pair(key, old_value, new_value)
|
82
|
+
# Replaces old_value with new_value if key exists and current value
|
83
|
+
# matches old_value
|
84
|
+
# @param [Object] key
|
85
|
+
# @param [Object] old_value
|
86
|
+
# @param [Object] new_value
|
87
|
+
# @return [true, false] true if replaced
|
88
|
+
# @!macro map.atomic_method
|
89
|
+
|
90
|
+
# @!method replace_if_exists(key, new_value)
|
91
|
+
# Replaces current value with new_value if key exists
|
92
|
+
# @param [Object] key
|
93
|
+
# @param [Object] new_value
|
94
|
+
# @return [Object, nil] old value or nil
|
95
|
+
# @!macro map.atomic_method
|
96
|
+
|
97
|
+
# @!method get_and_set(key, value)
|
98
|
+
# Get the current value under key and set new value.
|
99
|
+
# @param [Object] key
|
100
|
+
# @param [Object] value
|
101
|
+
# @return [Object, nil] old value or nil when the key was absent
|
102
|
+
# @!macro map.atomic_method
|
103
|
+
|
104
|
+
# @!method delete(key)
|
105
|
+
# Delete key and its value.
|
106
|
+
# @param [Object] key
|
107
|
+
# @return [Object, nil] old value or nil when the key was absent
|
108
|
+
# @!macro map.atomic_method
|
109
|
+
|
110
|
+
# @!method delete_pair(key, value)
|
111
|
+
# Delete pair and its value if current value equals the provided value.
|
112
|
+
# @param [Object] key
|
113
|
+
# @param [Object] value
|
114
|
+
# @return [true, false] true if deleted
|
115
|
+
# @!macro map.atomic_method
|
44
116
|
|
45
|
-
# @!method put_if_absent
|
46
|
-
# @!macro map_method_is_atomic
|
47
|
-
|
48
|
-
# @!method compute_if_absent
|
49
|
-
# @!macro map_method_is_atomic
|
50
|
-
|
51
|
-
# @!method compute_if_present
|
52
|
-
# @!macro map_method_is_atomic
|
53
|
-
|
54
|
-
# @!method compute
|
55
|
-
# @!macro map_method_is_atomic
|
56
|
-
|
57
|
-
# @!method merge_pair
|
58
|
-
# @!macro map_method_is_atomic
|
59
|
-
|
60
|
-
# @!method replace_pair
|
61
|
-
# @!macro map_method_is_atomic
|
62
|
-
|
63
|
-
# @!method replace_if_exists
|
64
|
-
# @!macro map_method_is_atomic
|
65
|
-
|
66
|
-
# @!method get_and_set
|
67
|
-
# @!macro map_method_is_atomic
|
68
|
-
|
69
|
-
# @!method delete
|
70
|
-
# @!macro map_method_is_atomic
|
71
|
-
|
72
|
-
# @!method delete_pair
|
73
|
-
# @!macro map_method_is_atomic
|
74
117
|
|
75
118
|
def initialize(options = nil, &block)
|
76
119
|
if options.kind_of?(::Hash)
|
@@ -83,6 +126,9 @@ module Concurrent
|
|
83
126
|
@default_proc = block
|
84
127
|
end
|
85
128
|
|
129
|
+
# Get a value with key
|
130
|
+
# @param [Object] key
|
131
|
+
# @return [Object] the value
|
86
132
|
def [](key)
|
87
133
|
if value = super # non-falsy value is an existing mapping, return it right away
|
88
134
|
value
|
@@ -98,17 +144,27 @@ module Concurrent
|
|
98
144
|
end
|
99
145
|
|
100
146
|
alias_method :get, :[]
|
147
|
+
# TODO (pitr-ch 30-Oct-2018): doc
|
101
148
|
alias_method :put, :[]=
|
102
149
|
|
150
|
+
# Get a value with key, or default_value when key is absent,
|
151
|
+
# or fail when no default_value is given.
|
152
|
+
# @param [Object] key
|
153
|
+
# @param [Object] default_value
|
154
|
+
# @yield default value for a key
|
155
|
+
# @yieldparam key [Object]
|
156
|
+
# @yieldreturn [Object] default value
|
157
|
+
# @return [Object] the value or default value
|
158
|
+
# @raise [KeyError] when key is missing and no default_value is provided
|
103
159
|
# @!macro map_method_not_atomic
|
104
|
-
# The "fetch-then-act" methods of `Map` are not atomic. `Map` is intended
|
105
|
-
#
|
106
|
-
#
|
107
|
-
#
|
108
|
-
#
|
109
|
-
#
|
110
|
-
#
|
111
|
-
#
|
160
|
+
# @note The "fetch-then-act" methods of `Map` are not atomic. `Map` is intended
|
161
|
+
# to be use as a concurrency primitive with strong happens-before
|
162
|
+
# guarantees. It is not intended to be used as a high-level abstraction
|
163
|
+
# supporting complex operations. All read and write operations are
|
164
|
+
# thread safe, but no guarantees are made regarding race conditions
|
165
|
+
# between the fetch operation and yielding to the block. Additionally,
|
166
|
+
# this method does not support recursion. This is due to internal
|
167
|
+
# constraints that are very unlikely to change in the near future.
|
112
168
|
def fetch(key, default_value = NULL)
|
113
169
|
if NULL != (value = get_or_default(key, NULL))
|
114
170
|
value
|
@@ -121,23 +177,39 @@ module Concurrent
|
|
121
177
|
end
|
122
178
|
end
|
123
179
|
|
124
|
-
#
|
180
|
+
# Fetch value with key, or store default value when key is absent,
|
181
|
+
# or fail when no default_value is given. This is a two step operation,
|
182
|
+
# therefore not atomic. The store can overwrite other concurrently
|
183
|
+
# stored value.
|
184
|
+
# @param [Object] key
|
185
|
+
# @param [Object] default_value
|
186
|
+
# @yield default value for a key
|
187
|
+
# @yieldparam key [Object]
|
188
|
+
# @yieldreturn [Object] default value
|
189
|
+
# @return [Object] the value or default value
|
190
|
+
# @!macro map.atomic_method_with_block
|
125
191
|
def fetch_or_store(key, default_value = NULL)
|
126
192
|
fetch(key) do
|
127
193
|
put(key, block_given? ? yield(key) : (NULL == default_value ? raise_fetch_no_key : default_value))
|
128
194
|
end
|
129
195
|
end
|
130
196
|
|
131
|
-
#
|
197
|
+
# Insert value into map with key if key is absent in one atomic step.
|
198
|
+
# @param [Object] key
|
199
|
+
# @param [Object] value
|
200
|
+
# @return [Object, nil] the value or nil when key was present
|
132
201
|
def put_if_absent(key, value)
|
133
202
|
computed = false
|
134
|
-
result
|
203
|
+
result = compute_if_absent(key) do
|
135
204
|
computed = true
|
136
205
|
value
|
137
206
|
end
|
138
207
|
computed ? nil : result
|
139
208
|
end unless method_defined?(:put_if_absent)
|
140
209
|
|
210
|
+
# Is the value stored in the map. Iterates over all values.
|
211
|
+
# @param [Object] value
|
212
|
+
# @return [true, false]
|
141
213
|
def value?(value)
|
142
214
|
each_value do |v|
|
143
215
|
return true if value.equal?(v)
|
@@ -145,26 +217,46 @@ module Concurrent
|
|
145
217
|
false
|
146
218
|
end
|
147
219
|
|
220
|
+
# All keys
|
221
|
+
# @return [::Array<Object>] keys
|
148
222
|
def keys
|
149
223
|
arr = []
|
150
|
-
each_pair {|k, v| arr << k}
|
224
|
+
each_pair { |k, v| arr << k }
|
151
225
|
arr
|
152
226
|
end unless method_defined?(:keys)
|
153
227
|
|
228
|
+
# All values
|
229
|
+
# @return [::Array<Object>] values
|
154
230
|
def values
|
155
231
|
arr = []
|
156
|
-
each_pair {|k, v| arr << v}
|
232
|
+
each_pair { |k, v| arr << v }
|
157
233
|
arr
|
158
234
|
end unless method_defined?(:values)
|
159
235
|
|
236
|
+
# Iterates over each key.
|
237
|
+
# @yield for each key in the map
|
238
|
+
# @yieldparam key [Object]
|
239
|
+
# @return [self]
|
240
|
+
# @!macro map.atomic_method_with_block
|
160
241
|
def each_key
|
161
|
-
each_pair {|k, v| yield k}
|
242
|
+
each_pair { |k, v| yield k }
|
162
243
|
end unless method_defined?(:each_key)
|
163
244
|
|
245
|
+
# Iterates over each value.
|
246
|
+
# @yield for each value in the map
|
247
|
+
# @yieldparam value [Object]
|
248
|
+
# @return [self]
|
249
|
+
# @!macro map.atomic_method_with_block
|
164
250
|
def each_value
|
165
|
-
each_pair {|k, v| yield v}
|
251
|
+
each_pair { |k, v| yield v }
|
166
252
|
end unless method_defined?(:each_value)
|
167
253
|
|
254
|
+
# Iterates over each key value pair.
|
255
|
+
# @yield for each key value pair in the map
|
256
|
+
# @yieldparam key [Object]
|
257
|
+
# @yieldparam value [Object]
|
258
|
+
# @return [self]
|
259
|
+
# @!macro map.atomic_method_with_block
|
168
260
|
def each_pair
|
169
261
|
return enum_for :each_pair unless block_given?
|
170
262
|
super
|
@@ -172,30 +264,39 @@ module Concurrent
|
|
172
264
|
|
173
265
|
alias_method :each, :each_pair unless method_defined?(:each)
|
174
266
|
|
267
|
+
# Find key of a value.
|
268
|
+
# @param [Object] value
|
269
|
+
# @return [Object, nil] key or nil when not found
|
175
270
|
def key(value)
|
176
|
-
each_pair {|k, v| return k if v == value}
|
271
|
+
each_pair { |k, v| return k if v == value }
|
177
272
|
nil
|
178
273
|
end unless method_defined?(:key)
|
179
274
|
alias_method :index, :key if RUBY_VERSION < '1.9'
|
180
275
|
|
276
|
+
# Is map empty?
|
277
|
+
# @return [true, false]
|
181
278
|
def empty?
|
182
|
-
each_pair {|k, v| return false}
|
279
|
+
each_pair { |k, v| return false }
|
183
280
|
true
|
184
281
|
end unless method_defined?(:empty?)
|
185
282
|
|
283
|
+
# The size of map.
|
284
|
+
# @return [Integer] size
|
186
285
|
def size
|
187
286
|
count = 0
|
188
|
-
each_pair {|k, v| count += 1}
|
287
|
+
each_pair { |k, v| count += 1 }
|
189
288
|
count
|
190
289
|
end unless method_defined?(:size)
|
191
290
|
|
291
|
+
# @!visibility private
|
192
292
|
def marshal_dump
|
193
293
|
raise TypeError, "can't dump hash with default proc" if @default_proc
|
194
294
|
h = {}
|
195
|
-
each_pair {|k, v| h[k] = v}
|
295
|
+
each_pair { |k, v| h[k] = v }
|
196
296
|
h
|
197
297
|
end
|
198
298
|
|
299
|
+
# @!visibility private
|
199
300
|
def marshal_load(hash)
|
200
301
|
initialize
|
201
302
|
populate_from(hash)
|
@@ -209,6 +310,7 @@ module Concurrent
|
|
209
310
|
end
|
210
311
|
|
211
312
|
private
|
313
|
+
|
212
314
|
def raise_fetch_no_key
|
213
315
|
raise KeyError, 'key not found'
|
214
316
|
end
|
@@ -219,7 +321,7 @@ module Concurrent
|
|
219
321
|
end
|
220
322
|
|
221
323
|
def populate_from(hash)
|
222
|
-
hash.each_pair {|k, v| self[k] = v}
|
324
|
+
hash.each_pair { |k, v| self[k] = v }
|
223
325
|
self
|
224
326
|
end
|
225
327
|
|
@@ -1,5 +1,14 @@
|
|
1
1
|
require 'concurrent/thread_safe/util'
|
2
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
|
+
|
3
12
|
module Concurrent
|
4
13
|
module ThreadSafe
|
5
14
|
module Util
|
@@ -44,8 +53,7 @@ module Concurrent
|
|
44
53
|
klass.superclass.instance_methods(false).each do |method|
|
45
54
|
klass.class_eval <<-RUBY, __FILE__, __LINE__ + 1
|
46
55
|
def #{method}(*args, &block)
|
47
|
-
|
48
|
-
Truffle::System.synchronized(self) { super(*args, &block) }
|
56
|
+
TruffleRuby.synchronized(self) { super(*args, &block) }
|
49
57
|
end
|
50
58
|
RUBY
|
51
59
|
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
require_relative 'engine'
|
2
|
+
|
3
|
+
if Concurrent.ruby_version :<, 2, 0, 0
|
4
|
+
# @!visibility private
|
5
|
+
module Kernel
|
6
|
+
def __dir__
|
7
|
+
File.dirname __FILE__
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
# @!visibility private
|
12
|
+
class LoadError < ScriptError
|
13
|
+
def path
|
14
|
+
message.split(' -- ').last
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -8,7 +8,7 @@ module Concurrent
|
|
8
8
|
end
|
9
9
|
|
10
10
|
def on_jruby_9000?
|
11
|
-
on_jruby? && ruby_version(:>=, 9, 0, 0
|
11
|
+
on_jruby? && ruby_version(JRUBY_VERSION, :>=, 9, 0, 0)
|
12
12
|
end
|
13
13
|
|
14
14
|
def on_cruby?
|
@@ -39,7 +39,7 @@ module Concurrent
|
|
39
39
|
defined?(RUBY_ENGINE) ? RUBY_ENGINE : 'ruby'
|
40
40
|
end
|
41
41
|
|
42
|
-
def ruby_version(comparison, major, minor, patch
|
42
|
+
def ruby_version(version = RUBY_VERSION, comparison, major, minor, patch)
|
43
43
|
result = (version.split('.').map(&:to_i) <=> [major, minor, patch])
|
44
44
|
comparisons = { :== => [0],
|
45
45
|
:>= => [1, 0],
|
data/lib/concurrent/version.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: concurrent-ruby
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.1.
|
4
|
+
version: 1.1.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jerry D'Antonio
|
@@ -10,7 +10,7 @@ authors:
|
|
10
10
|
autorequire:
|
11
11
|
bindir: bin
|
12
12
|
cert_chain: []
|
13
|
-
date: 2018-
|
13
|
+
date: 2018-11-05 00:00:00.000000000 Z
|
14
14
|
dependencies: []
|
15
15
|
description: |
|
16
16
|
Modern concurrency tools including agents, futures, promises, thread pools, actors, supervisors, and more.
|
@@ -157,6 +157,7 @@ files:
|
|
157
157
|
- lib/concurrent/timer_task.rb
|
158
158
|
- lib/concurrent/tuple.rb
|
159
159
|
- lib/concurrent/tvar.rb
|
160
|
+
- lib/concurrent/utility/193.rb
|
160
161
|
- lib/concurrent/utility/at_exit.rb
|
161
162
|
- lib/concurrent/utility/engine.rb
|
162
163
|
- lib/concurrent/utility/monotonic_time.rb
|
@@ -176,12 +177,12 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
176
177
|
requirements:
|
177
178
|
- - ">="
|
178
179
|
- !ruby/object:Gem::Version
|
179
|
-
version:
|
180
|
+
version: 1.9.3
|
180
181
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
181
182
|
requirements:
|
182
|
-
- - "
|
183
|
+
- - ">="
|
183
184
|
- !ruby/object:Gem::Version
|
184
|
-
version:
|
185
|
+
version: '0'
|
185
186
|
requirements: []
|
186
187
|
rubyforge_project:
|
187
188
|
rubygems_version: 2.7.3
|