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.
Files changed (64) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +429 -0
  3. data/{LICENSE.txt → LICENSE.md} +2 -0
  4. data/README.md +203 -105
  5. data/{lib → lib-edge}/concurrent/actor/behaviour/abstract.rb +0 -0
  6. data/{lib → lib-edge}/concurrent/actor/behaviour/awaits.rb +0 -0
  7. data/{lib → lib-edge}/concurrent/actor/behaviour/buffer.rb +0 -0
  8. data/{lib → lib-edge}/concurrent/actor/behaviour/errors_on_unknown_message.rb +0 -0
  9. data/{lib → lib-edge}/concurrent/actor/behaviour/executes_context.rb +0 -0
  10. data/{lib → lib-edge}/concurrent/actor/behaviour/linking.rb +0 -0
  11. data/{lib → lib-edge}/concurrent/actor/behaviour/pausing.rb +0 -0
  12. data/{lib → lib-edge}/concurrent/actor/behaviour/removes_child.rb +0 -0
  13. data/{lib → lib-edge}/concurrent/actor/behaviour/sets_results.rb +0 -0
  14. data/{lib → lib-edge}/concurrent/actor/behaviour/supervising.rb +0 -0
  15. data/{lib → lib-edge}/concurrent/actor/behaviour/termination.rb +1 -1
  16. data/{lib → lib-edge}/concurrent/actor/behaviour.rb +1 -1
  17. data/{lib → lib-edge}/concurrent/actor/context.rb +1 -1
  18. data/{lib → lib-edge}/concurrent/actor/core.rb +2 -1
  19. data/{lib → lib-edge}/concurrent/actor/default_dead_letter_handler.rb +0 -0
  20. data/{lib → lib-edge}/concurrent/actor/envelope.rb +0 -0
  21. data/{lib → lib-edge}/concurrent/actor/errors.rb +0 -0
  22. data/{lib → lib-edge}/concurrent/actor/internal_delegations.rb +0 -0
  23. data/{lib → lib-edge}/concurrent/actor/public_delegations.rb +0 -0
  24. data/{lib → lib-edge}/concurrent/actor/reference.rb +1 -1
  25. data/{lib → lib-edge}/concurrent/actor/root.rb +0 -0
  26. data/{lib → lib-edge}/concurrent/actor/type_check.rb +0 -0
  27. data/{lib → lib-edge}/concurrent/actor/utils/ad_hoc.rb +0 -0
  28. data/{lib → lib-edge}/concurrent/actor/utils/balancer.rb +0 -0
  29. data/{lib → lib-edge}/concurrent/actor/utils/broadcast.rb +0 -0
  30. data/{lib → lib-edge}/concurrent/actor/utils/pool.rb +0 -0
  31. data/{lib → lib-edge}/concurrent/actor/utils.rb +0 -0
  32. data/{lib → lib-edge}/concurrent/actor.rb +9 -5
  33. data/{lib → lib-edge}/concurrent/channel/buffer/base.rb +14 -14
  34. data/{lib → lib-edge}/concurrent/channel/buffer/buffered.rb +0 -0
  35. data/{lib → lib-edge}/concurrent/channel/buffer/dropping.rb +0 -0
  36. data/{lib → lib-edge}/concurrent/channel/buffer/sliding.rb +0 -0
  37. data/{lib → lib-edge}/concurrent/channel/buffer/ticker.rb +0 -0
  38. data/{lib → lib-edge}/concurrent/channel/buffer/timer.rb +0 -0
  39. data/{lib → lib-edge}/concurrent/channel/buffer/unbuffered.rb +1 -1
  40. data/{lib → lib-edge}/concurrent/channel/buffer.rb +0 -0
  41. data/{lib → lib-edge}/concurrent/channel/selector/after_clause.rb +0 -0
  42. data/{lib → lib-edge}/concurrent/channel/selector/default_clause.rb +0 -0
  43. data/{lib → lib-edge}/concurrent/channel/selector/error_clause.rb +0 -0
  44. data/{lib → lib-edge}/concurrent/channel/selector/put_clause.rb +0 -0
  45. data/{lib → lib-edge}/concurrent/channel/selector/take_clause.rb +0 -0
  46. data/{lib → lib-edge}/concurrent/channel/selector.rb +0 -0
  47. data/{lib → lib-edge}/concurrent/channel/tick.rb +0 -0
  48. data/{lib → lib-edge}/concurrent/channel.rb +2 -1
  49. data/{lib → lib-edge}/concurrent/edge/cancellation.rb +5 -4
  50. data/{lib → lib-edge}/concurrent/edge/lock_free_linked_set/node.rb +2 -2
  51. data/{lib → lib-edge}/concurrent/edge/lock_free_linked_set/window.rb +0 -0
  52. data/{lib → lib-edge}/concurrent/edge/lock_free_linked_set.rb +8 -7
  53. data/{lib → lib-edge}/concurrent/edge/lock_free_queue.rb +0 -0
  54. data/{lib → lib-edge}/concurrent/edge/old_channel_integration.rb +0 -0
  55. data/{lib → lib-edge}/concurrent/edge/processing_actor.rb +3 -3
  56. data/lib-edge/concurrent/edge/promises.rb +178 -0
  57. data/{lib → lib-edge}/concurrent/edge/throttle.rb +24 -15
  58. data/lib-edge/concurrent/edge.rb +21 -0
  59. data/lib-edge/concurrent/lazy_register.rb +83 -0
  60. data/{lib → lib-edge}/concurrent-edge.rb +0 -4
  61. metadata +71 -70
  62. data/lib/concurrent/edge/atomic_markable_reference.rb +0 -184
  63. data/lib/concurrent/edge/lock_free_stack.rb +0 -126
  64. 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.3.1
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: 2017-02-26 00:00:00.000000000 Z
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.5
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.5
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.txt
39
+ - LICENSE.md
40
+ - CHANGELOG.md
40
41
  files:
41
- - LICENSE.txt
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/atomic_markable_reference.rb
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/lock_free_stack.rb
95
- - lib/concurrent/edge/old_channel_integration.rb
96
- - lib/concurrent/edge/processing_actor.rb
97
- - lib/concurrent/edge/promises.rb
98
- - lib/concurrent/edge/throttle.rb
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: 1.9.3
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: '0'
118
+ version: 1.3.1
117
119
  requirements: []
118
120
  rubyforge_project:
119
- rubygems_version: 2.6.8
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