philiprehberger-queue_stack 0.1.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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: bb3c47dcfc192e615cba4fd45499c4795e9e75709dc5c2e3f49558e24f66079f
4
+ data.tar.gz: 47622c2ace206565ca68368c15c8b8145a825138cae4125b8fe65781938a36b2
5
+ SHA512:
6
+ metadata.gz: a022329cdb118ca730b1ff1587bd3347cc5c42a5531f946e28a4cd660cce234ab38b0436afa3cdcb8d956afd571d97f7aeaf4db7465cad4df0bac33a90df5e54
7
+ data.tar.gz: 0b8843ed669a90e5e3f906fe64e5df242298d6a8d2e33a8206e2830dc59da164a112af8b2c1c0fb072b0c7c38a945777e826729aac2c4ef79ffbc9600494f02d
data/CHANGELOG.md ADDED
@@ -0,0 +1,20 @@
1
+ # Changelog
2
+
3
+ All notable changes to this gem will be documented in this file.
4
+
5
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
+ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
+
8
+ ## [Unreleased]
9
+
10
+ ## [0.1.0] - 2026-03-22
11
+
12
+ ### Added
13
+ - Initial release
14
+ - Thread-safe FIFO Queue with enqueue, dequeue, peek, and size
15
+ - Thread-safe LIFO Stack with push, pop, peek, and size
16
+ - Configurable capacity limits for both Queue and Stack
17
+ - Blocking operations that wait when empty or at capacity
18
+ - Timeout-based try_dequeue and try_pop operations
19
+ - Empty and full status checks
20
+ - Mutex and ConditionVariable for thread-safe access
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 philiprehberger
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,117 @@
1
+ # philiprehberger-queue_stack
2
+
3
+ [![Tests](https://github.com/philiprehberger/rb-queue-stack/actions/workflows/ci.yml/badge.svg)](https://github.com/philiprehberger/rb-queue-stack/actions/workflows/ci.yml)
4
+ [![Gem Version](https://badge.fury.io/rb/philiprehberger-queue_stack.svg)](https://rubygems.org/gems/philiprehberger-queue_stack)
5
+ [![License](https://img.shields.io/github/license/philiprehberger/rb-queue-stack)](LICENSE)
6
+
7
+ Thread-safe Queue and Stack with capacity limits and blocking operations
8
+
9
+ ## Requirements
10
+
11
+ - Ruby >= 3.1
12
+
13
+ ## Installation
14
+
15
+ Add to your Gemfile:
16
+
17
+ ```ruby
18
+ gem 'philiprehberger-queue_stack'
19
+ ```
20
+
21
+ Or install directly:
22
+
23
+ ```bash
24
+ gem install philiprehberger-queue_stack
25
+ ```
26
+
27
+ ## Usage
28
+
29
+ ```ruby
30
+ require 'philiprehberger/queue_stack'
31
+
32
+ q = Philiprehberger::QueueStack::Queue.new(capacity: 100)
33
+ q.enqueue('task')
34
+ item = q.dequeue # => 'task'
35
+ ```
36
+
37
+ ### Queue (FIFO)
38
+
39
+ ```ruby
40
+ q = Philiprehberger::QueueStack::Queue.new(capacity: 10)
41
+ q.enqueue('first')
42
+ q.enqueue('second')
43
+ q.dequeue # => 'first'
44
+ q.peek # => 'second'
45
+ q.size # => 1
46
+ ```
47
+
48
+ ### Stack (LIFO)
49
+
50
+ ```ruby
51
+ s = Philiprehberger::QueueStack::Stack.new(capacity: 10)
52
+ s.push('first')
53
+ s.push('second')
54
+ s.pop # => 'second'
55
+ s.peek # => 'first'
56
+ s.size # => 1
57
+ ```
58
+
59
+ ### Blocking with Timeout
60
+
61
+ ```ruby
62
+ q = Philiprehberger::QueueStack::Queue.new
63
+ item = q.try_dequeue(timeout: 5) # waits up to 5 seconds
64
+
65
+ s = Philiprehberger::QueueStack::Stack.new
66
+ item = s.try_pop(timeout: 5) # waits up to 5 seconds
67
+ ```
68
+
69
+ ### Capacity Limits
70
+
71
+ ```ruby
72
+ q = Philiprehberger::QueueStack::Queue.new(capacity: 3)
73
+ q.full? # => false
74
+ 3.times { |i| q.enqueue(i) }
75
+ q.full? # => true
76
+ # enqueue blocks until space is available
77
+ ```
78
+
79
+ ## API
80
+
81
+ ### `Queue`
82
+
83
+ | Method | Description |
84
+ |--------|-------------|
85
+ | `.new(capacity:)` | Create a queue with optional capacity limit |
86
+ | `#enqueue(item)` | Add item to back (blocks if full) |
87
+ | `#dequeue` | Remove and return front item (blocks if empty) |
88
+ | `#try_dequeue(timeout:)` | Dequeue with timeout, returns nil on timeout |
89
+ | `#peek` | View front item without removing |
90
+ | `#size` | Number of items |
91
+ | `#empty?` | Whether the queue is empty |
92
+ | `#full?` | Whether the queue is at capacity |
93
+
94
+ ### `Stack`
95
+
96
+ | Method | Description |
97
+ |--------|-------------|
98
+ | `.new(capacity:)` | Create a stack with optional capacity limit |
99
+ | `#push(item)` | Push item on top (blocks if full) |
100
+ | `#pop` | Remove and return top item (blocks if empty) |
101
+ | `#try_pop(timeout:)` | Pop with timeout, returns nil on timeout |
102
+ | `#peek` | View top item without removing |
103
+ | `#size` | Number of items |
104
+ | `#empty?` | Whether the stack is empty |
105
+ | `#full?` | Whether the stack is at capacity |
106
+
107
+ ## Development
108
+
109
+ ```bash
110
+ bundle install
111
+ bundle exec rspec # Run tests
112
+ bundle exec rubocop # Check code style
113
+ ```
114
+
115
+ ## License
116
+
117
+ MIT
@@ -0,0 +1,95 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Philiprehberger
4
+ module QueueStack
5
+ # Thread-safe FIFO queue with optional capacity limit and blocking operations.
6
+ #
7
+ # @example
8
+ # q = Queue.new(capacity: 10)
9
+ # q.enqueue('item')
10
+ # q.dequeue # => 'item'
11
+ class Queue
12
+ # Create a new queue.
13
+ #
14
+ # @param capacity [Integer, nil] maximum number of items (nil for unlimited)
15
+ def initialize(capacity: nil)
16
+ @items = []
17
+ @capacity = capacity
18
+ @mutex = Mutex.new
19
+ @not_empty = ConditionVariable.new
20
+ @not_full = ConditionVariable.new
21
+ end
22
+
23
+ # Add an item to the back of the queue. Blocks if at capacity.
24
+ #
25
+ # @param item [Object] the item to enqueue
26
+ # @return [void]
27
+ def enqueue(item)
28
+ @mutex.synchronize do
29
+ @not_full.wait(@mutex) while @capacity && @items.length >= @capacity
30
+ @items.push(item)
31
+ @not_empty.signal
32
+ end
33
+ end
34
+
35
+ # Remove and return the front item. Blocks if empty.
36
+ #
37
+ # @return [Object] the dequeued item
38
+ def dequeue
39
+ @mutex.synchronize do
40
+ @not_empty.wait(@mutex) while @items.empty?
41
+ item = @items.shift
42
+ @not_full.signal
43
+ item
44
+ end
45
+ end
46
+
47
+ # Try to dequeue an item with a timeout.
48
+ #
49
+ # @param timeout [Numeric] seconds to wait
50
+ # @return [Object, nil] the dequeued item or nil on timeout
51
+ def try_dequeue(timeout:)
52
+ deadline = Time.now + timeout
53
+ @mutex.synchronize do
54
+ while @items.empty?
55
+ remaining = deadline - Time.now
56
+ return nil if remaining <= 0
57
+
58
+ @not_empty.wait(@mutex, remaining)
59
+ end
60
+ item = @items.shift
61
+ @not_full.signal
62
+ item
63
+ end
64
+ end
65
+
66
+ # Peek at the front item without removing it.
67
+ #
68
+ # @return [Object, nil] the front item or nil if empty
69
+ def peek
70
+ @mutex.synchronize { @items.first }
71
+ end
72
+
73
+ # Return the number of items in the queue.
74
+ #
75
+ # @return [Integer]
76
+ def size
77
+ @mutex.synchronize { @items.length }
78
+ end
79
+
80
+ # Whether the queue is empty.
81
+ #
82
+ # @return [Boolean]
83
+ def empty?
84
+ @mutex.synchronize { @items.empty? }
85
+ end
86
+
87
+ # Whether the queue is at capacity.
88
+ #
89
+ # @return [Boolean]
90
+ def full?
91
+ @mutex.synchronize { @capacity ? @items.length >= @capacity : false }
92
+ end
93
+ end
94
+ end
95
+ end
@@ -0,0 +1,95 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Philiprehberger
4
+ module QueueStack
5
+ # Thread-safe LIFO stack with optional capacity limit and blocking operations.
6
+ #
7
+ # @example
8
+ # s = Stack.new(capacity: 10)
9
+ # s.push('item')
10
+ # s.pop # => 'item'
11
+ class Stack
12
+ # Create a new stack.
13
+ #
14
+ # @param capacity [Integer, nil] maximum number of items (nil for unlimited)
15
+ def initialize(capacity: nil)
16
+ @items = []
17
+ @capacity = capacity
18
+ @mutex = Mutex.new
19
+ @not_empty = ConditionVariable.new
20
+ @not_full = ConditionVariable.new
21
+ end
22
+
23
+ # Push an item onto the top of the stack. Blocks if at capacity.
24
+ #
25
+ # @param item [Object] the item to push
26
+ # @return [void]
27
+ def push(item)
28
+ @mutex.synchronize do
29
+ @not_full.wait(@mutex) while @capacity && @items.length >= @capacity
30
+ @items.push(item)
31
+ @not_empty.signal
32
+ end
33
+ end
34
+
35
+ # Pop and return the top item. Blocks if empty.
36
+ #
37
+ # @return [Object] the popped item
38
+ def pop
39
+ @mutex.synchronize do
40
+ @not_empty.wait(@mutex) while @items.empty?
41
+ item = @items.pop
42
+ @not_full.signal
43
+ item
44
+ end
45
+ end
46
+
47
+ # Try to pop an item with a timeout.
48
+ #
49
+ # @param timeout [Numeric] seconds to wait
50
+ # @return [Object, nil] the popped item or nil on timeout
51
+ def try_pop(timeout:)
52
+ deadline = Time.now + timeout
53
+ @mutex.synchronize do
54
+ while @items.empty?
55
+ remaining = deadline - Time.now
56
+ return nil if remaining <= 0
57
+
58
+ @not_empty.wait(@mutex, remaining)
59
+ end
60
+ item = @items.pop
61
+ @not_full.signal
62
+ item
63
+ end
64
+ end
65
+
66
+ # Peek at the top item without removing it.
67
+ #
68
+ # @return [Object, nil] the top item or nil if empty
69
+ def peek
70
+ @mutex.synchronize { @items.last }
71
+ end
72
+
73
+ # Return the number of items in the stack.
74
+ #
75
+ # @return [Integer]
76
+ def size
77
+ @mutex.synchronize { @items.length }
78
+ end
79
+
80
+ # Whether the stack is empty.
81
+ #
82
+ # @return [Boolean]
83
+ def empty?
84
+ @mutex.synchronize { @items.empty? }
85
+ end
86
+
87
+ # Whether the stack is at capacity.
88
+ #
89
+ # @return [Boolean]
90
+ def full?
91
+ @mutex.synchronize { @capacity ? @items.length >= @capacity : false }
92
+ end
93
+ end
94
+ end
95
+ end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Philiprehberger
4
+ module QueueStack
5
+ VERSION = '0.1.0'
6
+ end
7
+ end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'queue_stack/version'
4
+ require_relative 'queue_stack/queue'
5
+ require_relative 'queue_stack/stack'
6
+
7
+ module Philiprehberger
8
+ module QueueStack
9
+ class Error < StandardError; end
10
+ end
11
+ end
metadata ADDED
@@ -0,0 +1,57 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: philiprehberger-queue_stack
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Philip Rehberger
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2026-03-22 00:00:00.000000000 Z
12
+ dependencies: []
13
+ description: Thread-safe queue and stack data structures with configurable capacity
14
+ limits, blocking enqueue/dequeue with timeouts, and peek operations. Uses Mutex
15
+ and ConditionVariable for safe concurrent access.
16
+ email:
17
+ - me@philiprehberger.com
18
+ executables: []
19
+ extensions: []
20
+ extra_rdoc_files: []
21
+ files:
22
+ - CHANGELOG.md
23
+ - LICENSE
24
+ - README.md
25
+ - lib/philiprehberger/queue_stack.rb
26
+ - lib/philiprehberger/queue_stack/queue.rb
27
+ - lib/philiprehberger/queue_stack/stack.rb
28
+ - lib/philiprehberger/queue_stack/version.rb
29
+ homepage: https://github.com/philiprehberger/rb-queue-stack
30
+ licenses:
31
+ - MIT
32
+ metadata:
33
+ homepage_uri: https://github.com/philiprehberger/rb-queue-stack
34
+ source_code_uri: https://github.com/philiprehberger/rb-queue-stack
35
+ changelog_uri: https://github.com/philiprehberger/rb-queue-stack/blob/main/CHANGELOG.md
36
+ bug_tracker_uri: https://github.com/philiprehberger/rb-queue-stack/issues
37
+ rubygems_mfa_required: 'true'
38
+ post_install_message:
39
+ rdoc_options: []
40
+ require_paths:
41
+ - lib
42
+ required_ruby_version: !ruby/object:Gem::Requirement
43
+ requirements:
44
+ - - ">="
45
+ - !ruby/object:Gem::Version
46
+ version: 3.1.0
47
+ required_rubygems_version: !ruby/object:Gem::Requirement
48
+ requirements:
49
+ - - ">="
50
+ - !ruby/object:Gem::Version
51
+ version: '0'
52
+ requirements: []
53
+ rubygems_version: 3.5.22
54
+ signing_key:
55
+ specification_version: 4
56
+ summary: Thread-safe Queue and Stack with capacity limits and blocking operations
57
+ test_files: []