concurrent-ruby-edge 0.3.1 → 0.4.0.pre1
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 +5 -5
- data/CHANGELOG.md +429 -0
- data/{LICENSE.txt → LICENSE.md} +2 -0
- data/README.md +203 -105
- data/{lib → lib-edge}/concurrent/actor/behaviour/abstract.rb +0 -0
- data/{lib → lib-edge}/concurrent/actor/behaviour/awaits.rb +0 -0
- data/{lib → lib-edge}/concurrent/actor/behaviour/buffer.rb +0 -0
- data/{lib → lib-edge}/concurrent/actor/behaviour/errors_on_unknown_message.rb +0 -0
- data/{lib → lib-edge}/concurrent/actor/behaviour/executes_context.rb +0 -0
- data/{lib → lib-edge}/concurrent/actor/behaviour/linking.rb +0 -0
- data/{lib → lib-edge}/concurrent/actor/behaviour/pausing.rb +0 -0
- data/{lib → lib-edge}/concurrent/actor/behaviour/removes_child.rb +0 -0
- data/{lib → lib-edge}/concurrent/actor/behaviour/sets_results.rb +0 -0
- data/{lib → lib-edge}/concurrent/actor/behaviour/supervising.rb +0 -0
- data/{lib → lib-edge}/concurrent/actor/behaviour/termination.rb +1 -1
- data/{lib → lib-edge}/concurrent/actor/behaviour.rb +1 -1
- data/{lib → lib-edge}/concurrent/actor/context.rb +1 -1
- data/{lib → lib-edge}/concurrent/actor/core.rb +2 -1
- data/{lib → lib-edge}/concurrent/actor/default_dead_letter_handler.rb +0 -0
- data/{lib → lib-edge}/concurrent/actor/envelope.rb +0 -0
- data/{lib → lib-edge}/concurrent/actor/errors.rb +0 -0
- data/{lib → lib-edge}/concurrent/actor/internal_delegations.rb +0 -0
- data/{lib → lib-edge}/concurrent/actor/public_delegations.rb +0 -0
- data/{lib → lib-edge}/concurrent/actor/reference.rb +1 -1
- data/{lib → lib-edge}/concurrent/actor/root.rb +0 -0
- data/{lib → lib-edge}/concurrent/actor/type_check.rb +0 -0
- data/{lib → lib-edge}/concurrent/actor/utils/ad_hoc.rb +0 -0
- data/{lib → lib-edge}/concurrent/actor/utils/balancer.rb +0 -0
- data/{lib → lib-edge}/concurrent/actor/utils/broadcast.rb +0 -0
- data/{lib → lib-edge}/concurrent/actor/utils/pool.rb +0 -0
- data/{lib → lib-edge}/concurrent/actor/utils.rb +0 -0
- data/{lib → lib-edge}/concurrent/actor.rb +9 -5
- data/{lib → lib-edge}/concurrent/channel/buffer/base.rb +14 -14
- data/{lib → lib-edge}/concurrent/channel/buffer/buffered.rb +0 -0
- data/{lib → lib-edge}/concurrent/channel/buffer/dropping.rb +0 -0
- data/{lib → lib-edge}/concurrent/channel/buffer/sliding.rb +0 -0
- data/{lib → lib-edge}/concurrent/channel/buffer/ticker.rb +0 -0
- data/{lib → lib-edge}/concurrent/channel/buffer/timer.rb +0 -0
- data/{lib → lib-edge}/concurrent/channel/buffer/unbuffered.rb +1 -1
- data/{lib → lib-edge}/concurrent/channel/buffer.rb +0 -0
- data/{lib → lib-edge}/concurrent/channel/selector/after_clause.rb +0 -0
- data/{lib → lib-edge}/concurrent/channel/selector/default_clause.rb +0 -0
- data/{lib → lib-edge}/concurrent/channel/selector/error_clause.rb +0 -0
- data/{lib → lib-edge}/concurrent/channel/selector/put_clause.rb +0 -0
- data/{lib → lib-edge}/concurrent/channel/selector/take_clause.rb +0 -0
- data/{lib → lib-edge}/concurrent/channel/selector.rb +0 -0
- data/{lib → lib-edge}/concurrent/channel/tick.rb +0 -0
- data/{lib → lib-edge}/concurrent/channel.rb +2 -1
- data/{lib → lib-edge}/concurrent/edge/cancellation.rb +5 -4
- data/{lib → lib-edge}/concurrent/edge/lock_free_linked_set/node.rb +2 -2
- data/{lib → lib-edge}/concurrent/edge/lock_free_linked_set/window.rb +0 -0
- data/{lib → lib-edge}/concurrent/edge/lock_free_linked_set.rb +8 -7
- data/{lib → lib-edge}/concurrent/edge/lock_free_queue.rb +0 -0
- data/{lib → lib-edge}/concurrent/edge/old_channel_integration.rb +0 -0
- data/{lib → lib-edge}/concurrent/edge/processing_actor.rb +3 -3
- data/lib-edge/concurrent/edge/promises.rb +178 -0
- data/{lib → lib-edge}/concurrent/edge/throttle.rb +24 -15
- data/lib-edge/concurrent/edge.rb +21 -0
- data/lib-edge/concurrent/lazy_register.rb +83 -0
- data/{lib → lib-edge}/concurrent-edge.rb +0 -4
- metadata +71 -70
- data/lib/concurrent/edge/atomic_markable_reference.rb +0 -184
- data/lib/concurrent/edge/lock_free_stack.rb +0 -126
- data/lib/concurrent/edge/promises.rb +0 -2111
@@ -0,0 +1,83 @@
|
|
1
|
+
require 'concurrent/atomic/atomic_reference'
|
2
|
+
require 'concurrent/delay'
|
3
|
+
|
4
|
+
module Concurrent
|
5
|
+
|
6
|
+
# Hash-like collection that store lazy evaluated values.
|
7
|
+
#
|
8
|
+
# @!macro warn.edge
|
9
|
+
#
|
10
|
+
# @example
|
11
|
+
# register = Concurrent::LazyRegister.new
|
12
|
+
# #=> #<Concurrent::LazyRegister:0x007fd7ecd5e230 @Data=#<Concurrent::AtomicReference:0x007fd7ecd5e1e0>>
|
13
|
+
# register[:key]
|
14
|
+
# #=> nil
|
15
|
+
# register.add(:key) { Concurrent::Actor.spawn!(Actor::AdHoc, :ping) { -> message { message } } }
|
16
|
+
# #=> #<Concurrent::LazyRegister:0x007fd7ecd5e230 @Data=#<Concurrent::AtomicReference:0x007fd7ecd5e1e0>>
|
17
|
+
# register[:key]
|
18
|
+
# #=> #<Concurrent::Actor::Reference /ping (Concurrent::Actor::AdHoc)>
|
19
|
+
#
|
20
|
+
class LazyRegister < Synchronization::Object
|
21
|
+
|
22
|
+
attr_atomic(:data)
|
23
|
+
private :data, :data=, :swap_data, :compare_and_set_data, :update_data
|
24
|
+
|
25
|
+
def initialize
|
26
|
+
super
|
27
|
+
self.data = {}
|
28
|
+
end
|
29
|
+
|
30
|
+
# Element reference. Retrieves the value object corresponding to the
|
31
|
+
# key object. Returns nil if the key is not found. Raises an exception
|
32
|
+
# if the stored item raised an exception when the block was evaluated.
|
33
|
+
#
|
34
|
+
# @param [Object] key
|
35
|
+
# @return [Object] value stored for the key or nil if the key is not found
|
36
|
+
#
|
37
|
+
# @raise Exception when the initialization block fails
|
38
|
+
def [](key)
|
39
|
+
delay = data[key]
|
40
|
+
delay ? delay.value! : nil
|
41
|
+
end
|
42
|
+
|
43
|
+
# Returns true if the given key is present.
|
44
|
+
#
|
45
|
+
# @param [Object] key
|
46
|
+
# @return [true, false] if the key is registered
|
47
|
+
def registered?(key)
|
48
|
+
data.key?(key)
|
49
|
+
end
|
50
|
+
|
51
|
+
alias_method :key?, :registered?
|
52
|
+
alias_method :has_key?, :registered?
|
53
|
+
|
54
|
+
# Element assignment. Associates the value given by value with the
|
55
|
+
# key given by key.
|
56
|
+
#
|
57
|
+
# @param [Object] key
|
58
|
+
# @yield the object to store under the key
|
59
|
+
#
|
60
|
+
# @return [LazyRegister] self
|
61
|
+
def register(key, &block)
|
62
|
+
delay = Delay.new(executor: :immediate, &block)
|
63
|
+
update_data { |h| h.merge(key => delay) }
|
64
|
+
self
|
65
|
+
end
|
66
|
+
|
67
|
+
alias_method :add, :register
|
68
|
+
alias_method :store, :register
|
69
|
+
|
70
|
+
# Un-registers the object under key, realized or not.
|
71
|
+
#
|
72
|
+
# @param [Object] key
|
73
|
+
#
|
74
|
+
# @return [LazyRegister] self
|
75
|
+
def unregister(key)
|
76
|
+
update_data { |h| h.dup.tap { |j| j.delete(key) } }
|
77
|
+
self
|
78
|
+
end
|
79
|
+
|
80
|
+
alias_method :remove, :unregister
|
81
|
+
alias_method :delete, :unregister
|
82
|
+
end
|
83
|
+
end
|
@@ -3,15 +3,11 @@ require 'concurrent'
|
|
3
3
|
require 'concurrent/actor'
|
4
4
|
require 'concurrent/agent'
|
5
5
|
require 'concurrent/channel'
|
6
|
-
require 'concurrent/exchanger'
|
7
6
|
require 'concurrent/lazy_register'
|
8
7
|
|
9
|
-
require 'concurrent/edge/atomic_markable_reference'
|
10
8
|
require 'concurrent/edge/lock_free_linked_set'
|
11
9
|
require 'concurrent/edge/lock_free_queue'
|
12
|
-
require 'concurrent/edge/lock_free_stack'
|
13
10
|
|
14
|
-
require 'concurrent/edge/promises'
|
15
11
|
require 'concurrent/edge/cancellation'
|
16
12
|
require 'concurrent/edge/throttle'
|
17
13
|
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: concurrent-ruby-edge
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.4.0.pre1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jerry D'Antonio
|
@@ -10,22 +10,22 @@ authors:
|
|
10
10
|
autorequire:
|
11
11
|
bindir: bin
|
12
12
|
cert_chain: []
|
13
|
-
date:
|
13
|
+
date: 2018-08-15 00:00:00.000000000 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: concurrent-ruby
|
17
17
|
requirement: !ruby/object:Gem::Requirement
|
18
18
|
requirements:
|
19
|
-
- -
|
19
|
+
- - "~>"
|
20
20
|
- !ruby/object:Gem::Version
|
21
|
-
version: 1.0.
|
21
|
+
version: 1.1.0.pre1
|
22
22
|
type: :runtime
|
23
23
|
prerelease: false
|
24
24
|
version_requirements: !ruby/object:Gem::Requirement
|
25
25
|
requirements:
|
26
|
-
- -
|
26
|
+
- - "~>"
|
27
27
|
- !ruby/object:Gem::Version
|
28
|
-
version: 1.0.
|
28
|
+
version: 1.1.0.pre1
|
29
29
|
description: |
|
30
30
|
These features are under active development and may change frequently. They are expected not to
|
31
31
|
keep backward compatibility (there may also lack tests and documentation). Semantic versions will
|
@@ -36,66 +36,68 @@ executables: []
|
|
36
36
|
extensions: []
|
37
37
|
extra_rdoc_files:
|
38
38
|
- README.md
|
39
|
-
- LICENSE.
|
39
|
+
- LICENSE.md
|
40
|
+
- CHANGELOG.md
|
40
41
|
files:
|
41
|
-
-
|
42
|
+
- CHANGELOG.md
|
43
|
+
- LICENSE.md
|
42
44
|
- README.md
|
43
|
-
- lib/concurrent-edge.rb
|
44
|
-
- lib/concurrent/actor.rb
|
45
|
-
- lib/concurrent/actor/behaviour.rb
|
46
|
-
- lib/concurrent/actor/behaviour/abstract.rb
|
47
|
-
- lib/concurrent/actor/behaviour/awaits.rb
|
48
|
-
- lib/concurrent/actor/behaviour/buffer.rb
|
49
|
-
- lib/concurrent/actor/behaviour/errors_on_unknown_message.rb
|
50
|
-
- lib/concurrent/actor/behaviour/executes_context.rb
|
51
|
-
- lib/concurrent/actor/behaviour/linking.rb
|
52
|
-
- lib/concurrent/actor/behaviour/pausing.rb
|
53
|
-
- lib/concurrent/actor/behaviour/removes_child.rb
|
54
|
-
- lib/concurrent/actor/behaviour/sets_results.rb
|
55
|
-
- lib/concurrent/actor/behaviour/supervising.rb
|
56
|
-
- lib/concurrent/actor/behaviour/termination.rb
|
57
|
-
- lib/concurrent/actor/context.rb
|
58
|
-
- lib/concurrent/actor/core.rb
|
59
|
-
- lib/concurrent/actor/default_dead_letter_handler.rb
|
60
|
-
- lib/concurrent/actor/envelope.rb
|
61
|
-
- lib/concurrent/actor/errors.rb
|
62
|
-
- lib/concurrent/actor/internal_delegations.rb
|
63
|
-
- lib/concurrent/actor/public_delegations.rb
|
64
|
-
- lib/concurrent/actor/reference.rb
|
65
|
-
- lib/concurrent/actor/root.rb
|
66
|
-
- lib/concurrent/actor/type_check.rb
|
67
|
-
- lib/concurrent/actor/utils.rb
|
68
|
-
- lib/concurrent/actor/utils/ad_hoc.rb
|
69
|
-
- lib/concurrent/actor/utils/balancer.rb
|
70
|
-
- lib/concurrent/actor/utils/broadcast.rb
|
71
|
-
- lib/concurrent/actor/utils/pool.rb
|
72
|
-
- lib/concurrent/channel.rb
|
73
|
-
- lib/concurrent/channel/buffer.rb
|
74
|
-
- lib/concurrent/channel/buffer/base.rb
|
75
|
-
- lib/concurrent/channel/buffer/buffered.rb
|
76
|
-
- lib/concurrent/channel/buffer/dropping.rb
|
77
|
-
- lib/concurrent/channel/buffer/sliding.rb
|
78
|
-
- lib/concurrent/channel/buffer/ticker.rb
|
79
|
-
- lib/concurrent/channel/buffer/timer.rb
|
80
|
-
- lib/concurrent/channel/buffer/unbuffered.rb
|
81
|
-
- lib/concurrent/channel/selector.rb
|
82
|
-
- lib/concurrent/channel/selector/after_clause.rb
|
83
|
-
- lib/concurrent/channel/selector/default_clause.rb
|
84
|
-
- lib/concurrent/channel/selector/error_clause.rb
|
85
|
-
- lib/concurrent/channel/selector/put_clause.rb
|
86
|
-
- lib/concurrent/channel/selector/take_clause.rb
|
87
|
-
- lib/concurrent/channel/tick.rb
|
88
|
-
- lib/concurrent/edge
|
89
|
-
- lib/concurrent/edge/cancellation.rb
|
90
|
-
- lib/concurrent/edge/lock_free_linked_set.rb
|
91
|
-
- lib/concurrent/edge/lock_free_linked_set/node.rb
|
92
|
-
- lib/concurrent/edge/lock_free_linked_set/window.rb
|
93
|
-
- lib/concurrent/edge/lock_free_queue.rb
|
94
|
-
- lib/concurrent/edge/
|
95
|
-
- lib/concurrent/edge/
|
96
|
-
- lib/concurrent/edge/
|
97
|
-
- lib/concurrent/edge/
|
98
|
-
- lib/concurrent/
|
45
|
+
- lib-edge/concurrent-edge.rb
|
46
|
+
- lib-edge/concurrent/actor.rb
|
47
|
+
- lib-edge/concurrent/actor/behaviour.rb
|
48
|
+
- lib-edge/concurrent/actor/behaviour/abstract.rb
|
49
|
+
- lib-edge/concurrent/actor/behaviour/awaits.rb
|
50
|
+
- lib-edge/concurrent/actor/behaviour/buffer.rb
|
51
|
+
- lib-edge/concurrent/actor/behaviour/errors_on_unknown_message.rb
|
52
|
+
- lib-edge/concurrent/actor/behaviour/executes_context.rb
|
53
|
+
- lib-edge/concurrent/actor/behaviour/linking.rb
|
54
|
+
- lib-edge/concurrent/actor/behaviour/pausing.rb
|
55
|
+
- lib-edge/concurrent/actor/behaviour/removes_child.rb
|
56
|
+
- lib-edge/concurrent/actor/behaviour/sets_results.rb
|
57
|
+
- lib-edge/concurrent/actor/behaviour/supervising.rb
|
58
|
+
- lib-edge/concurrent/actor/behaviour/termination.rb
|
59
|
+
- lib-edge/concurrent/actor/context.rb
|
60
|
+
- lib-edge/concurrent/actor/core.rb
|
61
|
+
- lib-edge/concurrent/actor/default_dead_letter_handler.rb
|
62
|
+
- lib-edge/concurrent/actor/envelope.rb
|
63
|
+
- lib-edge/concurrent/actor/errors.rb
|
64
|
+
- lib-edge/concurrent/actor/internal_delegations.rb
|
65
|
+
- lib-edge/concurrent/actor/public_delegations.rb
|
66
|
+
- lib-edge/concurrent/actor/reference.rb
|
67
|
+
- lib-edge/concurrent/actor/root.rb
|
68
|
+
- lib-edge/concurrent/actor/type_check.rb
|
69
|
+
- lib-edge/concurrent/actor/utils.rb
|
70
|
+
- lib-edge/concurrent/actor/utils/ad_hoc.rb
|
71
|
+
- lib-edge/concurrent/actor/utils/balancer.rb
|
72
|
+
- lib-edge/concurrent/actor/utils/broadcast.rb
|
73
|
+
- lib-edge/concurrent/actor/utils/pool.rb
|
74
|
+
- lib-edge/concurrent/channel.rb
|
75
|
+
- lib-edge/concurrent/channel/buffer.rb
|
76
|
+
- lib-edge/concurrent/channel/buffer/base.rb
|
77
|
+
- lib-edge/concurrent/channel/buffer/buffered.rb
|
78
|
+
- lib-edge/concurrent/channel/buffer/dropping.rb
|
79
|
+
- lib-edge/concurrent/channel/buffer/sliding.rb
|
80
|
+
- lib-edge/concurrent/channel/buffer/ticker.rb
|
81
|
+
- lib-edge/concurrent/channel/buffer/timer.rb
|
82
|
+
- lib-edge/concurrent/channel/buffer/unbuffered.rb
|
83
|
+
- lib-edge/concurrent/channel/selector.rb
|
84
|
+
- lib-edge/concurrent/channel/selector/after_clause.rb
|
85
|
+
- lib-edge/concurrent/channel/selector/default_clause.rb
|
86
|
+
- lib-edge/concurrent/channel/selector/error_clause.rb
|
87
|
+
- lib-edge/concurrent/channel/selector/put_clause.rb
|
88
|
+
- lib-edge/concurrent/channel/selector/take_clause.rb
|
89
|
+
- lib-edge/concurrent/channel/tick.rb
|
90
|
+
- lib-edge/concurrent/edge.rb
|
91
|
+
- lib-edge/concurrent/edge/cancellation.rb
|
92
|
+
- lib-edge/concurrent/edge/lock_free_linked_set.rb
|
93
|
+
- lib-edge/concurrent/edge/lock_free_linked_set/node.rb
|
94
|
+
- lib-edge/concurrent/edge/lock_free_linked_set/window.rb
|
95
|
+
- lib-edge/concurrent/edge/lock_free_queue.rb
|
96
|
+
- lib-edge/concurrent/edge/old_channel_integration.rb
|
97
|
+
- lib-edge/concurrent/edge/processing_actor.rb
|
98
|
+
- lib-edge/concurrent/edge/promises.rb
|
99
|
+
- lib-edge/concurrent/edge/throttle.rb
|
100
|
+
- lib-edge/concurrent/lazy_register.rb
|
99
101
|
homepage: http://www.concurrent-ruby.com
|
100
102
|
licenses:
|
101
103
|
- MIT
|
@@ -103,22 +105,21 @@ metadata: {}
|
|
103
105
|
post_install_message:
|
104
106
|
rdoc_options: []
|
105
107
|
require_paths:
|
106
|
-
- lib
|
108
|
+
- lib-edge
|
107
109
|
required_ruby_version: !ruby/object:Gem::Requirement
|
108
110
|
requirements:
|
109
111
|
- - ">="
|
110
112
|
- !ruby/object:Gem::Version
|
111
|
-
version:
|
113
|
+
version: 2.0.0
|
112
114
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
113
115
|
requirements:
|
114
|
-
- - "
|
116
|
+
- - ">"
|
115
117
|
- !ruby/object:Gem::Version
|
116
|
-
version:
|
118
|
+
version: 1.3.1
|
117
119
|
requirements: []
|
118
120
|
rubyforge_project:
|
119
|
-
rubygems_version: 2.
|
121
|
+
rubygems_version: 2.7.3
|
120
122
|
signing_key:
|
121
123
|
specification_version: 4
|
122
124
|
summary: Edge features and additions to the concurrent-ruby gem.
|
123
125
|
test_files: []
|
124
|
-
has_rdoc:
|
@@ -1,184 +0,0 @@
|
|
1
|
-
module Concurrent
|
2
|
-
module Edge
|
3
|
-
|
4
|
-
# @!macro [attach] atomic_markable_reference
|
5
|
-
#
|
6
|
-
# An atomic reference which maintains an object reference along with a mark bit
|
7
|
-
# that can be updated atomically.
|
8
|
-
#
|
9
|
-
# @see http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/atomic/AtomicMarkableReference.html
|
10
|
-
# java.util.concurrent.atomic.AtomicMarkableReference
|
11
|
-
class AtomicMarkableReference < ::Concurrent::Synchronization::Object
|
12
|
-
|
13
|
-
private(*attr_atomic(:reference))
|
14
|
-
|
15
|
-
# @!macro [attach] atomic_markable_reference_method_initialize
|
16
|
-
def initialize(value = nil, mark = false)
|
17
|
-
super()
|
18
|
-
self.reference = ImmutableArray[value, mark]
|
19
|
-
end
|
20
|
-
|
21
|
-
# @!macro [attach] atomic_markable_reference_method_compare_and_set
|
22
|
-
#
|
23
|
-
# Atomically sets the value and mark to the given updated value and
|
24
|
-
# mark given both:
|
25
|
-
# - the current value == the expected value &&
|
26
|
-
# - the current mark == the expected mark
|
27
|
-
#
|
28
|
-
# @param [Object] expected_val the expected value
|
29
|
-
# @param [Object] new_val the new value
|
30
|
-
# @param [Boolean] expected_mark the expected mark
|
31
|
-
# @param [Boolean] new_mark the new mark
|
32
|
-
#
|
33
|
-
# @return [Boolean] `true` if successful. A `false` return indicates
|
34
|
-
# that the actual value was not equal to the expected value or the
|
35
|
-
# actual mark was not equal to the expected mark
|
36
|
-
def compare_and_set(expected_val, new_val, expected_mark, new_mark)
|
37
|
-
# Memoize a valid reference to the current AtomicReference for
|
38
|
-
# later comparison.
|
39
|
-
current = reference
|
40
|
-
curr_val, curr_mark = current
|
41
|
-
|
42
|
-
# Ensure that that the expected marks match.
|
43
|
-
return false unless expected_mark == curr_mark
|
44
|
-
|
45
|
-
if expected_val.is_a? Numeric
|
46
|
-
# If the object is a numeric, we need to ensure we are comparing
|
47
|
-
# the numerical values
|
48
|
-
return false unless expected_val == curr_val
|
49
|
-
else
|
50
|
-
# Otherwise, we need to ensure we are comparing the object identity.
|
51
|
-
# Theoretically, this could be incorrect if a user monkey-patched
|
52
|
-
# `Object#equal?`, but they should know that they are playing with
|
53
|
-
# fire at that point.
|
54
|
-
return false unless expected_val.equal? curr_val
|
55
|
-
end
|
56
|
-
|
57
|
-
prospect = ImmutableArray[new_val, new_mark]
|
58
|
-
|
59
|
-
compare_and_set_reference current, prospect
|
60
|
-
end
|
61
|
-
alias_method :compare_and_swap, :compare_and_set
|
62
|
-
|
63
|
-
# @!macro [attach] atomic_markable_reference_method_get
|
64
|
-
#
|
65
|
-
# Gets the current reference and marked values.
|
66
|
-
#
|
67
|
-
# @return [ImmutableArray] the current reference and marked values
|
68
|
-
def get
|
69
|
-
reference
|
70
|
-
end
|
71
|
-
|
72
|
-
# @!macro [attach] atomic_markable_reference_method_value
|
73
|
-
#
|
74
|
-
# Gets the current value of the reference
|
75
|
-
#
|
76
|
-
# @return [Object] the current value of the reference
|
77
|
-
def value
|
78
|
-
reference[0]
|
79
|
-
end
|
80
|
-
|
81
|
-
# @!macro [attach] atomic_markable_reference_method_mark
|
82
|
-
#
|
83
|
-
# Gets the current marked value
|
84
|
-
#
|
85
|
-
# @return [Boolean] the current marked value
|
86
|
-
def mark
|
87
|
-
reference[1]
|
88
|
-
end
|
89
|
-
alias_method :marked?, :mark
|
90
|
-
|
91
|
-
# @!macro [attach] atomic_markable_reference_method_set
|
92
|
-
#
|
93
|
-
# _Unconditionally_ sets to the given value of both the reference and
|
94
|
-
# the mark.
|
95
|
-
#
|
96
|
-
# @param [Object] new_val the new value
|
97
|
-
# @param [Boolean] new_mark the new mark
|
98
|
-
#
|
99
|
-
# @return [ImmutableArray] both the new value and the new mark
|
100
|
-
def set(new_val, new_mark)
|
101
|
-
self.reference = ImmutableArray[new_val, new_mark]
|
102
|
-
end
|
103
|
-
|
104
|
-
# @!macro [attach] atomic_markable_reference_method_update
|
105
|
-
#
|
106
|
-
# Pass the current value and marked state to the given block, replacing it
|
107
|
-
# with the block's results. May retry if the value changes during the
|
108
|
-
# block's execution.
|
109
|
-
#
|
110
|
-
# @yield [Object] Calculate a new value and marked state for the atomic
|
111
|
-
# reference using given (old) value and (old) marked
|
112
|
-
# @yieldparam [Object] old_val the starting value of the atomic reference
|
113
|
-
# @yieldparam [Boolean] old_mark the starting state of marked
|
114
|
-
#
|
115
|
-
# @return [ImmutableArray] the new value and new mark
|
116
|
-
def update
|
117
|
-
loop do
|
118
|
-
old_val, old_mark = reference
|
119
|
-
new_val, new_mark = yield old_val, old_mark
|
120
|
-
|
121
|
-
if compare_and_set old_val, new_val, old_mark, new_mark
|
122
|
-
return ImmutableArray[new_val, new_mark]
|
123
|
-
end
|
124
|
-
end
|
125
|
-
end
|
126
|
-
|
127
|
-
# @!macro [attach] atomic_markable_reference_method_try_update!
|
128
|
-
#
|
129
|
-
# Pass the current value to the given block, replacing it
|
130
|
-
# with the block's result. Raise an exception if the update
|
131
|
-
# fails.
|
132
|
-
#
|
133
|
-
# @yield [Object] Calculate a new value and marked state for the atomic
|
134
|
-
# reference using given (old) value and (old) marked
|
135
|
-
# @yieldparam [Object] old_val the starting value of the atomic reference
|
136
|
-
# @yieldparam [Boolean] old_mark the starting state of marked
|
137
|
-
#
|
138
|
-
# @return [ImmutableArray] the new value and marked state
|
139
|
-
#
|
140
|
-
# @raise [Concurrent::ConcurrentUpdateError] if the update fails
|
141
|
-
def try_update!
|
142
|
-
old_val, old_mark = reference
|
143
|
-
new_val, new_mark = yield old_val, old_mark
|
144
|
-
|
145
|
-
unless compare_and_set old_val, new_val, old_mark, new_mark
|
146
|
-
fail ::Concurrent::ConcurrentUpdateError,
|
147
|
-
'AtomicMarkableReference: Update failed due to race condition.',
|
148
|
-
'Note: If you would like to guarantee an update, please use ' \
|
149
|
-
'the `AtomicMarkableReference#update` method.'
|
150
|
-
end
|
151
|
-
|
152
|
-
ImmutableArray[new_val, new_mark]
|
153
|
-
end
|
154
|
-
|
155
|
-
# @!macro [attach] atomic_markable_reference_method_try_update
|
156
|
-
#
|
157
|
-
# Pass the current value to the given block, replacing it with the
|
158
|
-
# block's result. Simply return nil if update fails.
|
159
|
-
#
|
160
|
-
# @yield [Object] Calculate a new value and marked state for the atomic
|
161
|
-
# reference using given (old) value and (old) marked
|
162
|
-
# @yieldparam [Object] old_val the starting value of the atomic reference
|
163
|
-
# @yieldparam [Boolean] old_mark the starting state of marked
|
164
|
-
#
|
165
|
-
# @return [ImmutableArray] the new value and marked state, or nil if
|
166
|
-
# the update failed
|
167
|
-
def try_update
|
168
|
-
old_val, old_mark = reference
|
169
|
-
new_val, new_mark = yield old_val, old_mark
|
170
|
-
|
171
|
-
return unless compare_and_set old_val, new_val, old_mark, new_mark
|
172
|
-
|
173
|
-
ImmutableArray[new_val, new_mark]
|
174
|
-
end
|
175
|
-
|
176
|
-
# Internal/private ImmutableArray for representing pairs
|
177
|
-
class ImmutableArray < ::Array
|
178
|
-
def self.new(*args)
|
179
|
-
super(*args).freeze
|
180
|
-
end
|
181
|
-
end
|
182
|
-
end
|
183
|
-
end
|
184
|
-
end
|
@@ -1,126 +0,0 @@
|
|
1
|
-
module Concurrent
|
2
|
-
|
3
|
-
# @!visibility private
|
4
|
-
class LockFreeStack < Synchronization::Object
|
5
|
-
|
6
|
-
safe_initialization!
|
7
|
-
|
8
|
-
class Node
|
9
|
-
# TODO (pitr-ch 20-Dec-2016): Could be unified with Stack class?
|
10
|
-
|
11
|
-
attr_reader :value, :next_node
|
12
|
-
# allow to nil-ify to free GC when the entry is no longer relevant, not synchronised
|
13
|
-
attr_writer :value
|
14
|
-
|
15
|
-
def initialize(value, next_node)
|
16
|
-
@value = value
|
17
|
-
@next_node = next_node
|
18
|
-
end
|
19
|
-
|
20
|
-
singleton_class.send :alias_method, :[], :new
|
21
|
-
end
|
22
|
-
|
23
|
-
class Empty < Node
|
24
|
-
def next_node
|
25
|
-
self
|
26
|
-
end
|
27
|
-
end
|
28
|
-
|
29
|
-
EMPTY = Empty[nil, nil]
|
30
|
-
|
31
|
-
private(*attr_atomic(:head))
|
32
|
-
|
33
|
-
def self.of1(value)
|
34
|
-
new Node[value, EMPTY]
|
35
|
-
end
|
36
|
-
|
37
|
-
def self.of2(value1, value2)
|
38
|
-
new Node[value1, Node[value2, EMPTY]]
|
39
|
-
end
|
40
|
-
|
41
|
-
def initialize(head = EMPTY)
|
42
|
-
super()
|
43
|
-
self.head = head
|
44
|
-
end
|
45
|
-
|
46
|
-
def empty?(head = self.head)
|
47
|
-
head.equal? EMPTY
|
48
|
-
end
|
49
|
-
|
50
|
-
def compare_and_push(head, value)
|
51
|
-
compare_and_set_head head, Node[value, head]
|
52
|
-
end
|
53
|
-
|
54
|
-
def push(value)
|
55
|
-
while true
|
56
|
-
current_head = head
|
57
|
-
return self if compare_and_set_head current_head, Node[value, current_head]
|
58
|
-
end
|
59
|
-
end
|
60
|
-
|
61
|
-
def peek
|
62
|
-
head
|
63
|
-
end
|
64
|
-
|
65
|
-
def compare_and_pop(head)
|
66
|
-
compare_and_set_head head, head.next_node
|
67
|
-
end
|
68
|
-
|
69
|
-
def pop
|
70
|
-
while true
|
71
|
-
current_head = head
|
72
|
-
return current_head.value if compare_and_set_head current_head, current_head.next_node
|
73
|
-
end
|
74
|
-
end
|
75
|
-
|
76
|
-
def compare_and_clear(head)
|
77
|
-
compare_and_set_head head, EMPTY
|
78
|
-
end
|
79
|
-
|
80
|
-
include Enumerable
|
81
|
-
|
82
|
-
def each(head = nil)
|
83
|
-
return to_enum(:each, head) unless block_given?
|
84
|
-
it = head || peek
|
85
|
-
until it.equal?(EMPTY)
|
86
|
-
yield it.value
|
87
|
-
it = it.next_node
|
88
|
-
end
|
89
|
-
self
|
90
|
-
end
|
91
|
-
|
92
|
-
def clear
|
93
|
-
while true
|
94
|
-
current_head = head
|
95
|
-
return false if current_head == EMPTY
|
96
|
-
return true if compare_and_set_head current_head, EMPTY
|
97
|
-
end
|
98
|
-
end
|
99
|
-
|
100
|
-
def clear_if(head)
|
101
|
-
compare_and_set_head head, EMPTY
|
102
|
-
end
|
103
|
-
|
104
|
-
def replace_if(head, new_head)
|
105
|
-
compare_and_set_head head, new_head
|
106
|
-
end
|
107
|
-
|
108
|
-
def clear_each(&block)
|
109
|
-
while true
|
110
|
-
current_head = head
|
111
|
-
return self if current_head == EMPTY
|
112
|
-
if compare_and_set_head current_head, EMPTY
|
113
|
-
each current_head, &block
|
114
|
-
return self
|
115
|
-
end
|
116
|
-
end
|
117
|
-
end
|
118
|
-
|
119
|
-
# @return [String] Short string representation.
|
120
|
-
def to_s
|
121
|
-
format '<#%s:0x%x %s>', self.class, object_id << 1, to_a.to_s
|
122
|
-
end
|
123
|
-
|
124
|
-
alias_method :inspect, :to_s
|
125
|
-
end
|
126
|
-
end
|