philiprehberger-queue_stack 0.2.0 → 0.4.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 +11 -0
- data/README.md +34 -3
- data/lib/philiprehberger/queue_stack/queue.rb +54 -0
- data/lib/philiprehberger/queue_stack/stack.rb +42 -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: 8f720c2ee97526d57826cb37fba4be96e6e1143879b7627a2792cef97ffaa1dc
|
|
4
|
+
data.tar.gz: 311fdae1a3eb9f31d27f4ef77006eae1f224050418ac97721540d761ac081ac0
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: fd4c5bc553fde4d2278b2efa422ed0c4c67aaf63d9c5bc049bce395066ab544533bf2b11696a564769cbd6dbdd900a4c802a12abec032d888d17c0d0d5d0dc36
|
|
7
|
+
data.tar.gz: aa1cc6ea3d889cde7c372943df2bb9b5c46d0f87f3e628659e01ebbbf3697a8ce548f41c36508a3f82af14818ca0bd852da74aa577e13abf29899f1b60e6a162
|
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.4.0] - 2026-04-15
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
- `Queue#peek_at(index)` returns the item at the given position without removing it, supporting negative indices like `Array#[]` and returning `nil` when out of range
|
|
14
|
+
|
|
15
|
+
## [0.3.0] - 2026-04-09
|
|
16
|
+
|
|
17
|
+
### Added
|
|
18
|
+
- `Queue#try_enqueue(item, timeout: nil)` and `Stack#try_push(item, timeout: nil)` non-blocking insertion variants
|
|
19
|
+
- `Queue#clear` and `Stack#clear` to discard all items and wake blocked producers
|
|
20
|
+
|
|
10
21
|
## [0.2.0] - 2026-04-03
|
|
11
22
|
|
|
12
23
|
### Added
|
data/README.md
CHANGED
|
@@ -40,9 +40,13 @@ item = q.dequeue # => 'task'
|
|
|
40
40
|
q = Philiprehberger::QueueStack::Queue.new(capacity: 10)
|
|
41
41
|
q.enqueue('first')
|
|
42
42
|
q.enqueue('second')
|
|
43
|
-
q.
|
|
44
|
-
q.peek
|
|
45
|
-
q.
|
|
43
|
+
q.enqueue('third')
|
|
44
|
+
q.peek # => 'first'
|
|
45
|
+
q.peek_at(1) # => 'second'
|
|
46
|
+
q.peek_at(-1) # => 'third'
|
|
47
|
+
q.peek_at(99) # => nil (out of range)
|
|
48
|
+
q.dequeue # => 'first'
|
|
49
|
+
q.size # => 2
|
|
46
50
|
```
|
|
47
51
|
|
|
48
52
|
### Stack (LIFO)
|
|
@@ -92,6 +96,28 @@ q.each { |item| puts item } # prints 'a', 'b'
|
|
|
92
96
|
q.to_a # => ['a', 'b'] (queue unchanged)
|
|
93
97
|
```
|
|
94
98
|
|
|
99
|
+
### Non-Blocking Insertion
|
|
100
|
+
|
|
101
|
+
```ruby
|
|
102
|
+
q = Philiprehberger::QueueStack::Queue.new(capacity: 1)
|
|
103
|
+
q.enqueue('a')
|
|
104
|
+
q.try_enqueue('b') # => false (full, no wait)
|
|
105
|
+
q.try_enqueue('b', timeout: 0.5) # => false after waiting up to 0.5s
|
|
106
|
+
|
|
107
|
+
s = Philiprehberger::QueueStack::Stack.new(capacity: 1)
|
|
108
|
+
s.push('a')
|
|
109
|
+
s.try_push('b') # => false (full, no wait)
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
### Clear
|
|
113
|
+
|
|
114
|
+
```ruby
|
|
115
|
+
q = Philiprehberger::QueueStack::Queue.new
|
|
116
|
+
q.enqueue('a'); q.enqueue('b')
|
|
117
|
+
q.clear
|
|
118
|
+
q.empty? # => true
|
|
119
|
+
```
|
|
120
|
+
|
|
95
121
|
### Close / Shutdown
|
|
96
122
|
|
|
97
123
|
```ruby
|
|
@@ -122,9 +148,12 @@ q.full? # => true
|
|
|
122
148
|
|--------|-------------|
|
|
123
149
|
| `.new(capacity:)` | Create a queue with optional capacity limit |
|
|
124
150
|
| `#enqueue(item)` | Add item to back (blocks if full) |
|
|
151
|
+
| `#try_enqueue(item, timeout: nil)` | Non-blocking enqueue, returns true/false (waits up to timeout if given) |
|
|
125
152
|
| `#dequeue` | Remove and return front item (blocks if empty) |
|
|
126
153
|
| `#try_dequeue(timeout:)` | Dequeue with timeout, returns nil on timeout |
|
|
154
|
+
| `#clear` | Remove all items without returning them |
|
|
127
155
|
| `#peek` | View front item without removing |
|
|
156
|
+
| `#peek_at(index)` | View item at the given position (supports negative indices, returns nil if out of range) |
|
|
128
157
|
| `#drain` | Remove and return all items as array (FIFO order) |
|
|
129
158
|
| `#each` | Iterate items without removing (returns Enumerator if no block) |
|
|
130
159
|
| `#to_a` | Snapshot as array (FIFO order) |
|
|
@@ -140,8 +169,10 @@ q.full? # => true
|
|
|
140
169
|
|--------|-------------|
|
|
141
170
|
| `.new(capacity:)` | Create a stack with optional capacity limit |
|
|
142
171
|
| `#push(item)` | Push item on top (blocks if full) |
|
|
172
|
+
| `#try_push(item, timeout: nil)` | Non-blocking push, returns true/false (waits up to timeout if given) |
|
|
143
173
|
| `#pop` | Remove and return top item (blocks if empty) |
|
|
144
174
|
| `#try_pop(timeout:)` | Pop with timeout, returns nil on timeout |
|
|
175
|
+
| `#clear` | Remove all items without returning them |
|
|
145
176
|
| `#peek` | View top item without removing |
|
|
146
177
|
| `#drain` | Remove and return all items as array (LIFO order) |
|
|
147
178
|
| `#each` | Iterate items without removing (returns Enumerator if no block) |
|
|
@@ -54,6 +54,48 @@ module Philiprehberger
|
|
|
54
54
|
end
|
|
55
55
|
end
|
|
56
56
|
|
|
57
|
+
# Try to enqueue an item without blocking indefinitely.
|
|
58
|
+
#
|
|
59
|
+
# With timeout: nil, returns immediately. With a numeric timeout, waits up to
|
|
60
|
+
# that many seconds for space to become available.
|
|
61
|
+
#
|
|
62
|
+
# @param item [Object] the item to enqueue
|
|
63
|
+
# @param timeout [Numeric, nil] seconds to wait, or nil for non-blocking
|
|
64
|
+
# @return [Boolean] true if enqueued, false if full (or timed out)
|
|
65
|
+
# @raise [ClosedError] if the queue has been closed
|
|
66
|
+
def try_enqueue(item, timeout: nil)
|
|
67
|
+
@mutex.synchronize do
|
|
68
|
+
raise ClosedError, 'cannot enqueue on a closed queue' if @closed
|
|
69
|
+
|
|
70
|
+
if @capacity && @items.length >= @capacity
|
|
71
|
+
return false if timeout.nil? || timeout <= 0
|
|
72
|
+
|
|
73
|
+
deadline = Time.now + timeout
|
|
74
|
+
while @items.length >= @capacity
|
|
75
|
+
remaining = deadline - Time.now
|
|
76
|
+
return false if remaining <= 0
|
|
77
|
+
|
|
78
|
+
@not_full.wait(@mutex, remaining)
|
|
79
|
+
raise ClosedError, 'cannot enqueue on a closed queue' if @closed
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
@items.push(item)
|
|
84
|
+
@not_empty.signal
|
|
85
|
+
true
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
# Remove all items without returning them. Signals any blocked producers.
|
|
90
|
+
#
|
|
91
|
+
# @return [void]
|
|
92
|
+
def clear
|
|
93
|
+
@mutex.synchronize do
|
|
94
|
+
@items.clear
|
|
95
|
+
@not_full.broadcast
|
|
96
|
+
end
|
|
97
|
+
end
|
|
98
|
+
|
|
57
99
|
# Try to dequeue an item with a timeout.
|
|
58
100
|
#
|
|
59
101
|
# @param timeout [Numeric] seconds to wait
|
|
@@ -133,6 +175,18 @@ module Philiprehberger
|
|
|
133
175
|
@mutex.synchronize { @items.first }
|
|
134
176
|
end
|
|
135
177
|
|
|
178
|
+
# Peek at the item at the given position without removing it.
|
|
179
|
+
#
|
|
180
|
+
# Indexing follows +Array#[]+ semantics: +0+ is the front of the queue,
|
|
181
|
+
# +size - 1+ is the back, and negative indices count from the back
|
|
182
|
+
# (+-1+ is the last item). Returns +nil+ when the index is out of range.
|
|
183
|
+
#
|
|
184
|
+
# @param index [Integer] position in the queue (supports negative indices)
|
|
185
|
+
# @return [Object, nil] the item at the position or nil if out of range
|
|
186
|
+
def peek_at(index)
|
|
187
|
+
@mutex.synchronize { @items[index] }
|
|
188
|
+
end
|
|
189
|
+
|
|
136
190
|
# Return the number of items in the queue.
|
|
137
191
|
#
|
|
138
192
|
# @return [Integer]
|
|
@@ -54,6 +54,48 @@ module Philiprehberger
|
|
|
54
54
|
end
|
|
55
55
|
end
|
|
56
56
|
|
|
57
|
+
# Try to push an item without blocking indefinitely.
|
|
58
|
+
#
|
|
59
|
+
# With timeout: nil, returns immediately. With a numeric timeout, waits up to
|
|
60
|
+
# that many seconds for space to become available.
|
|
61
|
+
#
|
|
62
|
+
# @param item [Object] the item to push
|
|
63
|
+
# @param timeout [Numeric, nil] seconds to wait, or nil for non-blocking
|
|
64
|
+
# @return [Boolean] true if pushed, false if full (or timed out)
|
|
65
|
+
# @raise [ClosedError] if the stack has been closed
|
|
66
|
+
def try_push(item, timeout: nil)
|
|
67
|
+
@mutex.synchronize do
|
|
68
|
+
raise ClosedError, 'cannot push on a closed stack' if @closed
|
|
69
|
+
|
|
70
|
+
if @capacity && @items.length >= @capacity
|
|
71
|
+
return false if timeout.nil? || timeout <= 0
|
|
72
|
+
|
|
73
|
+
deadline = Time.now + timeout
|
|
74
|
+
while @items.length >= @capacity
|
|
75
|
+
remaining = deadline - Time.now
|
|
76
|
+
return false if remaining <= 0
|
|
77
|
+
|
|
78
|
+
@not_full.wait(@mutex, remaining)
|
|
79
|
+
raise ClosedError, 'cannot push on a closed stack' if @closed
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
@items.push(item)
|
|
84
|
+
@not_empty.signal
|
|
85
|
+
true
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
# Remove all items without returning them. Signals any blocked producers.
|
|
90
|
+
#
|
|
91
|
+
# @return [void]
|
|
92
|
+
def clear
|
|
93
|
+
@mutex.synchronize do
|
|
94
|
+
@items.clear
|
|
95
|
+
@not_full.broadcast
|
|
96
|
+
end
|
|
97
|
+
end
|
|
98
|
+
|
|
57
99
|
# Try to pop an item with a timeout.
|
|
58
100
|
#
|
|
59
101
|
# @param timeout [Numeric] seconds to wait
|
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.4.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-
|
|
11
|
+
date: 2026-04-15 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
|