nblf-queue 0.1.0__cp312-abi3-win_amd64.whl

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.
nblf_queue/__init__.py ADDED
@@ -0,0 +1,3 @@
1
+ from ._nblf_queue_py import Queue, DynamicQueue
2
+
3
+ __all__ = ["Queue", "DynamicQueue"]
@@ -0,0 +1,183 @@
1
+ from typing import Callable, Generic, TypeVar
2
+
3
+ _T = TypeVar("_T")
4
+
5
+ class DynamicQueue(Generic[_T]):
6
+ """
7
+ A dynamically growable, lock-free non-blocking MPMC queue.
8
+
9
+ Core operations detach from the python GIL, to ensure concurrent performance.
10
+ """
11
+
12
+ def __init__(self, size: int) -> None:
13
+ """
14
+ Constructs a new `DynamicQueue` with initial capacity `size`.
15
+ """
16
+ ...
17
+
18
+ def push(self, item: _T) -> _T | None:
19
+ """
20
+ Attempts to push an element into the queue.
21
+
22
+ Returns the item, if the queue was full.
23
+ """
24
+ ...
25
+
26
+ def pop(self) -> _T | None:
27
+ """
28
+ Attempts to pop an item from the queue.
29
+
30
+ Returns `None` if the queue was empty.
31
+ """
32
+ ...
33
+
34
+ def len(self) -> int:
35
+ """
36
+ Returns the current length of the queue.
37
+
38
+ This method should not be used for synchronization.
39
+ """
40
+ ...
41
+
42
+ def capacity(self) -> int:
43
+ """
44
+ Returns the current capacity of the queue.
45
+
46
+ This method should not be used for synchronization.
47
+ """
48
+ ...
49
+
50
+ def is_empty(self) -> bool:
51
+ """
52
+ Indicates whether the queue is currently empty.
53
+
54
+ This method should not be used for synchronization.
55
+ """
56
+ ...
57
+
58
+ def is_full(self) -> bool:
59
+ """
60
+ Indicates whether the queue is currently full.
61
+
62
+ This method should not be used for synchronization.
63
+ """
64
+ ...
65
+
66
+ def force_push(self, item: _T) -> _T | None:
67
+ """
68
+ Pushes an item into the queue.
69
+ This method may take some time under heavy contention.
70
+ This method may pop an arbitrary amount of items from the queue.
71
+
72
+ Returns the last popped item, if the queue was full. All other items are dropped.
73
+ """
74
+ ...
75
+
76
+ def force_push_and_do(self, item: _T, f: Callable[[_T], None]) -> None:
77
+ """
78
+ Pushes an item into the queue.
79
+ This method may take some time under heavy contention.
80
+ This method may pop an arbitrary amount of items from the queue.
81
+ Applies `f` to each popped item.
82
+ """
83
+ ...
84
+
85
+ def grow_by(self, by: int) -> bool:
86
+ """
87
+ Attempts to grow the queue's capacity by `by` items.
88
+
89
+ This method may spuriously fail.
90
+
91
+ Returns `True` if the capacity was successfully grown.
92
+ """
93
+ ...
94
+
95
+ def grow(self) -> bool:
96
+ """
97
+ Attempts to grow the queue's capacity using limited exponential growth.
98
+
99
+ This method may spuriously fail.
100
+
101
+ Returns `True` if the capacity was successfully grown.
102
+ """
103
+ ...
104
+
105
+ class Queue(Generic[_T]):
106
+ """
107
+ A lock-free non-blocking MPMC queue.
108
+
109
+ Core operations detach from the python GIL, to ensure concurrent performance.
110
+ """
111
+
112
+ def __init__(self, size: int) -> None:
113
+ """
114
+ Constructs a new `Queue` with initial capacity `size`.
115
+ """
116
+ ...
117
+
118
+ def push(self, item: _T) -> _T | None:
119
+ """
120
+ Attempts to push an element into the queue.
121
+
122
+ Returns the item, if the queue was full.
123
+ """
124
+ ...
125
+
126
+ def pop(self) -> _T | None:
127
+ """
128
+ Attempts to pop an item from the queue.
129
+
130
+ Returns `None` if the queue was empty.
131
+ """
132
+ ...
133
+
134
+ def len(self) -> int:
135
+ """
136
+ Returns the current length of the queue.
137
+
138
+ This method should not be used for synchronization.
139
+ """
140
+ ...
141
+
142
+ def capacity(self) -> int:
143
+ """
144
+ Returns the current capacity of the queue.
145
+
146
+ This method should not be used for synchronization.
147
+ """
148
+ ...
149
+
150
+ def is_empty(self) -> bool:
151
+ """
152
+ Indicates whether the queue is currently empty.
153
+
154
+ This method should not be used for synchronization.
155
+ """
156
+ ...
157
+
158
+ def is_full(self) -> bool:
159
+ """
160
+ Indicates whether the queue is currently full.
161
+
162
+ This method should not be used for synchronization.
163
+ """
164
+ ...
165
+
166
+ def force_push(self, item: _T) -> _T | None:
167
+ """
168
+ Pushes an item into the queue.
169
+ This method may take some time under heavy contention.
170
+ This method may pop an arbitrary amount of items from the queue.
171
+
172
+ Returns the last popped item, if the queue was full. All other items are dropped.
173
+ """
174
+ ...
175
+
176
+ def force_push_and_do(self, item: _T, f: Callable[[_T], None]) -> None:
177
+ """
178
+ Pushes an item into the queue.
179
+ This method may take some time under heavy contention.
180
+ This method may pop an arbitrary amount of items from the queue.
181
+ Applies `f` to each popped item.
182
+ """
183
+ ...
Binary file
@@ -0,0 +1,162 @@
1
+ Metadata-Version: 2.4
2
+ Name: nblf-queue
3
+ Version: 0.1.0
4
+ License-File: LICENSE
5
+ Summary: Lock-free, non-blocking MPMC queues.
6
+ Keywords: queue,mpmc,atomic,lock-free
7
+ Author-email: Louis Meller <louis.meller@icloud.com>
8
+ License-Expression: MIT
9
+ Requires-Python: >=3.12
10
+ Description-Content-Type: text/markdown; charset=UTF-8; variant=GFM
11
+ Project-URL: Repository, https://github.com/lmeller-git/nblf-queue
12
+ Project-URL: Documentation, https://docs.rs/nblf-queue
13
+
14
+ [![Codecov](https://codecov.io/github/lmeller-git/nblf-queue/coverage.svg?branch=main)](https://codecov.io/gh/lmeller-git/nblf-queue)
15
+ ![CI Test](https://github.com/lmeller-git/nblf-queue/actions/workflows/test.yml/badge.svg?branch=main)
16
+ ![Safety Test](https://github.com/lmeller-git/nblf-queue/actions/workflows/safety.yml/badge.svg?branch=main)
17
+ ![no_std Test](https://github.com/lmeller-git/nblf-queue/actions/workflows/nostd.yml/badge.svg?branch=main)
18
+ [![Crates.io](https://img.shields.io/crates/v/nblf-queue)](https://crates.io/crates/nblf-queue)
19
+ [![Docs.rs](https://docs.rs/nblf-queue/badge.svg)](https://docs.rs/nblf-queue)
20
+
21
+ # nblf-queue
22
+
23
+ > Non-Blocking Lock-Free Queue
24
+
25
+ An atomic lock-free MPMC queue based on the NBLFQ algorithm.
26
+
27
+ This repository provides multiple queue implementations with different storage and allocation strategies.
28
+
29
+ All queues in this repository are safe to use in a concurrent context and will never block the calling thread.
30
+
31
+ ## Queue variants
32
+
33
+ - **Static queues**: fixed-capacity queues backed by static storage
34
+ - **Allocated queues**: fixed-capacity queues backed by dynamically allocated storage, only available on feature `alloc`
35
+ - **Dynamic queues**: dynamically growable queues, only available on feature `dynamic`
36
+ - **Pooled Queues**: variants of other queues, which may store arbitrary types, only available on feature `pool`
37
+
38
+ Non-pooled queues store items in atomically updated slots, restricting the stored items to small, pointer-like values.
39
+
40
+
41
+ ## Usage
42
+
43
+ `nblf_queue::StaticQueue`:
44
+
45
+ ```rust
46
+ use nblf_queue::{StaticQueue, MPMCQueue};
47
+
48
+ let q: StaticQueue<_, 2> = StaticQueue::new();
49
+
50
+ assert!(q.push(&42).is_ok());
51
+ assert!(q.push(&1).is_ok());
52
+ assert!(q.push(&4242).is_err());
53
+
54
+ assert_eq!(q.pop(), Some(&42));
55
+ assert_eq!(q.pop(), Some(&1));
56
+ assert!(q.pop().is_none());
57
+ ```
58
+
59
+
60
+ `nblf_queue::PooledStaticQueue`:
61
+
62
+ ```rust
63
+ #[cfg(feature = "pool")]
64
+ fn run() {
65
+ use nblf_queue::{PooledStaticQueue, MPMCQueue};
66
+
67
+ let q: PooledStaticQueue<_, 2> = PooledStaticQueue::new();
68
+
69
+ assert!(q.push(42).is_ok());
70
+ assert!(q.push(1).is_ok());
71
+ assert!(q.push(4242).is_err());
72
+
73
+ assert_eq!(q.pop(), Some(42));
74
+ assert_eq!(q.pop(), Some(1));
75
+ assert!(q.pop().is_none());
76
+ }
77
+
78
+ #[cfg(feature = "pool")]
79
+ run();
80
+ ```
81
+
82
+
83
+ ## Choosing a queue type
84
+
85
+ `StaticQueue` and `Queue` may only store small values and are optimized for this use case.
86
+
87
+ `PooledStaticQueue` and `PooledQueue` may store arbitrary types, at the cost of higher memory usage and runtime cost.
88
+
89
+ `DynamicQueue` and `PooledDynamicQueue` may be grown dynamically, at the cost of higher total memory usage and runtime cost. This is cost is even higher for `PooledDynamicQueue`.
90
+
91
+ ## Platform Support
92
+
93
+ Multiple storage types are available, dependent on platform:
94
+
95
+ - **Tagged64** - platforms with native 64-bit atomic operations or feature `atomic-fallback`
96
+
97
+ - **Tagged128** - platforms with native 128-bit atomic operations or feature `atomic-fallback`
98
+
99
+ Storage types will be chosen automatically, unless sepcified explicitly.
100
+
101
+ > [!NOTE]
102
+ > **ABA Safety & Storage Selection**
103
+ > If it is plausible that other threads could perform `(2^15 - 1) * queue_size`
104
+ > pop and push operations while a single thread is paused/preempted in pop/push, `Tagged128` slots should be used to ensure ABA safety.
105
+
106
+ ## Feature Flags
107
+
108
+ - `std`: Enables `std` and `alloc` support
109
+
110
+ - `alloc`: Enables `alloc` support, allowing usage of some dynamically allocated queues
111
+
112
+ - `pool`: Enables pooled queues, which may store any type
113
+
114
+ - `dynamic`: Enables dynamic queues, which may dynamically grow
115
+
116
+ - `atomic-fallback`: Uses `portable-atomic` `fallback` feature for atomics if necessary. It is discouraged to use this feature, as `fallback` internally uses locks
117
+
118
+ - `default`: `pool`
119
+
120
+
121
+ ## Python Bindings
122
+
123
+ Python bindings backed by `PooledQueue` and `PooledDynamicQueue` are available for concurrent applications.
124
+ Core operations detach from the GIL to allow parallel execution.
125
+
126
+ > [!NOTE]
127
+ > The Python bindings strictly use `Auto` slots without feature `atomic-fallback`.
128
+ > As a result, these bindings are only supported on platforms with native 64-bit or 128-bit atomic operations.
129
+
130
+ ```python
131
+ from nblf_queue import Queue, DynamicQueue
132
+
133
+ q: Queue[int] = Queue(10)
134
+
135
+ q.push(42)
136
+ item = q.pop()
137
+ assert item == 42
138
+
139
+ dq: DynamicQueue[str] = DynamicQueue(5)
140
+ dq.push("hello")
141
+
142
+ dq.grow()
143
+ ```
144
+
145
+
146
+ ## Testing
147
+
148
+ The core test-suite of this crate was adapted from [`crossbeam-queue`](https://github.com/crossbeam-rs/crossbeam/tree/main/crossbeam-queue).
149
+
150
+ Current testing is based on:
151
+
152
+ - **Miri** - to validate pointer arithmetic and catch UB
153
+ - **Loom and Shuttle** - to test for race conditions
154
+ - **ASan** - to check for memory corruption and leakage
155
+
156
+
157
+ ## References
158
+
159
+ Alexandre Denis, Charles Goedefroit. NBLFQ: a lock-free MPMC queue optimized for low contention.
160
+ IPDPS 2025 - 39th International Parallel & Distributed Processing Symposium, IEEE, Jun 2025,
161
+ Milan, Italy. hal-04851700v2
162
+
@@ -0,0 +1,7 @@
1
+ nblf_queue-0.1.0.dist-info/METADATA,sha256=pvYPZmvwKvKzD9FKNOqlHHsqO9IbLMHqq0RQALEbRQg,5571
2
+ nblf_queue-0.1.0.dist-info/WHEEL,sha256=VRUGISFtmkUtogJQvMvdBlw5mQA2s0VSEJD4NOAK5wg,95
3
+ nblf_queue-0.1.0.dist-info/licenses/LICENSE,sha256=kQATdwljoFZxExTADvtRsqU58Wk4a4ivtDYG9kDyguY,1089
4
+ nblf_queue/__init__.py,sha256=gvsdy0JDHG8vHbCBhmUKk-9riZt91Wo4BwXp9MxM_40,88
5
+ nblf_queue/__init__.pyi,sha256=hEuiImBpxEF28eyXrDhih6FjUHrsG8_mC8i1cluvX4M,4902
6
+ nblf_queue/_nblf_queue_py.pyd,sha256=F2P5OE98RqegyHZU-ex9NH-gGZm1JdsUCKpg_9gHtCw,273408
7
+ nblf_queue-0.1.0.dist-info/RECORD,,
@@ -0,0 +1,4 @@
1
+ Wheel-Version: 1.0
2
+ Generator: maturin (1.9.4)
3
+ Root-Is-Purelib: false
4
+ Tag: cp312-abi3-win_amd64
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 lmeller-git
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.