backports 3.18.0 → 3.20.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 +47 -1
- data/Gemfile +3 -16
- data/README.md +31 -11
- data/backports.gemspec +1 -1
- data/lib/backports/2.0.0.rb +1 -1
- data/lib/backports/2.1.0.rb +1 -1
- data/lib/backports/2.2.0.rb +1 -1
- data/lib/backports/2.2.0/string/unicode_normalize.rb +3 -3
- data/lib/backports/2.3.0.rb +1 -1
- data/lib/backports/2.3.0/queue/close.rb +48 -0
- data/lib/backports/2.3.0/string.rb +3 -0
- data/lib/backports/2.4.0.rb +1 -1
- data/lib/backports/2.4.0/bignum.rb +3 -0
- data/lib/backports/2.4.0/bignum/dup.rb +5 -0
- data/lib/backports/2.5.0.rb +1 -1
- data/lib/backports/2.5.0/hash/transform_keys.rb +10 -3
- data/lib/backports/2.5.0/integer/sqrt.rb +1 -1
- data/lib/backports/2.5.0/string/undump.rb +2 -2
- data/lib/backports/2.5.rb +1 -1
- data/lib/backports/2.6.0.rb +2 -2
- data/lib/backports/2.6.0/enumerable/chain.rb +2 -0
- data/lib/backports/2.6.rb +1 -1
- data/lib/backports/2.7.0.rb +2 -2
- data/lib/backports/3.0.0.rb +3 -0
- data/lib/backports/3.0.0/env.rb +3 -0
- data/lib/backports/3.0.0/env/except.rb +10 -0
- data/lib/backports/3.0.0/hash.rb +3 -0
- data/lib/backports/3.0.0/hash/except.rb +10 -0
- data/lib/backports/3.0.0/hash/transform_keys.rb +48 -0
- data/lib/backports/3.0.0/ractor.rb +5 -0
- data/lib/backports/3.0.0/symbol.rb +3 -0
- data/lib/backports/3.0.0/symbol/name.rb +11 -0
- data/lib/backports/3.0.rb +1 -0
- data/lib/backports/ractor/cloner.rb +91 -0
- data/lib/backports/ractor/errors.rb +16 -0
- data/lib/backports/ractor/queues.rb +62 -0
- data/lib/backports/ractor/ractor.rb +261 -0
- data/lib/backports/ractor/sharing.rb +93 -0
- data/lib/backports/tools/filtered_queue.rb +202 -0
- data/lib/backports/version.rb +1 -1
- metadata +27 -7
@@ -0,0 +1,93 @@
|
|
1
|
+
class Ractor
|
2
|
+
class << self
|
3
|
+
# @api private
|
4
|
+
def ractor_isolate(val, move = false)
|
5
|
+
return val if move
|
6
|
+
|
7
|
+
Cloner.deep_clone(val)
|
8
|
+
end
|
9
|
+
|
10
|
+
private def ractor_check_shareability?(obj, freeze_all)
|
11
|
+
ractor_shareable_self?(obj, freeze_all) do
|
12
|
+
visited = {}
|
13
|
+
|
14
|
+
return false unless ractor_shareable_parts?(obj, freeze_all, visited)
|
15
|
+
|
16
|
+
ractor_mark_set_shareable(visited)
|
17
|
+
|
18
|
+
true
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
# yield if shareability can't be determined without looking at its parts
|
23
|
+
def ractor_shareable_self?(obj, freeze_all)
|
24
|
+
return true if @ractor_shareable.key?(obj)
|
25
|
+
return true if ractor_shareable_by_nature?(obj, freeze_all)
|
26
|
+
if obj.frozen? || (freeze_all && obj.freeze)
|
27
|
+
yield
|
28
|
+
else
|
29
|
+
false
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
private def ractor_shareable_parts?(obj, freeze_all, visited)
|
34
|
+
return true if visited.key?(obj)
|
35
|
+
visited[obj] = true
|
36
|
+
|
37
|
+
ractor_traverse(obj) do |part|
|
38
|
+
return false unless ractor_shareable_self?(part, freeze_all) do
|
39
|
+
ractor_shareable_parts?(part, freeze_all, visited)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
true
|
44
|
+
end
|
45
|
+
|
46
|
+
def ractor_mark_set_shareable(visited)
|
47
|
+
visited.each do |key|
|
48
|
+
@ractor_shareable[key] = Ractor
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
private def ractor_traverse(obj, &block)
|
53
|
+
case obj
|
54
|
+
when ::Hash
|
55
|
+
Hash obj.default
|
56
|
+
yield obj.default_proc
|
57
|
+
obj.each do |key, value|
|
58
|
+
yield key
|
59
|
+
yield value
|
60
|
+
end
|
61
|
+
when ::Range
|
62
|
+
yield obj.begin
|
63
|
+
yield obj.end
|
64
|
+
when ::Array, ::Struct
|
65
|
+
obj.each(&block)
|
66
|
+
when ::Complex
|
67
|
+
yield obj.real
|
68
|
+
yield obj.imaginary
|
69
|
+
when ::Rational
|
70
|
+
yield obj.numerator
|
71
|
+
yield obj.denominator
|
72
|
+
end
|
73
|
+
obj.instance_variables.each do |var|
|
74
|
+
yield obj.instance_variable_get(var)
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
private def ractor_shareable_by_nature?(obj, freeze_all)
|
79
|
+
case obj
|
80
|
+
when ::Module, ::Ractor
|
81
|
+
true
|
82
|
+
when ::Regexp, ::Range, ::Numeric
|
83
|
+
!freeze_all # Assume that these are literals that would have been frozen in 3.0
|
84
|
+
# unless we're making them shareable, in which case we might as well
|
85
|
+
# freeze them for real.
|
86
|
+
when ::Symbol, false, true, nil # Were only frozen in Ruby 2.3+
|
87
|
+
true
|
88
|
+
else
|
89
|
+
false
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
@@ -0,0 +1,202 @@
|
|
1
|
+
module Backports
|
2
|
+
class FilteredQueue
|
3
|
+
require 'backports/2.3.0/queue/close'
|
4
|
+
CONSUME_ON_ESCAPE = true
|
5
|
+
|
6
|
+
class ClosedQueueError < ::ClosedQueueError
|
7
|
+
end
|
8
|
+
class TimeoutError < ::ThreadError
|
9
|
+
end
|
10
|
+
|
11
|
+
class Message
|
12
|
+
# Not using Struct as we want comparision by identity
|
13
|
+
attr_reader :value
|
14
|
+
attr_accessor :reserved
|
15
|
+
|
16
|
+
def initialize(value)
|
17
|
+
@value = value
|
18
|
+
@reserved = false
|
19
|
+
end
|
20
|
+
end
|
21
|
+
private_constant :Message
|
22
|
+
|
23
|
+
# Like ::Queue, but with
|
24
|
+
# - filtering
|
25
|
+
# - timeout
|
26
|
+
# - raises on closed queues
|
27
|
+
|
28
|
+
attr_reader :num_waiting
|
29
|
+
|
30
|
+
# Timeout processing based on https://spin.atomicobject.com/2017/06/28/queue-pop-with-timeout-fixed/
|
31
|
+
def initialize
|
32
|
+
@mutex = ::Mutex.new
|
33
|
+
@queue = []
|
34
|
+
@closed = false
|
35
|
+
@received = ::ConditionVariable.new
|
36
|
+
@num_waiting = 0
|
37
|
+
end
|
38
|
+
|
39
|
+
def close
|
40
|
+
@mutex.synchronize do
|
41
|
+
@closed = true
|
42
|
+
@received.broadcast
|
43
|
+
end
|
44
|
+
self
|
45
|
+
end
|
46
|
+
|
47
|
+
def closed?
|
48
|
+
@closed
|
49
|
+
end
|
50
|
+
|
51
|
+
def <<(x)
|
52
|
+
@mutex.synchronize do
|
53
|
+
ensure_open
|
54
|
+
@queue << Message.new(x)
|
55
|
+
@received.signal
|
56
|
+
end
|
57
|
+
self
|
58
|
+
end
|
59
|
+
alias_method :push, :<<
|
60
|
+
|
61
|
+
def clear
|
62
|
+
@mutex.synchronize do
|
63
|
+
@queue.clear
|
64
|
+
end
|
65
|
+
self
|
66
|
+
end
|
67
|
+
|
68
|
+
def pop(timeout: nil, &block)
|
69
|
+
msg = nil
|
70
|
+
exclude = [] if block # exclusion list of messages rejected by this call
|
71
|
+
timeout_time = timeout + Time.now.to_f if timeout
|
72
|
+
while true do
|
73
|
+
@mutex.synchronize do
|
74
|
+
reenter if reentrant?
|
75
|
+
msg = acquire!(timeout_time, exclude)
|
76
|
+
return consume!(msg).value unless block
|
77
|
+
end
|
78
|
+
return msg.value if filter?(msg, &block)
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
def empty?
|
83
|
+
avail = @mutex.synchronize do
|
84
|
+
available!
|
85
|
+
end
|
86
|
+
|
87
|
+
!avail
|
88
|
+
end
|
89
|
+
|
90
|
+
protected def timeout_value
|
91
|
+
raise self.class::TimeoutError, "timeout elapsed"
|
92
|
+
end
|
93
|
+
|
94
|
+
protected def closed_queue_value
|
95
|
+
ensure_open
|
96
|
+
end
|
97
|
+
|
98
|
+
# @return if outer message should be consumed or not
|
99
|
+
protected def reenter
|
100
|
+
true
|
101
|
+
end
|
102
|
+
|
103
|
+
### private section
|
104
|
+
#
|
105
|
+
# bang methods require synchronization
|
106
|
+
|
107
|
+
# @returns:
|
108
|
+
# * true if message consumed (block result truthy or due to reentrant call)
|
109
|
+
# * false if rejected
|
110
|
+
private def filter?(msg)
|
111
|
+
consume = self.class::CONSUME_ON_ESCAPE
|
112
|
+
begin
|
113
|
+
reentered = consume_on_reentry(msg) do
|
114
|
+
consume = !!(yield msg.value)
|
115
|
+
end
|
116
|
+
reentered ? reenter : consume
|
117
|
+
ensure
|
118
|
+
commit(msg, consume) unless reentered
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
# @returns msg
|
123
|
+
private def consume!(msg)
|
124
|
+
@queue.delete(msg)
|
125
|
+
end
|
126
|
+
|
127
|
+
private def reject!(msg)
|
128
|
+
msg.reserved = false
|
129
|
+
@received.broadcast
|
130
|
+
end
|
131
|
+
|
132
|
+
private def commit(msg, consume)
|
133
|
+
@mutex.synchronize do
|
134
|
+
if consume
|
135
|
+
consume!(msg)
|
136
|
+
else
|
137
|
+
reject!(msg)
|
138
|
+
end
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
private def consume_on_reentry(msg)
|
143
|
+
q_map = current_filtered_queues
|
144
|
+
if (outer_msg = q_map[self])
|
145
|
+
commit(outer_msg, reenter)
|
146
|
+
end
|
147
|
+
q_map[self] = msg
|
148
|
+
begin
|
149
|
+
yield
|
150
|
+
ensure
|
151
|
+
reentered = !q_map.delete(self)
|
152
|
+
end
|
153
|
+
reentered
|
154
|
+
end
|
155
|
+
|
156
|
+
private def reentrant?
|
157
|
+
!!current_filtered_queues[self]
|
158
|
+
end
|
159
|
+
|
160
|
+
# @returns Hash { FilteredQueue => Message }
|
161
|
+
private def current_filtered_queues
|
162
|
+
t = Thread.current
|
163
|
+
t.thread_variable_get(:backports_currently_filtered_queues) or
|
164
|
+
t.thread_variable_set(:backports_currently_filtered_queues, {}.compare_by_identity)
|
165
|
+
end
|
166
|
+
|
167
|
+
# private methods assume @mutex synchonized
|
168
|
+
# adds to exclude list
|
169
|
+
private def acquire!(timeout_time, exclude = nil)
|
170
|
+
while true do
|
171
|
+
if (msg = available!(exclude))
|
172
|
+
msg.reserved = true
|
173
|
+
exclude << msg if exclude
|
174
|
+
return msg
|
175
|
+
end
|
176
|
+
return closed_queue_value if @closed
|
177
|
+
# wait for element or timeout
|
178
|
+
if timeout_time
|
179
|
+
remaining_time = timeout_time - ::Time.now.to_f
|
180
|
+
return timeout_value if remaining_time <= 0
|
181
|
+
end
|
182
|
+
begin
|
183
|
+
@num_waiting += 1
|
184
|
+
@received.wait(@mutex, remaining_time)
|
185
|
+
ensure
|
186
|
+
@num_waiting -= 1
|
187
|
+
end
|
188
|
+
end
|
189
|
+
end
|
190
|
+
|
191
|
+
private def available!(exclude = nil)
|
192
|
+
@queue.find do |msg|
|
193
|
+
next if exclude && exclude.include?(msg)
|
194
|
+
!msg.reserved
|
195
|
+
end
|
196
|
+
end
|
197
|
+
|
198
|
+
private def ensure_open
|
199
|
+
raise self.class::ClosedQueueError, 'queue closed' if @closed
|
200
|
+
end
|
201
|
+
end
|
202
|
+
end
|
data/lib/backports/version.rb
CHANGED
@@ -1,3 +1,3 @@
|
|
1
1
|
module Backports
|
2
|
-
VERSION = "3.
|
2
|
+
VERSION = "3.20.1" unless Backports.constants.include? :VERSION # the guard is against a redefinition warning that happens on Travis
|
3
3
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: backports
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 3.
|
4
|
+
version: 3.20.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Marc-André Lafortune
|
8
|
-
autorequire:
|
8
|
+
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2021-01-03 00:00:00.000000000 Z
|
12
12
|
dependencies: []
|
13
13
|
description: Essential backports that enable many of the nice features of Ruby for
|
14
14
|
earlier versions.
|
@@ -425,12 +425,16 @@ files:
|
|
425
425
|
- lib/backports/2.3.0/numeric.rb
|
426
426
|
- lib/backports/2.3.0/numeric/negative.rb
|
427
427
|
- lib/backports/2.3.0/numeric/positive.rb
|
428
|
+
- lib/backports/2.3.0/queue/close.rb
|
429
|
+
- lib/backports/2.3.0/string.rb
|
428
430
|
- lib/backports/2.3.0/string/uminus.rb
|
429
431
|
- lib/backports/2.3.0/string/uplus.rb
|
430
432
|
- lib/backports/2.3.0/struct.rb
|
431
433
|
- lib/backports/2.3.0/struct/dig.rb
|
432
434
|
- lib/backports/2.3.rb
|
433
435
|
- lib/backports/2.4.0.rb
|
436
|
+
- lib/backports/2.4.0/bignum.rb
|
437
|
+
- lib/backports/2.4.0/bignum/dup.rb
|
434
438
|
- lib/backports/2.4.0/comparable.rb
|
435
439
|
- lib/backports/2.4.0/comparable/clamp.rb
|
436
440
|
- lib/backports/2.4.0/enumerable.rb
|
@@ -528,6 +532,16 @@ files:
|
|
528
532
|
- lib/backports/2.7.0/time/ceil.rb
|
529
533
|
- lib/backports/2.7.0/time/floor.rb
|
530
534
|
- lib/backports/2.7.rb
|
535
|
+
- lib/backports/3.0.0.rb
|
536
|
+
- lib/backports/3.0.0/env.rb
|
537
|
+
- lib/backports/3.0.0/env/except.rb
|
538
|
+
- lib/backports/3.0.0/hash.rb
|
539
|
+
- lib/backports/3.0.0/hash/except.rb
|
540
|
+
- lib/backports/3.0.0/hash/transform_keys.rb
|
541
|
+
- lib/backports/3.0.0/ractor.rb
|
542
|
+
- lib/backports/3.0.0/symbol.rb
|
543
|
+
- lib/backports/3.0.0/symbol/name.rb
|
544
|
+
- lib/backports/3.0.rb
|
531
545
|
- lib/backports/basic_object.rb
|
532
546
|
- lib/backports/force/array_map.rb
|
533
547
|
- lib/backports/force/enumerable_map.rb
|
@@ -535,6 +549,11 @@ files:
|
|
535
549
|
- lib/backports/force/string_length.rb
|
536
550
|
- lib/backports/force/string_size.rb
|
537
551
|
- lib/backports/latest.rb
|
552
|
+
- lib/backports/ractor/cloner.rb
|
553
|
+
- lib/backports/ractor/errors.rb
|
554
|
+
- lib/backports/ractor/queues.rb
|
555
|
+
- lib/backports/ractor/ractor.rb
|
556
|
+
- lib/backports/ractor/sharing.rb
|
538
557
|
- lib/backports/rails.rb
|
539
558
|
- lib/backports/rails/array.rb
|
540
559
|
- lib/backports/rails/enumerable.rb
|
@@ -553,6 +572,7 @@ files:
|
|
553
572
|
- lib/backports/tools/arguments.rb
|
554
573
|
- lib/backports/tools/deprecation.rb
|
555
574
|
- lib/backports/tools/extreme_object.rb
|
575
|
+
- lib/backports/tools/filtered_queue.rb
|
556
576
|
- lib/backports/tools/float_integer_conversion.rb
|
557
577
|
- lib/backports/tools/io.rb
|
558
578
|
- lib/backports/tools/make_block_optional.rb
|
@@ -566,10 +586,10 @@ homepage: http://github.com/marcandre/backports
|
|
566
586
|
licenses:
|
567
587
|
- MIT
|
568
588
|
metadata:
|
569
|
-
changelog_uri: https://github.com/marcandre/backports/blob/master/CHANGELOG.
|
589
|
+
changelog_uri: https://github.com/marcandre/backports/blob/master/CHANGELOG.md
|
570
590
|
source_code_uri: https://github.com/marcandre/backports
|
571
591
|
bug_tracker_uri: https://github.com/marcandre/backports/issues
|
572
|
-
post_install_message:
|
592
|
+
post_install_message:
|
573
593
|
rdoc_options: []
|
574
594
|
require_paths:
|
575
595
|
- lib
|
@@ -584,8 +604,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
584
604
|
- !ruby/object:Gem::Version
|
585
605
|
version: '0'
|
586
606
|
requirements: []
|
587
|
-
rubygems_version: 3.1.
|
588
|
-
signing_key:
|
607
|
+
rubygems_version: 3.1.4
|
608
|
+
signing_key:
|
589
609
|
specification_version: 4
|
590
610
|
summary: Backports of Ruby features for older Ruby.
|
591
611
|
test_files: []
|