philiprehberger-queue_stack 0.4.0 → 0.6.0

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 8f720c2ee97526d57826cb37fba4be96e6e1143879b7627a2792cef97ffaa1dc
4
- data.tar.gz: 311fdae1a3eb9f31d27f4ef77006eae1f224050418ac97721540d761ac081ac0
3
+ metadata.gz: aeb1d7901c33280074ac91777f24b5dcc3704f9d3144dac214a4e8baba9b8bf0
4
+ data.tar.gz: 21a0f6c879d8d1f95270b4d34497e5905064ee96738b30ae9a7bb870c6e3d820
5
5
  SHA512:
6
- metadata.gz: fd4c5bc553fde4d2278b2efa422ed0c4c67aaf63d9c5bc049bce395066ab544533bf2b11696a564769cbd6dbdd900a4c802a12abec032d888d17c0d0d5d0dc36
7
- data.tar.gz: aa1cc6ea3d889cde7c372943df2bb9b5c46d0f87f3e628659e01ebbbf3697a8ce548f41c36508a3f82af14818ca0bd852da74aa577e13abf29899f1b60e6a162
6
+ metadata.gz: 28ba1990bc0e94d4c79b414d1a62a69d022f4091d76bd3bdc092e6c377cc0fd7fd79d1a265126aed15bf3a705fa34ac05c05d084990ea867022e03220f23ed7d
7
+ data.tar.gz: d6fc9a7f47a18010cf5b1f7e096861cca61bf565f604c5687a10165cc2074196457e918b3564fe8f80a233ca2e9ad4584929af11b465db4481b3e35f40e0a6ca
data/CHANGELOG.md CHANGED
@@ -7,6 +7,17 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [0.6.0] - 2026-04-27
11
+
12
+ ### Added
13
+ - `Queue#capacity`, `Queue#remaining_capacity`, `Stack#capacity`, `Stack#remaining_capacity` — capacity introspection. `capacity` returns the configured limit (or `nil` for unlimited); `remaining_capacity` returns the number of additional items that can still be accepted (or `nil` for unlimited, `0` when full). Mutex-synchronized for consistent reads.
14
+
15
+ ## [0.5.0] - 2026-04-16
16
+
17
+ ### Added
18
+ - `Queue#dequeue_if { |item| ... }` conditionally removes and returns the front item only when the block returns truthy; returns `nil` when empty or the block returns false (non-blocking)
19
+ - `Stack#pop_if { |item| ... }` conditionally removes and returns the top item only when the block returns truthy; returns `nil` when empty or the block returns false (non-blocking)
20
+
10
21
  ## [0.4.0] - 2026-04-15
11
22
 
12
23
  ### Added
data/README.md CHANGED
@@ -70,6 +70,25 @@ s = Philiprehberger::QueueStack::Stack.new
70
70
  item = s.try_pop(timeout: 5) # waits up to 5 seconds
71
71
  ```
72
72
 
73
+ ### Conditional Removal
74
+
75
+ Remove the front/top item only when a predicate holds. Non-blocking; returns `nil` if the collection is empty or the block returns false (the item stays put).
76
+
77
+ ```ruby
78
+ q = Philiprehberger::QueueStack::Queue.new
79
+ q.enqueue({ priority: 10 })
80
+ q.enqueue({ priority: 2 })
81
+
82
+ # Only take high-priority work
83
+ q.dequeue_if { |job| job[:priority] >= 5 } # => { priority: 10 }
84
+ q.dequeue_if { |job| job[:priority] >= 5 } # => nil (head priority 2 left intact)
85
+
86
+ s = Philiprehberger::QueueStack::Stack.new
87
+ s.push(:ready)
88
+ s.pop_if { |item| item == :ready } # => :ready
89
+ s.pop_if { |item| item == :ready } # => nil (empty)
90
+ ```
91
+
73
92
  ### Drain
74
93
 
75
94
  ```ruby
@@ -140,6 +159,22 @@ q.full? # => true
140
159
  # enqueue blocks until space is available
141
160
  ```
142
161
 
162
+ ### Capacity
163
+
164
+ Read the configured capacity and the number of additional items that can be
165
+ accepted. Both return `nil` for unbounded containers; `remaining_capacity`
166
+ returns `0` when full. Useful for sizing batches or backpressure decisions.
167
+
168
+ ```ruby
169
+ q = Philiprehberger::QueueStack::Queue.new(capacity: 100)
170
+ q.capacity # => 100
171
+ q.remaining_capacity # => 100
172
+ 50.times { |i| q.enqueue(i) }
173
+ q.remaining_capacity # => 50
174
+
175
+ batch_size = [items.length, q.remaining_capacity].min
176
+ ```
177
+
143
178
  ## API
144
179
 
145
180
  ### `Queue`
@@ -150,6 +185,7 @@ q.full? # => true
150
185
  | `#enqueue(item)` | Add item to back (blocks if full) |
151
186
  | `#try_enqueue(item, timeout: nil)` | Non-blocking enqueue, returns true/false (waits up to timeout if given) |
152
187
  | `#dequeue` | Remove and return front item (blocks if empty) |
188
+ | `#dequeue_if { \|item\| ... }` | Remove and return the front item only if the block is truthy (non-blocking) |
153
189
  | `#try_dequeue(timeout:)` | Dequeue with timeout, returns nil on timeout |
154
190
  | `#clear` | Remove all items without returning them |
155
191
  | `#peek` | View front item without removing |
@@ -162,6 +198,8 @@ q.full? # => true
162
198
  | `#size` | Number of items |
163
199
  | `#empty?` | Whether the queue is empty |
164
200
  | `#full?` | Whether the queue is at capacity |
201
+ | `#capacity` | Configured capacity, or `nil` for an unlimited queue |
202
+ | `#remaining_capacity` | Items the queue can still accept (`nil` for unlimited, `0` when full) |
165
203
 
166
204
  ### `Stack`
167
205
 
@@ -171,6 +209,7 @@ q.full? # => true
171
209
  | `#push(item)` | Push item on top (blocks if full) |
172
210
  | `#try_push(item, timeout: nil)` | Non-blocking push, returns true/false (waits up to timeout if given) |
173
211
  | `#pop` | Remove and return top item (blocks if empty) |
212
+ | `#pop_if { \|item\| ... }` | Remove and return the top item only if the block is truthy (non-blocking) |
174
213
  | `#try_pop(timeout:)` | Pop with timeout, returns nil on timeout |
175
214
  | `#clear` | Remove all items without returning them |
176
215
  | `#peek` | View top item without removing |
@@ -182,6 +221,8 @@ q.full? # => true
182
221
  | `#size` | Number of items |
183
222
  | `#empty?` | Whether the stack is empty |
184
223
  | `#full?` | Whether the stack is at capacity |
224
+ | `#capacity` | Configured capacity, or `nil` for an unlimited stack |
225
+ | `#remaining_capacity` | Items the stack can still accept (`nil` for unlimited, `0` when full) |
185
226
 
186
227
  ## Development
187
228
 
@@ -96,6 +96,24 @@ module Philiprehberger
96
96
  end
97
97
  end
98
98
 
99
+ # Conditionally dequeue the front item. The block is called with the item
100
+ # that would be dequeued next. If the block returns truthy, the item is
101
+ # removed and returned. Otherwise the item is left in place and +nil+ is
102
+ # returned. Returns +nil+ immediately if the queue is empty (non-blocking).
103
+ #
104
+ # @yield [item] the front item
105
+ # @return [Object, nil] the removed item, or nil if empty or block returned false
106
+ def dequeue_if
107
+ @mutex.synchronize do
108
+ return nil if @items.empty?
109
+ return nil unless yield(@items.first)
110
+
111
+ item = @items.shift
112
+ @not_full.signal
113
+ item
114
+ end
115
+ end
116
+
99
117
  # Try to dequeue an item with a timeout.
100
118
  #
101
119
  # @param timeout [Numeric] seconds to wait
@@ -207,6 +225,27 @@ module Philiprehberger
207
225
  def full?
208
226
  @mutex.synchronize { @capacity ? @items.length >= @capacity : false }
209
227
  end
228
+
229
+ # The configured capacity, or +nil+ for an unlimited queue.
230
+ #
231
+ # @return [Integer, nil]
232
+ def capacity
233
+ @mutex.synchronize { @capacity }
234
+ end
235
+
236
+ # Number of additional items the queue can accept before it is full.
237
+ #
238
+ # Returns +nil+ for unlimited queues. For bounded queues returns
239
+ # +capacity - size+, clamped to a minimum of 0.
240
+ #
241
+ # @return [Integer, nil]
242
+ def remaining_capacity
243
+ @mutex.synchronize do
244
+ next nil unless @capacity
245
+
246
+ [@capacity - @items.length, 0].max
247
+ end
248
+ end
210
249
  end
211
250
  end
212
251
  end
@@ -96,6 +96,24 @@ module Philiprehberger
96
96
  end
97
97
  end
98
98
 
99
+ # Conditionally pop the top item. The block is called with the item that
100
+ # would be popped next. If the block returns truthy, the item is removed
101
+ # and returned. Otherwise the item is left in place and +nil+ is returned.
102
+ # Returns +nil+ immediately if the stack is empty (non-blocking).
103
+ #
104
+ # @yield [item] the top item
105
+ # @return [Object, nil] the removed item, or nil if empty or block returned false
106
+ def pop_if
107
+ @mutex.synchronize do
108
+ return nil if @items.empty?
109
+ return nil unless yield(@items.last)
110
+
111
+ item = @items.pop
112
+ @not_full.signal
113
+ item
114
+ end
115
+ end
116
+
99
117
  # Try to pop an item with a timeout.
100
118
  #
101
119
  # @param timeout [Numeric] seconds to wait
@@ -195,6 +213,27 @@ module Philiprehberger
195
213
  def full?
196
214
  @mutex.synchronize { @capacity ? @items.length >= @capacity : false }
197
215
  end
216
+
217
+ # The configured capacity, or +nil+ for an unlimited stack.
218
+ #
219
+ # @return [Integer, nil]
220
+ def capacity
221
+ @mutex.synchronize { @capacity }
222
+ end
223
+
224
+ # Number of additional items the stack can accept before it is full.
225
+ #
226
+ # Returns +nil+ for unlimited stacks. For bounded stacks returns
227
+ # +capacity - size+, clamped to a minimum of 0.
228
+ #
229
+ # @return [Integer, nil]
230
+ def remaining_capacity
231
+ @mutex.synchronize do
232
+ next nil unless @capacity
233
+
234
+ [@capacity - @items.length, 0].max
235
+ end
236
+ end
198
237
  end
199
238
  end
200
239
  end
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Philiprehberger
4
4
  module QueueStack
5
- VERSION = '0.4.0'
5
+ VERSION = '0.6.0'
6
6
  end
7
7
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: philiprehberger-queue_stack
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.0
4
+ version: 0.6.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Philip Rehberger
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2026-04-15 00:00:00.000000000 Z
11
+ date: 2026-04-28 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: Thread-safe queue and stack data structures with configurable capacity
14
14
  limits, blocking enqueue/dequeue with timeouts, and peek operations. Uses Mutex