philiprehberger-queue_stack 0.6.0 → 0.7.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 +4 -4
- data/CHANGELOG.md +6 -0
- data/README.md +21 -0
- data/lib/philiprehberger/queue_stack/queue.rb +41 -0
- data/lib/philiprehberger/queue_stack/stack.rb +40 -0
- data/lib/philiprehberger/queue_stack/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: dbcea69e9c62dd59232e450824070497d480a78224b1f04894664832e1e5c019
|
|
4
|
+
data.tar.gz: b9c91c0ff26af13c51ce30667c5eee0ad0bedce13c807164ddcd273e147d2513
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 8db38faf1a4c7090ee405fededf09f3f939fd11217d46d0220641ff12b3ef286ca915c845b98847e3c22e7f4e0a4ab55d5c71a14d18db9af7b99859e24b454ff
|
|
7
|
+
data.tar.gz: 748285864c78717094e6f34a8c0cf9b4fc2e9c7bde05c17d14b8bd60821790bca8687b9076e2f4d24b9f5bb3cab3a23c131e1dd87cd64f7a4b6da1b30985df38
|
data/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [0.7.0] - 2026-05-29
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
- `Queue#enqueue_all(items)` and `Stack#push_all(items)` — enqueue/push an array of items under a single mutex acquisition; each item respects capacity and `ClosedError` semantics
|
|
14
|
+
- `Queue#dequeue_batch(max)` and `Stack#pop_batch(max)` — remove and return up to `max` items in one synchronized step; non-blocking; signals waiting producers
|
|
15
|
+
|
|
10
16
|
## [0.6.0] - 2026-04-27
|
|
11
17
|
|
|
12
18
|
### Added
|
data/README.md
CHANGED
|
@@ -4,6 +4,8 @@
|
|
|
4
4
|
[](https://rubygems.org/gems/philiprehberger-queue_stack)
|
|
5
5
|
[](https://github.com/philiprehberger/rb-queue-stack/commits/main)
|
|
6
6
|
|
|
7
|
+

|
|
8
|
+
|
|
7
9
|
Thread-safe Queue and Stack with capacity limits and blocking operations
|
|
8
10
|
|
|
9
11
|
## Requirements
|
|
@@ -175,6 +177,21 @@ q.remaining_capacity # => 50
|
|
|
175
177
|
batch_size = [items.length, q.remaining_capacity].min
|
|
176
178
|
```
|
|
177
179
|
|
|
180
|
+
### Batch Insertion and Draining
|
|
181
|
+
|
|
182
|
+
`enqueue_all` / `push_all` insert an array of items under a single mutex acquisition. `dequeue_batch` / `pop_batch` remove up to `max` items at once and signal waiting producers. All four respect capacity and `ClosedError` semantics.
|
|
183
|
+
|
|
184
|
+
```ruby
|
|
185
|
+
q = Philiprehberger::QueueStack::Queue.new
|
|
186
|
+
q.enqueue_all(%w[a b c d])
|
|
187
|
+
q.dequeue_batch(2) # => ["a", "b"]
|
|
188
|
+
q.dequeue_batch(99) # => ["c", "d"] (clamped to available)
|
|
189
|
+
|
|
190
|
+
s = Philiprehberger::QueueStack::Stack.new
|
|
191
|
+
s.push_all(%w[a b c])
|
|
192
|
+
s.pop_batch(2) # => ["c", "b"] (LIFO: top first)
|
|
193
|
+
```
|
|
194
|
+
|
|
178
195
|
## API
|
|
179
196
|
|
|
180
197
|
### `Queue`
|
|
@@ -183,8 +200,10 @@ batch_size = [items.length, q.remaining_capacity].min
|
|
|
183
200
|
|--------|-------------|
|
|
184
201
|
| `.new(capacity:)` | Create a queue with optional capacity limit |
|
|
185
202
|
| `#enqueue(item)` | Add item to back (blocks if full) |
|
|
203
|
+
| `#enqueue_all(items)` | Enqueue an array of items in FIFO order (blocks per-element if full) |
|
|
186
204
|
| `#try_enqueue(item, timeout: nil)` | Non-blocking enqueue, returns true/false (waits up to timeout if given) |
|
|
187
205
|
| `#dequeue` | Remove and return front item (blocks if empty) |
|
|
206
|
+
| `#dequeue_batch(max)` | Remove and return up to `max` items in FIFO order (non-blocking) |
|
|
188
207
|
| `#dequeue_if { \|item\| ... }` | Remove and return the front item only if the block is truthy (non-blocking) |
|
|
189
208
|
| `#try_dequeue(timeout:)` | Dequeue with timeout, returns nil on timeout |
|
|
190
209
|
| `#clear` | Remove all items without returning them |
|
|
@@ -207,8 +226,10 @@ batch_size = [items.length, q.remaining_capacity].min
|
|
|
207
226
|
|--------|-------------|
|
|
208
227
|
| `.new(capacity:)` | Create a stack with optional capacity limit |
|
|
209
228
|
| `#push(item)` | Push item on top (blocks if full) |
|
|
229
|
+
| `#push_all(items)` | Push an array of items in order; last becomes the top (blocks per-element if full) |
|
|
210
230
|
| `#try_push(item, timeout: nil)` | Non-blocking push, returns true/false (waits up to timeout if given) |
|
|
211
231
|
| `#pop` | Remove and return top item (blocks if empty) |
|
|
232
|
+
| `#pop_batch(max)` | Pop up to `max` items, top first (non-blocking) |
|
|
212
233
|
| `#pop_if { \|item\| ... }` | Remove and return the top item only if the block is truthy (non-blocking) |
|
|
213
234
|
| `#try_pop(timeout:)` | Pop with timeout, returns nil on timeout |
|
|
214
235
|
| `#clear` | Remove all items without returning them |
|
|
@@ -246,6 +246,47 @@ module Philiprehberger
|
|
|
246
246
|
[@capacity - @items.length, 0].max
|
|
247
247
|
end
|
|
248
248
|
end
|
|
249
|
+
|
|
250
|
+
# Enqueue many items in FIFO order. Each item is enqueued under the
|
|
251
|
+
# same Mutex acquisition; the call blocks while waiting for capacity
|
|
252
|
+
# exactly as +enqueue+ would for the individual elements that cannot
|
|
253
|
+
# fit immediately.
|
|
254
|
+
#
|
|
255
|
+
# @param items [Array] the items to enqueue, in order
|
|
256
|
+
# @return [void]
|
|
257
|
+
# @raise [ClosedError] if the queue has been closed
|
|
258
|
+
def enqueue_all(items)
|
|
259
|
+
@mutex.synchronize do
|
|
260
|
+
raise ClosedError, 'cannot enqueue on a closed queue' if @closed
|
|
261
|
+
|
|
262
|
+
items.each do |item|
|
|
263
|
+
@not_full.wait(@mutex) while @capacity && @items.length >= @capacity
|
|
264
|
+
raise ClosedError, 'cannot enqueue on a closed queue' if @closed
|
|
265
|
+
|
|
266
|
+
@items.push(item)
|
|
267
|
+
@not_empty.signal
|
|
268
|
+
end
|
|
269
|
+
end
|
|
270
|
+
end
|
|
271
|
+
|
|
272
|
+
# Remove and return up to +max+ items from the front of the queue.
|
|
273
|
+
# Non-blocking: returns an empty array if the queue is empty.
|
|
274
|
+
#
|
|
275
|
+
# @param max [Integer] maximum number of items to remove (must be a non-negative Integer)
|
|
276
|
+
# @return [Array] up to +max+ items in FIFO order
|
|
277
|
+
# @raise [ArgumentError] if +max+ is not a non-negative Integer
|
|
278
|
+
def dequeue_batch(max)
|
|
279
|
+
raise ArgumentError, 'max must be a non-negative Integer' unless max.is_a?(Integer) && max >= 0
|
|
280
|
+
|
|
281
|
+
@mutex.synchronize do
|
|
282
|
+
count = [max, @items.length].min
|
|
283
|
+
next [] if count.zero?
|
|
284
|
+
|
|
285
|
+
batch = @items.shift(count)
|
|
286
|
+
@not_full.broadcast
|
|
287
|
+
batch
|
|
288
|
+
end
|
|
289
|
+
end
|
|
249
290
|
end
|
|
250
291
|
end
|
|
251
292
|
end
|
|
@@ -234,6 +234,46 @@ module Philiprehberger
|
|
|
234
234
|
[@capacity - @items.length, 0].max
|
|
235
235
|
end
|
|
236
236
|
end
|
|
237
|
+
|
|
238
|
+
# Push many items onto the stack in order. The last element of +items+
|
|
239
|
+
# ends up on top. Each push respects capacity exactly as +push+ would.
|
|
240
|
+
#
|
|
241
|
+
# @param items [Array] the items to push, in order
|
|
242
|
+
# @return [void]
|
|
243
|
+
# @raise [ClosedError] if the stack has been closed
|
|
244
|
+
def push_all(items)
|
|
245
|
+
@mutex.synchronize do
|
|
246
|
+
raise ClosedError, 'cannot push on a closed stack' if @closed
|
|
247
|
+
|
|
248
|
+
items.each do |item|
|
|
249
|
+
@not_full.wait(@mutex) while @capacity && @items.length >= @capacity
|
|
250
|
+
raise ClosedError, 'cannot push on a closed stack' if @closed
|
|
251
|
+
|
|
252
|
+
@items.push(item)
|
|
253
|
+
@not_empty.signal
|
|
254
|
+
end
|
|
255
|
+
end
|
|
256
|
+
end
|
|
257
|
+
|
|
258
|
+
# Pop up to +max+ items from the top of the stack in LIFO order
|
|
259
|
+
# (top first). Non-blocking: returns an empty array if the stack is
|
|
260
|
+
# empty.
|
|
261
|
+
#
|
|
262
|
+
# @param max [Integer] maximum number of items to pop (must be a non-negative Integer)
|
|
263
|
+
# @return [Array] up to +max+ items, top first
|
|
264
|
+
# @raise [ArgumentError] if +max+ is not a non-negative Integer
|
|
265
|
+
def pop_batch(max)
|
|
266
|
+
raise ArgumentError, 'max must be a non-negative Integer' unless max.is_a?(Integer) && max >= 0
|
|
267
|
+
|
|
268
|
+
@mutex.synchronize do
|
|
269
|
+
count = [max, @items.length].min
|
|
270
|
+
next [] if count.zero?
|
|
271
|
+
|
|
272
|
+
batch = Array.new(count) { @items.pop }
|
|
273
|
+
@not_full.broadcast
|
|
274
|
+
batch
|
|
275
|
+
end
|
|
276
|
+
end
|
|
237
277
|
end
|
|
238
278
|
end
|
|
239
279
|
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
|
+
version: 0.7.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-
|
|
11
|
+
date: 2026-05-30 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
|