71 lines
2.2 KiB
Nim
71 lines
2.2 KiB
Nim
# SPDX-License-Identifier: LSL-1.0
|
|
# Copyright (c) 2026 Markus Maiwald
|
|
# Stewardship: Self Sovereign Society Foundation
|
|
#
|
|
# This file is part of the Nexus Sovereign Core.
|
|
# See legal/LICENSE_SOVEREIGN.md for license terms.
|
|
|
|
## Rumpk Layer 1: Simple Lock-Free Ring Buffers
|
|
|
|
# Rumpk Disruptor Ring Buffer
|
|
# Lock-free O(1) inter-fiber communication
|
|
|
|
import std/atomics
|
|
|
|
type
|
|
Cursor* = object
|
|
value*: Atomic[int64]
|
|
padding: array[64 - sizeof(Atomic[int64]), byte] ## Prevent false sharing
|
|
|
|
RingBuffer*[T; N: static[int]] = object
|
|
## Lock-free circular buffer for zero-copy I/O
|
|
## N must be power of 2 for masking
|
|
data*: array[N, T]
|
|
head* {.align: 64.}: Cursor ## Written by producer
|
|
tail* {.align: 64.}: Cursor ## Read by consumer
|
|
mask: int64 ## N - 1 for fast modulo
|
|
|
|
proc init*[T; N: static[int]](ring: var RingBuffer[T, N]) =
|
|
## Static check: N must be power of 2
|
|
static: doAssert (N and (N - 1)) == 0, "RingBuffer size must be power of 2"
|
|
|
|
ring.head.value.store(0)
|
|
ring.tail.value.store(0)
|
|
ring.mask = N - 1
|
|
|
|
proc push*[T; N: static[int]](ring: var RingBuffer[T, N]; item: T): bool =
|
|
## Push item to ring. Returns false if full.
|
|
let head = ring.head.value.load(moRelaxed)
|
|
let tail = ring.tail.value.load(moAcquire)
|
|
|
|
if head - tail >= N:
|
|
return false # Full
|
|
|
|
ring.data[head and ring.mask] = item
|
|
ring.head.value.store(head + 1, moRelease)
|
|
return true
|
|
|
|
proc pop*[T; N: static[int]](ring: var RingBuffer[T, N]): tuple[ok: bool; item: T] =
|
|
## Pop item from ring. Returns (false, default) if empty.
|
|
let tail = ring.tail.value.load(moRelaxed)
|
|
let head = ring.head.value.load(moAcquire)
|
|
|
|
if tail >= head:
|
|
return (false, default(T)) # Empty
|
|
|
|
let item = ring.data[tail and ring.mask]
|
|
ring.tail.value.store(tail + 1, moRelease)
|
|
return (true, item)
|
|
|
|
proc len*[T; N: static[int]](ring: var RingBuffer[T, N]): int =
|
|
## Current number of items in ring
|
|
let head = ring.head.value.load(moRelaxed)
|
|
let tail = ring.tail.value.load(moRelaxed)
|
|
return int(head - tail)
|
|
|
|
proc isFull*[T; N: static[int]](ring: var RingBuffer[T, N]): bool =
|
|
ring.len >= N
|
|
|
|
proc isEmpty*[T; N: static[int]](ring: var RingBuffer[T, N]): bool =
|
|
ring.len == 0
|