Skip to content

BQueue

Coming from lockfreequeues v5?

See From lockfreequeues v5 for the package rename, import path changes, and the static-thread-affinity endpoint API.

BQueue[T, ccProd, ccCons, N, P, C] is the unified bounded, lock-free queue exposed by lockfree v0.1.0. A single generic type covers all four producer/consumer cardinality combinations — SPSC, MPSC, SPMC, and MPMC — selected at compile time through the ccProd and ccCons parameters. It replaces the family-prefixed bounded types (Sipsic, Sipmuc, Mupsic, Mupmuc) shipped by the predecessor package lockfreequeues through v4.x; the consolidated umbrella lockfree absorbs that surface verbatim under a single generic.

Overview

  • Capacity: Fixed at compile time (N)
  • Push: Wait-free (SPSC) or lock-free (multi-producer)
  • Pop: Wait-free (SPSC) or lock-free (multi-consumer)
  • No heap state: the bounded body owns no dynamic memory and needs no memory-reclamation manager. The default destructor is sufficient.

BQueue carries no debra integration and none of the unbounded Queue's ST / S / MaxThreads axes. Internally it dispatches on (ccProd, ccCons): the SPSC shape uses an N+1-slot ring with plain Atomic[int] head/tail; every multi-cardinality shape uses a Vyukov per-slot seq-counter cell array with Atomic[uint64] head/tail. The sequence-counter protocol carries the producer→consumer and consumer→next-producer happens-before edges without a separate committed flag array.

Supported T

Per Path-C of the lockfree v0.1.0 element-type story, BQueue[T, …] supports the full Nim type vocabulary, including ref T, string, and seq[T], via the ManagedRef / ManagedSlice wrappers documented in Managed Ref and Managed Slice. Plain copyable T (POD, fixed-size structs) flow through unmodified; GC-managed T flow through the managed wrappers, which keep the lock-free fast path intact while preserving ownership.

Type Parameters

  • T — Item type
  • ccProd: static PinScopeCardinality — Producer cardinality (ccSingle or ccMulti)
  • ccCons: static PinScopeCardinality — Consumer cardinality (ccSingle or ccMulti)
  • N: static int — Queue capacity (must be > 0; power of 2 recommended)
  • P: static int — Producer-registry capacity. Required > 0 when ccProd == ccMulti; must be 0 when ccProd == ccSingle.
  • C: static int — Consumer-registry capacity. Required > 0 when ccCons == ccMulti; must be 0 when ccCons == ccSingle.

The parameter order is load-bearing: T, ccProd, ccCons, N, P, C.

Constructors

newBQueue[T, ccProd, ccCons, N, P, C]() is the canonical generic smart constructor. Family-named thin wrappers are retained for ergonomic continuity with the lockfreequeues v3.x/v4.x naming and to minimize churn in downstream call sites migrating to lockfree v0.1.0; all compile to the same BQueue type:

  • newSpscQueue[T, N]() — ccSingle × ccSingle (SPSC)
  • newMpscQueue[T, N, P]() — ccMulti × ccSingle (MPSC)
  • newSpmcQueue[T, N, C]() — ccSingle × ccMulti (SPMC)
  • newMpmcQueue[T, N, P, C]() — ccMulti × ccMulti (MPMC)

Usage

import lockfree

# SPSC: single producer, single consumer, capacity 16.
# No handles needed — push/pop go directly on the queue.
var spsc = newSpscQueue[int, 16]()
discard spsc.push(42)
let a = spsc.pop()                 # some(42)

# MPMC: capacity 64, up to 4 producers and 4 consumers.
var mpmc = newBQueue[int, ccMulti, ccMulti, 64, 4, 4]()
var producer = mpmc.getProducer()
discard producer.bindToThread()  # claim the view on this thread
discard producer.push(99)
var consumer = mpmc.getConsumer()
discard consumer.bindToThread()
let b = consumer.pop()             # some(99)

# MPMC: when the calling thread is also the operating thread,
# `getProducerHere` / `getConsumerHere` are sugar for getX() + attach().
# Use the explicit form when handing the view off to a worker thread.
var mpmc2 = newBQueue[int, ccMulti, ccMulti, 64, 4, 4]()
var producer2 = mpmc2.getProducerHere()
discard producer2.push(99)
var consumer2 = mpmc2.getConsumerHere()
let c = consumer2.pop()            # some(99)

Calling Convention by Cardinality

The single side of each axis operates directly on the queue; the multi side requires a per-thread handle obtained from getProducer() / getConsumer():

Shape Push Pop
SPSC queue.push(item) queue.pop()
MPSC producer.push(item) queue.pop()
SPMC queue.push(item) consumer.pop()
MPMC producer.push(item) consumer.pop()

Calling push directly on a multi-producer BQueue (or pop on a multi-consumer BQueue) is a compile-time error — a {.error.} overload directs the caller to BQueue.getProducer().push(item) / BQueue.getConsumer().pop(). The diagnostic names only the user-visible Bound[T, Tag, BQueue[...]] endpoint / Bound[T, Tag, BQueue[...]] endpoint aliases.

When all P producer slots are taken, getProducer() raises NoProducersAvailableError; when all C consumer slots are taken, getConsumer() raises NoConsumersAvailableError.

For the common same-thread case (the calling thread is also the thread that will push/pop through the returned view), getProducerHere() / getConsumerHere() are templates that combine getX() + attach() in one call. Use the explicit getX() + attach() pair when the view is handed off to a worker thread that does the push/pop.

Typestate Notes

BQueue carries a Lifecycle typestate (BQueueInit -> BQueueDestroyed) driven by =destroy; the per-thread Bound[T, Tag, BQueue[...]] endpoint / Bound[T, Tag, BQueue[...]] endpoint views carry a Claim-state typestate (Unclaimed -> BothClaimed). All push/pop/attach/detach operations are state-preserving and emit no static transition; only the destructor moves a value to its terminal state. Use-after-destroy is a documented limitation (typestates does not statically catch a method call on an already-destroyed value); see the lockfree CHANGELOG [0.1.0] entry for details.

See also

bqueue

Bounded lock-free queue — BQueue[T, ccProd, ccCons, N, P, C].

A 6-param bounded ring-buffer surface with no debra integration and no ST/S/MaxThreads axes. Cardinality dispatch uses when (ccProd, ccCons) is internally.

Param order is LOAD-BEARING: T, ccProd, ccCons, N, P, C.

No cross-import. bqueue.nim MUST NOT import ./queue (or vice-versa). Shared helpers route through ./internal/shared. Any helper added to internal/shared is available to both modules without creating a backward dependency that would defeat the split.

Queueable[T] concept hookup. Bare BQueue[T, ccSingle, ccSingle, ...] satisfies the Queueable[T] concept defined in ./typestates/with_bound. Conformance is pinned by static doAsserts in that module across the full Path-C-encoded payload set (ref / string / seq / POD). No code change to this module is required for concept conformance — the existing public push / pop signatures on the SPSC arm already match the concept's expected shape.

Field-layout invariant. Bounded queue bodies preserve the offset prefix required by the typestate Base types (SpscBase, MpscBase, SpmcBase, MpmcBase, *PushBase). The static: offsetOf asserts below lock the prefix at canonical instantiations so the unsafe casts in the push/pop bodies remain sound. Object-field offsets are computed structurally, so a match for one instantiation implies a match for all.

Cardinality dispatch ladder. The four (ccProd × ccCons) combos are handled by when arms inside the procs, matching the layout the legacy per-family files (spsc.nim / mpsc.nim / spmc.nim / mpmc.nim) used pre-unification: - ccSingle × ccSingle (SPSC): direct Queue.push / Queue.pop. - ccMulti × ccSingle (MPSC): producer.push / direct pop. - ccSingle × ccMulti (SPMC): direct push / consumer.pop. - ccMulti × ccMulti (MPMC): producer.push / consumer.pop.

Multi-side direct-on-queue calls are gated by compile-time {.error.} overloads — calling BQueue.push(item) on a ccProd == ccMulti queue (or BQueue.pop() on ccCons == ccMulti) fails at compile time with a message pointing the caller at BQueue.getProducer().push(item) / BQueue.getConsumer().pop().

BQueueLifecycleCtx

type BQueueLifecycleCtx[T; ccProd, ccCons: static PinScopeCardinality; N, P, C: static int] = object

Phantom context type for the BQueue Lifecycle typestate. Never

instantiated at runtime; carries the generic param shape so the state types below can distinct from it.

BQueueInit

type BQueueInit[T; ccProd, ccCons: static PinScopeCardinality; N, P, C: static int] = distinct BQueueLifecycleCtx[T, ccProd, ccCons, N, P, C]

Initial Lifecycle state for a BQueue. Every newly constructed

BQueue enters this state via the {.BQueueLifecycle: BQueueInit.} attachment pragma on the BQueue object below.

BQueueDestroyed

type BQueueDestroyed[T; ccProd, ccCons: static PinScopeCardinality; N, P, C: static int] = distinct BQueueLifecycleCtx[T, ccProd, ccCons, N, P, C]

Terminal Lifecycle state for a BQueue. Reached exclusively via

the BQueue =destroy destructor's destructorTransition.

assertBQueueParams

template assertBQueueParams()

validateBQueueParams

proc validateBQueueParams(_: typedesc[BQueue[T, ccProd, ccCons, N, P, C]])

Compile-time entry point for BQueue's 4-5 param-coherence guards

(subset of ). Invoked implicitly by initBQueue; callers may invoke explicitly to exercise the guards in isolation. Has no runtime cost.

Parameters
  • _ (typedesc[BQueue[T, ccProd, ccCons, N, P, C]])

initBQueue

proc initBQueue(): BQueue[T, ccProd, ccCons, N, P, C]

Bounded-queue constructor. Initializes the slot storage, zeroes

head/tail, and clears any producer/consumer thread-id registry tables (multi-cardinality only).

initBQueue is the primitive that returns a freshly cleared BQueue value. newBQueue is the canonical smart constructor and forwards verbatim — callers should prefer newBQueue.

Returns

BQueue[T, ccProd, ccCons, N, P, C]

newBQueue inline

proc newBQueue(): BQueue[T, ccProd, ccCons, N, P, C]

Canonical bounded-queue smart constructor (M4 alias-return lock —

returns the user-visible BQueue alias, never a backing type).

Forwards to initBQueue. The family-named helpers (newSpscQueue / newMpscQueue / newSpmcQueue / newMpmcQueue) are thin wrappers around this generic ctor with the cardinality pre-bound; they exist for ergonomic continuity with the v3.x → v4.x naming and minimize churn in the test suite.

Returns

BQueue[T, ccProd, ccCons, N, P, C]

newSpscQueue inline

proc newSpscQueue(): BQueue[T, ccSingle, ccSingle, N, 0, 0]

Bounded spsc-equivalent (ccSingle × ccSingle) smart-constructor.

Returns

BQueue[T, ccSingle, ccSingle, N, 0, 0]

newMpscQueue inline

proc newMpscQueue(): BQueue[T, ccMulti, ccSingle, N, P, 0]

Bounded mpsc-equivalent (ccMulti × ccSingle) smart-constructor.

P is the producer-registry capacity.

Returns

BQueue[T, ccMulti, ccSingle, N, P, 0]

newSpmcQueue inline

proc newSpmcQueue(): BQueue[T, ccSingle, ccMulti, N, 0, C]

Bounded spmc-equivalent (ccSingle × ccMulti) smart-constructor.

C is the consumer-registry capacity.

Returns

BQueue[T, ccSingle, ccMulti, N, 0, C]

newMpmcQueue inline

proc newMpmcQueue(): BQueue[T, ccMulti, ccMulti, N, P, C]

Bounded mpmc-equivalent (ccMulti × ccMulti) smart-constructor.

P is the producer-registry capacity, C is the consumer-registry capacity.

Returns

BQueue[T, ccMulti, ccMulti, N, P, C]

capacity inline

proc capacity(self: var BQueue[T, ccProd, ccCons, N, P, C]): int

Returns the queue's storage capacity (N).

Parameters
  • self (var BQueue[T, ccProd, ccCons, N, P, C])
Returns

int

producerCount inline

proc producerCount(self: var BQueue[T, ccProd, ccCons, N, P, C]): int

Returns the queue's producer-registry capacity (P).

Single-producer shapes report 0.

Parameters
  • self (var BQueue[T, ccProd, ccCons, N, P, C])
Returns

int

consumerCount inline

proc consumerCount(self: var BQueue[T, ccProd, ccCons, N, P, C]): int

Returns the queue's consumer-registry capacity (C).

Single-consumer shapes report 0.

Parameters
  • self (var BQueue[T, ccProd, ccCons, N, P, C])
Returns

int

push

proc push(self: var BQueue[T, ccSingle, ccSingle, N, 0, 0]; item: sink T): bool

SPSC single-item push (lock-free; uses the SPSC typestate verbs).

Parameters
  • self (var BQueue[T, ccSingle, ccSingle, N, 0, 0])
  • item (sink T)
Returns

bool

push

proc push(self: var BQueue[T, ccSingle, ccMulti, N, 0, C]; item: sink T): bool

SPMC single-item push (defensive CAS, single-producer-side).

Parameters
  • self (var BQueue[T, ccSingle, ccMulti, N, 0, C])
  • item (sink T)
Returns

bool

push error

proc push(self: var BQueue[T, ccMulti, ccCons, N, P, C]; item: T): bool
Parameters
  • self (var BQueue[T, ccMulti, ccCons, N, P, C])
  • item (T)
Returns

bool

pop

proc pop(self: var BQueue[T, ccSingle, ccSingle, N, 0, 0]): Option[T]

SPSC single-item pop.

Parameters
  • self (var BQueue[T, ccSingle, ccSingle, N, 0, 0])
Returns

Option[T]

pop

proc pop(self: var BQueue[T, ccMulti, ccSingle, N, P, 0]): Option[T]

MPSC single-item pop (defensive CAS, single-consumer-side).

Parameters
  • self (var BQueue[T, ccMulti, ccSingle, N, P, 0])
Returns

Option[T]

pop error

proc pop(self: var BQueue[T, ccProd, ccMulti, N, P, C]): Option[T]
Parameters
  • self (var BQueue[T, ccProd, ccMulti, N, P, C])
Returns

Option[T]

popBatch

proc popBatch(self: var BQueue[T, ccSingle, ccSingle, N, 0, 0]; dest: var openArray[T]; maxCount: int = -1): int

SPSC direct batch pop into a caller-supplied buffer.

Parameters
  • self (var BQueue[T, ccSingle, ccSingle, N, 0, 0])
  • dest (var openArray[T])
  • maxCount (int)
Returns

int

popBatch

proc popBatch(self: var BQueue[T, ccMulti, ccSingle, N, P, 0]; dest: var openArray[T]; maxCount: int = -1): int

MPSC direct batch pop into a caller-supplied buffer.

Parameters
  • self (var BQueue[T, ccMulti, ccSingle, N, P, 0])
  • dest (var openArray[T])
  • maxCount (int)
Returns

int

popChunk

proc popChunk(self: var BQueue[T, ccSingle, ccSingle, N, 0, 0]; chunkSize: int): seq[T]
Parameters
  • self (var BQueue[T, ccSingle, ccSingle, N, 0, 0])
  • chunkSize (int)
Returns

seq[T]

popChunk

proc popChunk(self: var BQueue[T, ccMulti, ccSingle, N, P, 0]; chunkSize: int): seq[T]
Parameters
  • self (var BQueue[T, ccMulti, ccSingle, N, P, 0])
  • chunkSize (int)
Returns

seq[T]

push

proc push(self: var BQueue[T, ccSingle, ccSingle, N, 0, 0]; items: openArray[T]): Option[HSlice[int, int]]

SPSC batch push.

Parameters
  • self (var BQueue[T, ccSingle, ccSingle, N, 0, 0])
  • items (openArray[T])
Returns

Option[HSlice[int, int]]

push

proc push(self: var BQueue[T, ccSingle, ccMulti, N, 0, C]; items: openArray[T]): Option[HSlice[int, int]]

SPMC batch push (loop of single-item pushes).

Parameters
  • self (var BQueue[T, ccSingle, ccMulti, N, 0, C])
  • items (openArray[T])
Returns

Option[HSlice[int, int]]

push error

proc push(self: var BQueue[T, ccMulti, ccCons, N, P, C]; items: openArray[T]): Option[HSlice[int, int]]
Parameters
  • self (var BQueue[T, ccMulti, ccCons, N, P, C])
  • items (openArray[T])
Returns

Option[HSlice[int, int]]

pop

proc pop(self: var BQueue[T, ccSingle, ccSingle, N, 0, 0]; count: int): Option[seq[T]]

SPSC batch pop.

Parameters
  • self (var BQueue[T, ccSingle, ccSingle, N, 0, 0])
  • count (int)
Returns

Option[seq[T]]

pop

proc pop(self: var BQueue[T, ccMulti, ccSingle, N, P, 0]; count: int): Option[seq[T]]

MPSC batch pop (loop of single-item pops).

Parameters
  • self (var BQueue[T, ccMulti, ccSingle, N, P, 0])
  • count (int)
Returns

Option[seq[T]]

pop error

proc pop(self: var BQueue[T, ccProd, ccMulti, N, P, C]; count: int): Option[seq[T]]
Parameters
  • self (var BQueue[T, ccProd, ccMulti, N, P, C])
  • count (int)
Returns

Option[seq[T]]

= destructorTransition transitionError raises

proc =(self: var BQueue[T, ccProd, ccCons, N, P, C])

BQueue destructor — drives the Lifecycle terminal transition AND

performs the destroy-walk for unpopped slots.

BQueue owns no debra/manager heap state. For POD T the default destructor would suffice. For ref / string / seq T the cells / storage hold SlotEncoding(T) values (ManagedRef or ManagedSlice — distinct uint, no auto-=destroy), so abandoned items must be explicitly disposed here. This is the ONLY library-managed cleanup path (push and pop are pure transfers).

Parameters
  • self (var BQueue[T, ccProd, ccCons, N, P, C])

push tags raises notATransition

proc push(self: Bound[T, Tag, BQueue[T, ccMulti, ccSingle, N, P, 0]]; item: sink T): bool

MPSC single-item push on a Bound producer endpoint.

Parameters
  • self (Bound[T, Tag, BQueue[T, ccMulti, ccSingle, N, P, 0]])
  • item (sink T)
Returns

bool

push tags raises notATransition

proc push(self: Bound[T, Tag, BQueue[T, ccMulti, ccMulti, N, P, C]]; item: sink T): bool

MPMC single-item push on a Bound producer endpoint.

Parameters
  • self (Bound[T, Tag, BQueue[T, ccMulti, ccMulti, N, P, C]])
  • item (sink T)
Returns

bool

pop tags raises notATransition

proc pop(self: Bound[T, Tag, BQueue[T, ccSingle, ccMulti, N, 0, C]]): Option[T]

SPMC single-item pop on a Bound consumer endpoint.

Parameters
  • self (Bound[T, Tag, BQueue[T, ccSingle, ccMulti, N, 0, C]])
Returns

Option[T]

pop tags raises notATransition

proc pop(self: Bound[T, Tag, BQueue[T, ccMulti, ccMulti, N, P, C]]): Option[T]

MPMC single-item pop on a Bound consumer endpoint.

Parameters
  • self (Bound[T, Tag, BQueue[T, ccMulti, ccMulti, N, P, C]])
Returns

Option[T]

push tags raises notATransition

proc push(self: Bound[T, Tag, BQueue[T, ccMulti, ccSingle, N, P, 0]]; items: openArray[T]): Option[HSlice[int, int]]

MPSC batch push. Returns none if all items pushed; some(slice)

of unpushed indices otherwise.

Parameters
  • self (Bound[T, Tag, BQueue[T, ccMulti, ccSingle, N, P, 0]])
  • items (openArray[T])
Returns

Option[HSlice[int, int]]

push tags raises notATransition

proc push(self: Bound[T, Tag, BQueue[T, ccMulti, ccMulti, N, P, C]]; items: openArray[T]): Option[HSlice[int, int]]

MPMC batch push. Same semantics as MPSC variant.

Parameters
  • self (Bound[T, Tag, BQueue[T, ccMulti, ccMulti, N, P, C]])
  • items (openArray[T])
Returns

Option[HSlice[int, int]]

pop tags raises notATransition

proc pop(self: Bound[T, Tag, BQueue[T, ccSingle, ccMulti, N, 0, C]]; count: int): Option[seq[T]]

SPMC batch pop.

Parameters
  • self (Bound[T, Tag, BQueue[T, ccSingle, ccMulti, N, 0, C]])
  • count (int)
Returns

Option[seq[T]]

pop tags raises notATransition

proc pop(self: Bound[T, Tag, BQueue[T, ccMulti, ccMulti, N, P, C]]; count: int): Option[seq[T]]

MPMC batch pop.

Parameters
  • self (Bound[T, Tag, BQueue[T, ccMulti, ccMulti, N, P, C]])
  • count (int)
Returns

Option[seq[T]]

popBatch tags raises notATransition

proc popBatch(self: var Bound[T, Tag, BQueue[T, ccProd, ccCons, N, P, C]]; dest: var openArray[T]; maxCount: int = -1): int

Multi-consumer BQueue batch pop into a caller-supplied openArray buffer.

Extracts up to min(dest.len, maxCount) items without allocating intermediate seqs. Returns the number of items successfully extracted.

Parameters
  • self (var Bound[T, Tag, BQueue[T, ccProd, ccCons, N, P, C]])
  • dest (var openArray[T])
  • maxCount (int)
Returns

int

popBatch tags raises notATransition

proc popBatch(self: Bound[T, Tag, BQueue[T, ccProd, ccCons, N, P, C]]; dest: var openArray[T]; maxCount: int = -1): int

Multi-consumer BQueue batch pop (value-receiver overload).

Parameters
  • self (Bound[T, Tag, BQueue[T, ccProd, ccCons, N, P, C]])
  • dest (var openArray[T])
  • maxCount (int)
Returns

int

popChunk tags raises notATransition

proc popChunk(self: var Bound[T, Tag, BQueue[T, ccProd, ccCons, N, P, C]]; chunkSize: int): seq[T]

Extracts a chunk of up to chunkSize items into a new seq[T].

Parameters
  • self (var Bound[T, Tag, BQueue[T, ccProd, ccCons, N, P, C]])
  • chunkSize (int)
Returns

seq[T]

popChunk tags raises notATransition

proc popChunk(self: Bound[T, Tag, BQueue[T, ccProd, ccCons, N, P, C]]; chunkSize: int): seq[T]
Parameters
  • self (Bound[T, Tag, BQueue[T, ccProd, ccCons, N, P, C]])
  • chunkSize (int)
Returns

seq[T]

drain

iterator drain(self: var BQueue[T, ccProd, ccSingle, N, P, 0]): T

Drain a single-consumer BQueue (SPSC or MPSC). Yields each remaining

item until the queue is empty. Calls the existing pop in a loop — Path-C unwrap is already done by pop.

Parameters
  • self (var BQueue[T, ccProd, ccSingle, N, P, 0])
Returns

T

drain

iterator drain(self: Bound[T, Tag, BQueue[T, ccSingle, ccMulti, N, 0, C]]): T

Drain an SPMC BQueue via its Bound consumer endpoint.

Parameters
  • self (Bound[T, Tag, BQueue[T, ccSingle, ccMulti, N, 0, C]])
Returns

T

drain

iterator drain(self: Bound[T, Tag, BQueue[T, ccMulti, ccMulti, N, P, C]]): T

Drain an MPMC BQueue via its Bound consumer endpoint.

Parameters
  • self (Bound[T, Tag, BQueue[T, ccMulti, ccMulti, N, P, C]])
Returns

T

items

iterator items(self: var BQueue[T, ccProd, ccSingle, N, P, 0]): T
Parameters
  • self (var BQueue[T, ccProd, ccSingle, N, P, 0])
Returns

T

items

iterator items(self: Bound[T, Tag, BQueue[T, ccSingle, ccMulti, N, 0, C]]): T
Parameters
  • self (Bound[T, Tag, BQueue[T, ccSingle, ccMulti, N, 0, C]])
Returns

T

items

iterator items(self: Bound[T, Tag, BQueue[T, ccMulti, ccMulti, N, P, C]]): T
Parameters
  • self (Bound[T, Tag, BQueue[T, ccMulti, ccMulti, N, P, C]])
Returns

T

pairs

iterator pairs(self: var BQueue[T, ccProd, ccSingle, N, P, 0]): (int, T)
Parameters
  • self (var BQueue[T, ccProd, ccSingle, N, P, 0])
Returns

(int, T)

pairs

iterator pairs(self: Bound[T, Tag, BQueue[T, ccSingle, ccMulti, N, 0, C]]): (int, T)
Parameters
  • self (Bound[T, Tag, BQueue[T, ccSingle, ccMulti, N, 0, C]])
Returns

(int, T)

pairs

iterator pairs(self: Bound[T, Tag, BQueue[T, ccMulti, ccMulti, N, P, C]]): (int, T)
Parameters
  • self (Bound[T, Tag, BQueue[T, ccMulti, ccMulti, N, P, C]])
Returns

(int, T)

destroyAndDrain

proc destroyAndDrain(self: sink BQueue[T, ccProd, ccSingle, N, P, 0]; cleanup: proc (item: T) {.gcsafe, raises: [].})

Drain a single-consumer BQueue (SPSC or MPSC), calling cleanup

on each remaining item, then trigger queue destruction. Takes sink of the queue so the caller's binding is moved-from (preventing scope-end double-destroy on top of the explicit destruction here).

Under mm:none this is the ONLY safe teardown path for a non-empty queue carrying ref / string / seq payloads (strict bit-transport contract). For POD payloads the cleanup is logically a no-op.

Parameters
  • self (sink BQueue[T, ccProd, ccSingle, N, P, 0])
  • cleanup (proc (item: T) {.gcsafe, raises: [].})

destroyAndDrain

proc destroyAndDrain(self: sink BQueue[T, ccProd, ccSingle, N, P, 0])

POD discard-callback overload for single-consumer BQueue. Takes

sink for the same reason as the callback overload. Safe for POD T; for non-POD T the queue's =destroy walk handles disposal under arc/orc/atomicArc/refc — under mm:none, this overload leaks payload bits (the operator must provide an explicit cleanup callback under mm:none for non-POD T).

Parameters
  • self (sink BQueue[T, ccProd, ccSingle, N, P, 0])

reset

proc reset(self: var BQueue[T, ccProd, ccCons, N, P, C])

Resets the queue to its default state. For single-threaded unit

tests only.

Parameters
  • self (var BQueue[T, ccProd, ccCons, N, P, C])

checkState

proc checkState(self: var BQueue[T, ccSingle, ccSingle, N, 0, 0]; head: int; tail: int; storage: seq[T])

SPSC checkState.

Parameters
  • self (var BQueue[T, ccSingle, ccSingle, N, 0, 0])
  • head (int)
  • tail (int)
  • storage (seq[T])

checkState

proc checkState(self: var BQueue[T, ccProd, ccCons, N, P, C]; head: uint64; tail: uint64)

Non-SPSC head+tail-only checkState.

Parameters
  • self (var BQueue[T, ccProd, ccCons, N, P, C])
  • head (uint64)
  • tail (uint64)

checkState

proc checkState(self: var BQueue[T, ccProd, ccCons, N, P, C]; head: uint64; tail: uint64; data: seq[T])

Non-SPSC head+tail+data checkState.

Parameters
  • self (var BQueue[T, ccProd, ccCons, N, P, C])
  • head (uint64)
  • tail (uint64)
  • data (seq[T])