concurrent-ruby 0.9.2-java → 1.0.0-java

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 (121) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +49 -1
  3. data/README.md +86 -120
  4. data/lib/concurrent.rb +14 -5
  5. data/lib/concurrent/agent.rb +587 -0
  6. data/lib/concurrent/array.rb +39 -0
  7. data/lib/concurrent/async.rb +296 -149
  8. data/lib/concurrent/atom.rb +135 -45
  9. data/lib/concurrent/atomic/abstract_thread_local_var.rb +38 -0
  10. data/lib/concurrent/atomic/atomic_boolean.rb +83 -118
  11. data/lib/concurrent/atomic/atomic_fixnum.rb +101 -163
  12. data/lib/concurrent/atomic/atomic_reference.rb +1 -8
  13. data/lib/concurrent/atomic/count_down_latch.rb +62 -103
  14. data/lib/concurrent/atomic/cyclic_barrier.rb +3 -1
  15. data/lib/concurrent/atomic/event.rb +1 -1
  16. data/lib/concurrent/atomic/java_count_down_latch.rb +39 -0
  17. data/lib/concurrent/atomic/java_thread_local_var.rb +50 -0
  18. data/lib/concurrent/atomic/mutex_atomic_boolean.rb +60 -0
  19. data/lib/concurrent/atomic/mutex_atomic_fixnum.rb +91 -0
  20. data/lib/concurrent/atomic/mutex_count_down_latch.rb +43 -0
  21. data/lib/concurrent/atomic/mutex_semaphore.rb +115 -0
  22. data/lib/concurrent/atomic/read_write_lock.rb +5 -4
  23. data/lib/concurrent/atomic/reentrant_read_write_lock.rb +3 -1
  24. data/lib/concurrent/atomic/ruby_thread_local_var.rb +172 -0
  25. data/lib/concurrent/atomic/semaphore.rb +84 -178
  26. data/lib/concurrent/atomic/thread_local_var.rb +65 -294
  27. data/lib/concurrent/atomic_reference/jruby+truffle.rb +1 -0
  28. data/lib/concurrent/atomic_reference/jruby.rb +1 -1
  29. data/lib/concurrent/atomic_reference/mutex_atomic.rb +14 -8
  30. data/lib/concurrent/atomic_reference/ruby.rb +1 -1
  31. data/lib/concurrent/atomics.rb +7 -37
  32. data/lib/concurrent/collection/copy_on_notify_observer_set.rb +7 -15
  33. data/lib/concurrent/collection/copy_on_write_observer_set.rb +7 -15
  34. data/lib/concurrent/collection/java_non_concurrent_priority_queue.rb +84 -0
  35. data/lib/concurrent/collection/map/atomic_reference_map_backend.rb +927 -0
  36. data/lib/concurrent/collection/map/mri_map_backend.rb +66 -0
  37. data/lib/concurrent/collection/map/non_concurrent_map_backend.rb +144 -0
  38. data/lib/concurrent/collection/map/synchronized_map_backend.rb +86 -0
  39. data/lib/concurrent/collection/non_concurrent_priority_queue.rb +143 -0
  40. data/lib/concurrent/collection/ruby_non_concurrent_priority_queue.rb +150 -0
  41. data/lib/concurrent/concern/dereferenceable.rb +9 -24
  42. data/lib/concurrent/concern/logging.rb +1 -1
  43. data/lib/concurrent/concern/obligation.rb +11 -20
  44. data/lib/concurrent/concern/observable.rb +38 -13
  45. data/lib/concurrent/configuration.rb +23 -152
  46. data/lib/concurrent/constants.rb +8 -0
  47. data/lib/concurrent/delay.rb +14 -12
  48. data/lib/concurrent/exchanger.rb +339 -41
  49. data/lib/concurrent/executor/abstract_executor_service.rb +134 -0
  50. data/lib/concurrent/executor/executor_service.rb +23 -359
  51. data/lib/concurrent/executor/immediate_executor.rb +3 -2
  52. data/lib/concurrent/executor/java_executor_service.rb +100 -0
  53. data/lib/concurrent/executor/java_single_thread_executor.rb +3 -3
  54. data/lib/concurrent/executor/java_thread_pool_executor.rb +3 -4
  55. data/lib/concurrent/executor/ruby_executor_service.rb +78 -0
  56. data/lib/concurrent/executor/ruby_single_thread_executor.rb +10 -66
  57. data/lib/concurrent/executor/ruby_thread_pool_executor.rb +25 -22
  58. data/lib/concurrent/executor/safe_task_executor.rb +6 -7
  59. data/lib/concurrent/executor/serial_executor_service.rb +34 -0
  60. data/lib/concurrent/executor/serialized_execution.rb +10 -33
  61. data/lib/concurrent/executor/serialized_execution_delegator.rb +28 -0
  62. data/lib/concurrent/executor/simple_executor_service.rb +1 -10
  63. data/lib/concurrent/executor/single_thread_executor.rb +20 -10
  64. data/lib/concurrent/executor/timer_set.rb +8 -10
  65. data/lib/concurrent/executors.rb +12 -2
  66. data/lib/concurrent/future.rb +6 -4
  67. data/lib/concurrent/hash.rb +35 -0
  68. data/lib/concurrent/immutable_struct.rb +5 -1
  69. data/lib/concurrent/ivar.rb +12 -16
  70. data/lib/concurrent/lazy_register.rb +11 -8
  71. data/lib/concurrent/map.rb +180 -0
  72. data/lib/concurrent/maybe.rb +6 -3
  73. data/lib/concurrent/mutable_struct.rb +7 -6
  74. data/lib/concurrent/mvar.rb +26 -2
  75. data/lib/concurrent/{executor/executor.rb → options.rb} +5 -29
  76. data/lib/concurrent/promise.rb +7 -5
  77. data/lib/concurrent/scheduled_task.rb +13 -71
  78. data/lib/concurrent/settable_struct.rb +5 -4
  79. data/lib/concurrent/synchronization.rb +15 -3
  80. data/lib/concurrent/synchronization/abstract_lockable_object.rb +98 -0
  81. data/lib/concurrent/synchronization/abstract_object.rb +7 -146
  82. data/lib/concurrent/synchronization/abstract_struct.rb +2 -3
  83. data/lib/concurrent/synchronization/condition.rb +6 -4
  84. data/lib/concurrent/synchronization/jruby_lockable_object.rb +13 -0
  85. data/lib/concurrent/synchronization/jruby_object.rb +44 -0
  86. data/lib/concurrent/synchronization/lock.rb +3 -2
  87. data/lib/concurrent/synchronization/lockable_object.rb +72 -0
  88. data/lib/concurrent/synchronization/mri_lockable_object.rb +71 -0
  89. data/lib/concurrent/synchronization/mri_object.rb +43 -0
  90. data/lib/concurrent/synchronization/object.rb +140 -73
  91. data/lib/concurrent/synchronization/rbx_lockable_object.rb +65 -0
  92. data/lib/concurrent/synchronization/rbx_object.rb +30 -73
  93. data/lib/concurrent/synchronization/volatile.rb +34 -0
  94. data/lib/concurrent/thread_safe/synchronized_delegator.rb +50 -0
  95. data/lib/concurrent/thread_safe/util.rb +14 -0
  96. data/lib/concurrent/thread_safe/util/adder.rb +74 -0
  97. data/lib/concurrent/thread_safe/util/array_hash_rbx.rb +30 -0
  98. data/lib/concurrent/thread_safe/util/cheap_lockable.rb +118 -0
  99. data/lib/concurrent/thread_safe/util/power_of_two_tuple.rb +38 -0
  100. data/lib/concurrent/thread_safe/util/striped64.rb +241 -0
  101. data/lib/concurrent/thread_safe/util/volatile.rb +75 -0
  102. data/lib/concurrent/thread_safe/util/xor_shift_random.rb +50 -0
  103. data/lib/concurrent/timer_task.rb +3 -4
  104. data/lib/concurrent/tuple.rb +86 -0
  105. data/lib/concurrent/tvar.rb +5 -1
  106. data/lib/concurrent/utility/at_exit.rb +1 -1
  107. data/lib/concurrent/utility/engine.rb +4 -0
  108. data/lib/concurrent/utility/monotonic_time.rb +3 -4
  109. data/lib/concurrent/utility/native_extension_loader.rb +50 -30
  110. data/lib/concurrent/version.rb +2 -2
  111. data/lib/concurrent_ruby_ext.jar +0 -0
  112. metadata +47 -12
  113. data/lib/concurrent/atomic/condition.rb +0 -78
  114. data/lib/concurrent/collection/priority_queue.rb +0 -360
  115. data/lib/concurrent/synchronization/java_object.rb +0 -34
  116. data/lib/concurrent/synchronization/monitor_object.rb +0 -27
  117. data/lib/concurrent/synchronization/mutex_object.rb +0 -43
  118. data/lib/concurrent/utilities.rb +0 -5
  119. data/lib/concurrent/utility/timeout.rb +0 -39
  120. data/lib/concurrent/utility/timer.rb +0 -26
  121. data/lib/concurrent_ruby.rb +0 -2
@@ -0,0 +1,66 @@
1
+ require 'thread'
2
+ require 'concurrent/collection/map/non_concurrent_map_backend'
3
+
4
+ module Concurrent
5
+
6
+ # @!visibility private
7
+ module Collection
8
+
9
+ # @!visibility private
10
+ class MriMapBackend < NonConcurrentMapBackend
11
+
12
+ def initialize(options = nil)
13
+ super(options)
14
+ @write_lock = Mutex.new
15
+ end
16
+
17
+ def []=(key, value)
18
+ @write_lock.synchronize { super }
19
+ end
20
+
21
+ def compute_if_absent(key)
22
+ if stored_value = _get(key) # fast non-blocking path for the most likely case
23
+ stored_value
24
+ else
25
+ @write_lock.synchronize { super }
26
+ end
27
+ end
28
+
29
+ def compute_if_present(key)
30
+ @write_lock.synchronize { super }
31
+ end
32
+
33
+ def compute(key)
34
+ @write_lock.synchronize { super }
35
+ end
36
+
37
+ def merge_pair(key, value)
38
+ @write_lock.synchronize { super }
39
+ end
40
+
41
+ def replace_pair(key, old_value, new_value)
42
+ @write_lock.synchronize { super }
43
+ end
44
+
45
+ def replace_if_exists(key, new_value)
46
+ @write_lock.synchronize { super }
47
+ end
48
+
49
+ def get_and_set(key, value)
50
+ @write_lock.synchronize { super }
51
+ end
52
+
53
+ def delete(key)
54
+ @write_lock.synchronize { super }
55
+ end
56
+
57
+ def delete_pair(key, value)
58
+ @write_lock.synchronize { super }
59
+ end
60
+
61
+ def clear
62
+ @write_lock.synchronize { super }
63
+ end
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,144 @@
1
+ require 'concurrent/constants'
2
+
3
+ module Concurrent
4
+
5
+ # @!visibility private
6
+ module Collection
7
+
8
+ # @!visibility private
9
+ class NonConcurrentMapBackend
10
+
11
+ # WARNING: all public methods of the class must operate on the @backend
12
+ # directly without calling each other. This is important because of the
13
+ # SynchronizedMapBackend which uses a non-reentrant mutex for perfomance
14
+ # reasons.
15
+ def initialize(options = nil)
16
+ @backend = {}
17
+ end
18
+
19
+ def [](key)
20
+ @backend[key]
21
+ end
22
+
23
+ def []=(key, value)
24
+ @backend[key] = value
25
+ end
26
+
27
+ def compute_if_absent(key)
28
+ if NULL != (stored_value = @backend.fetch(key, NULL))
29
+ stored_value
30
+ else
31
+ @backend[key] = yield
32
+ end
33
+ end
34
+
35
+ def replace_pair(key, old_value, new_value)
36
+ if pair?(key, old_value)
37
+ @backend[key] = new_value
38
+ true
39
+ else
40
+ false
41
+ end
42
+ end
43
+
44
+ def replace_if_exists(key, new_value)
45
+ if NULL != (stored_value = @backend.fetch(key, NULL))
46
+ @backend[key] = new_value
47
+ stored_value
48
+ end
49
+ end
50
+
51
+ def compute_if_present(key)
52
+ if NULL != (stored_value = @backend.fetch(key, NULL))
53
+ store_computed_value(key, yield(stored_value))
54
+ end
55
+ end
56
+
57
+ def compute(key)
58
+ store_computed_value(key, yield(@backend[key]))
59
+ end
60
+
61
+ def merge_pair(key, value)
62
+ if NULL == (stored_value = @backend.fetch(key, NULL))
63
+ @backend[key] = value
64
+ else
65
+ store_computed_value(key, yield(stored_value))
66
+ end
67
+ end
68
+
69
+ def get_and_set(key, value)
70
+ stored_value = @backend[key]
71
+ @backend[key] = value
72
+ stored_value
73
+ end
74
+
75
+ def key?(key)
76
+ @backend.key?(key)
77
+ end
78
+
79
+ def value?(value)
80
+ @backend.value?(value)
81
+ end
82
+
83
+ def delete(key)
84
+ @backend.delete(key)
85
+ end
86
+
87
+ def delete_pair(key, value)
88
+ if pair?(key, value)
89
+ @backend.delete(key)
90
+ true
91
+ else
92
+ false
93
+ end
94
+ end
95
+
96
+ def clear
97
+ @backend.clear
98
+ self
99
+ end
100
+
101
+ def each_pair
102
+ dupped_backend.each_pair do |k, v|
103
+ yield k, v
104
+ end
105
+ self
106
+ end
107
+
108
+ def size
109
+ @backend.size
110
+ end
111
+
112
+ def get_or_default(key, default_value)
113
+ @backend.fetch(key, default_value)
114
+ end
115
+
116
+ alias_method :_get, :[]
117
+ alias_method :_set, :[]=
118
+ private :_get, :_set
119
+ private
120
+ def initialize_copy(other)
121
+ super
122
+ @backend = {}
123
+ self
124
+ end
125
+
126
+ def dupped_backend
127
+ @backend.dup
128
+ end
129
+
130
+ def pair?(key, expected_value)
131
+ NULL != (stored_value = @backend.fetch(key, NULL)) && expected_value.equal?(stored_value)
132
+ end
133
+
134
+ def store_computed_value(key, new_value)
135
+ if new_value.nil?
136
+ @backend.delete(key)
137
+ nil
138
+ else
139
+ @backend[key] = new_value
140
+ end
141
+ end
142
+ end
143
+ end
144
+ end
@@ -0,0 +1,86 @@
1
+ require 'concurrent/collection/map/non_concurrent_map_backend'
2
+
3
+ module Concurrent
4
+
5
+ # @!visibility private
6
+ module Collection
7
+
8
+ # @!visibility private
9
+ class SynchronizedMapBackend < NonConcurrentMapBackend
10
+
11
+ require 'mutex_m'
12
+ include Mutex_m
13
+ # WARNING: Mutex_m is a non-reentrant lock, so the synchronized methods are
14
+ # not allowed to call each other.
15
+
16
+ def [](key)
17
+ synchronize { super }
18
+ end
19
+
20
+ def []=(key, value)
21
+ synchronize { super }
22
+ end
23
+
24
+ def compute_if_absent(key)
25
+ synchronize { super }
26
+ end
27
+
28
+ def compute_if_present(key)
29
+ synchronize { super }
30
+ end
31
+
32
+ def compute(key)
33
+ synchronize { super }
34
+ end
35
+
36
+ def merge_pair(key, value)
37
+ synchronize { super }
38
+ end
39
+
40
+ def replace_pair(key, old_value, new_value)
41
+ synchronize { super }
42
+ end
43
+
44
+ def replace_if_exists(key, new_value)
45
+ synchronize { super }
46
+ end
47
+
48
+ def get_and_set(key, value)
49
+ synchronize { super }
50
+ end
51
+
52
+ def key?(key)
53
+ synchronize { super }
54
+ end
55
+
56
+ def value?(value)
57
+ synchronize { super }
58
+ end
59
+
60
+ def delete(key)
61
+ synchronize { super }
62
+ end
63
+
64
+ def delete_pair(key, value)
65
+ synchronize { super }
66
+ end
67
+
68
+ def clear
69
+ synchronize { super }
70
+ end
71
+
72
+ def size
73
+ synchronize { super }
74
+ end
75
+
76
+ def get_or_default(key, default_value)
77
+ synchronize { super }
78
+ end
79
+
80
+ private
81
+ def dupped_backend
82
+ synchronize { super }
83
+ end
84
+ end
85
+ end
86
+ end
@@ -0,0 +1,143 @@
1
+ require 'concurrent/collection/java_non_concurrent_priority_queue'
2
+ require 'concurrent/collection/ruby_non_concurrent_priority_queue'
3
+ require 'concurrent/utility/engine'
4
+
5
+ module Concurrent
6
+ module Collection
7
+
8
+ # @!visibility private
9
+ # @!macro internal_implementation_note
10
+ NonConcurrentPriorityQueueImplementation = case
11
+ when Concurrent.on_jruby?
12
+ JavaNonConcurrentPriorityQueue
13
+ else
14
+ RubyNonConcurrentPriorityQueue
15
+ end
16
+ private_constant :NonConcurrentPriorityQueueImplementation
17
+
18
+ # @!macro [attach] priority_queue
19
+ #
20
+ # A queue collection in which the elements are sorted based on their
21
+ # comparison (spaceship) operator `<=>`. Items are added to the queue
22
+ # at a position relative to their priority. On removal the element
23
+ # with the "highest" priority is removed. By default the sort order is
24
+ # from highest to lowest, but a lowest-to-highest sort order can be
25
+ # set on construction.
26
+ #
27
+ # The API is based on the `Queue` class from the Ruby standard library.
28
+ #
29
+ # The pure Ruby implementation, `RubyNonConcurrentPriorityQueue` uses a heap algorithm
30
+ # stored in an array. The algorithm is based on the work of Robert Sedgewick
31
+ # and Kevin Wayne.
32
+ #
33
+ # The JRuby native implementation is a thin wrapper around the standard
34
+ # library `java.util.NonConcurrentPriorityQueue`.
35
+ #
36
+ # When running under JRuby the class `NonConcurrentPriorityQueue` extends `JavaNonConcurrentPriorityQueue`.
37
+ # When running under all other interpreters it extends `RubyNonConcurrentPriorityQueue`.
38
+ #
39
+ # @note This implementation is *not* thread safe.
40
+ #
41
+ # @see http://en.wikipedia.org/wiki/Priority_queue
42
+ # @see http://ruby-doc.org/stdlib-2.0.0/libdoc/thread/rdoc/Queue.html
43
+ #
44
+ # @see http://algs4.cs.princeton.edu/24pq/index.php#2.6
45
+ # @see http://algs4.cs.princeton.edu/24pq/MaxPQ.java.html
46
+ #
47
+ # @see http://docs.oracle.com/javase/7/docs/api/java/util/PriorityQueue.html
48
+ #
49
+ # @!visibility private
50
+ class NonConcurrentPriorityQueue < NonConcurrentPriorityQueueImplementation
51
+
52
+ alias_method :has_priority?, :include?
53
+
54
+ alias_method :size, :length
55
+
56
+ alias_method :deq, :pop
57
+ alias_method :shift, :pop
58
+
59
+ alias_method :<<, :push
60
+ alias_method :enq, :push
61
+
62
+ # @!method initialize(opts = {})
63
+ # @!macro [new] priority_queue_method_initialize
64
+ #
65
+ # Create a new priority queue with no items.
66
+ #
67
+ # @param [Hash] opts the options for creating the queue
68
+ # @option opts [Symbol] :order (:max) dictates the order in which items are
69
+ # stored: from highest to lowest when `:max` or `:high`; from lowest to
70
+ # highest when `:min` or `:low`
71
+
72
+ # @!method clear
73
+ # @!macro [new] priority_queue_method_clear
74
+ #
75
+ # Removes all of the elements from this priority queue.
76
+
77
+ # @!method delete(item)
78
+ # @!macro [new] priority_queue_method_delete
79
+ #
80
+ # Deletes all items from `self` that are equal to `item`.
81
+ #
82
+ # @param [Object] item the item to be removed from the queue
83
+ # @return [Object] true if the item is found else false
84
+
85
+ # @!method empty?
86
+ # @!macro [new] priority_queue_method_empty
87
+ #
88
+ # Returns `true` if `self` contains no elements.
89
+ #
90
+ # @return [Boolean] true if there are no items in the queue else false
91
+
92
+ # @!method include?(item)
93
+ # @!macro [new] priority_queue_method_include
94
+ #
95
+ # Returns `true` if the given item is present in `self` (that is, if any
96
+ # element == `item`), otherwise returns false.
97
+ #
98
+ # @param [Object] item the item to search for
99
+ #
100
+ # @return [Boolean] true if the item is found else false
101
+
102
+ # @!method length
103
+ # @!macro [new] priority_queue_method_length
104
+ #
105
+ # The current length of the queue.
106
+ #
107
+ # @return [Fixnum] the number of items in the queue
108
+
109
+ # @!method peek
110
+ # @!macro [new] priority_queue_method_peek
111
+ #
112
+ # Retrieves, but does not remove, the head of this queue, or returns `nil`
113
+ # if this queue is empty.
114
+ #
115
+ # @return [Object] the head of the queue or `nil` when empty
116
+
117
+ # @!method pop
118
+ # @!macro [new] priority_queue_method_pop
119
+ #
120
+ # Retrieves and removes the head of this queue, or returns `nil` if this
121
+ # queue is empty.
122
+ #
123
+ # @return [Object] the head of the queue or `nil` when empty
124
+
125
+ # @!method push(item)
126
+ # @!macro [new] priority_queue_method_push
127
+ #
128
+ # Inserts the specified element into this priority queue.
129
+ #
130
+ # @param [Object] item the item to insert onto the queue
131
+
132
+ # @!method self.from_list(list, opts = {})
133
+ # @!macro [new] priority_queue_method_from_list
134
+ #
135
+ # Create a new priority queue from the given list.
136
+ #
137
+ # @param [Enumerable] list the list to build the queue from
138
+ # @param [Hash] opts the options for creating the queue
139
+ #
140
+ # @return [NonConcurrentPriorityQueue] the newly created and populated queue
141
+ end
142
+ end
143
+ end
@@ -0,0 +1,150 @@
1
+ module Concurrent
2
+ module Collection
3
+
4
+ # @!macro priority_queue
5
+ #
6
+ # @!visibility private
7
+ # @!macro internal_implementation_note
8
+ class RubyNonConcurrentPriorityQueue
9
+
10
+ # @!macro priority_queue_method_initialize
11
+ def initialize(opts = {})
12
+ order = opts.fetch(:order, :max)
13
+ @comparator = [:min, :low].include?(order) ? -1 : 1
14
+ clear
15
+ end
16
+
17
+ # @!macro priority_queue_method_clear
18
+ def clear
19
+ @queue = [nil]
20
+ @length = 0
21
+ true
22
+ end
23
+
24
+ # @!macro priority_queue_method_delete
25
+ def delete(item)
26
+ return false if empty?
27
+ original_length = @length
28
+ k = 1
29
+ while k <= @length
30
+ if @queue[k] == item
31
+ swap(k, @length)
32
+ @length -= 1
33
+ sink(k)
34
+ @queue.pop
35
+ else
36
+ k += 1
37
+ end
38
+ end
39
+ @length != original_length
40
+ end
41
+
42
+ # @!macro priority_queue_method_empty
43
+ def empty?
44
+ size == 0
45
+ end
46
+
47
+ # @!macro priority_queue_method_include
48
+ def include?(item)
49
+ @queue.include?(item)
50
+ end
51
+ alias_method :has_priority?, :include?
52
+
53
+ # @!macro priority_queue_method_length
54
+ def length
55
+ @length
56
+ end
57
+ alias_method :size, :length
58
+
59
+ # @!macro priority_queue_method_peek
60
+ def peek
61
+ empty? ? nil : @queue[1]
62
+ end
63
+
64
+ # @!macro priority_queue_method_pop
65
+ def pop
66
+ return nil if empty?
67
+ max = @queue[1]
68
+ swap(1, @length)
69
+ @length -= 1
70
+ sink(1)
71
+ @queue.pop
72
+ max
73
+ end
74
+ alias_method :deq, :pop
75
+ alias_method :shift, :pop
76
+
77
+ # @!macro priority_queue_method_push
78
+ def push(item)
79
+ raise ArgumentError.new('cannot enqueue nil') if item.nil?
80
+ @length += 1
81
+ @queue << item
82
+ swim(@length)
83
+ true
84
+ end
85
+ alias_method :<<, :push
86
+ alias_method :enq, :push
87
+
88
+ # @!macro priority_queue_method_from_list
89
+ def self.from_list(list, opts = {})
90
+ queue = new(opts)
91
+ list.each{|item| queue << item }
92
+ queue
93
+ end
94
+
95
+ private
96
+
97
+ # Exchange the values at the given indexes within the internal array.
98
+ #
99
+ # @param [Integer] x the first index to swap
100
+ # @param [Integer] y the second index to swap
101
+ #
102
+ # @!visibility private
103
+ def swap(x, y)
104
+ temp = @queue[x]
105
+ @queue[x] = @queue[y]
106
+ @queue[y] = temp
107
+ end
108
+
109
+ # Are the items at the given indexes ordered based on the priority
110
+ # order specified at construction?
111
+ #
112
+ # @param [Integer] x the first index from which to retrieve a comparable value
113
+ # @param [Integer] y the second index from which to retrieve a comparable value
114
+ #
115
+ # @return [Boolean] true if the two elements are in the correct priority order
116
+ # else false
117
+ #
118
+ # @!visibility private
119
+ def ordered?(x, y)
120
+ (@queue[x] <=> @queue[y]) == @comparator
121
+ end
122
+
123
+ # Percolate down to maintain heap invariant.
124
+ #
125
+ # @param [Integer] k the index at which to start the percolation
126
+ #
127
+ # @!visibility private
128
+ def sink(k)
129
+ while (j = (2 * k)) <= @length do
130
+ j += 1 if j < @length && ! ordered?(j, j+1)
131
+ break if ordered?(k, j)
132
+ swap(k, j)
133
+ k = j
134
+ end
135
+ end
136
+
137
+ # Percolate up to maintain heap invariant.
138
+ #
139
+ # @param [Integer] k the index at which to start the percolation
140
+ #
141
+ # @!visibility private
142
+ def swim(k)
143
+ while k > 1 && ! ordered?(k/2, k) do
144
+ swap(k, k/2)
145
+ k = k/2
146
+ end
147
+ end
148
+ end
149
+ end
150
+ end