Hello,
While working with Nim on Arduino, I stumbled across bbqueue. It implements BipBuffers, which are a type of lock-less circular buffers. Such a buffer has a statically sized block of memory, from which it can "lend" parts of variable size upon request to writers. A writer can write something into this region and then tells the buffer it has finished. Readers can request the written parts to consume.
There are two implementations I am aware of, one in Rust and another one in Ada. I am currently working on a Nim implementation based on the Ada implementations design. The majority of this was easily translated, except for one part: In the Rust and Ada languages they can give the memory pieces to readers/writers using slices, the same should be possible in D, too. However, using slices in Nim I can not do this for the writer, as they are immutable. Here an MWE of what I would like to do:
proc modifySlice(sl: var openArray[int]):
sl[0] = 0
var
x = [1, 2, 3]
modifySlice(x[0..1])
A possible solution would be to pass the start and end pointers of the memory region to a caller. But this would remove all security checks a slice would offer and make the caller responsible to handle the memory borders.
Finally my question: is there a better way in Nim, to achieve this? Did I miss an easy solution?
Thank you for any help or suggestions!
Thank you for the quick reply!
The overload you linked does not work the way I need it to. It creates a new sequence from the content of the initial array. In contrast, I need the exact memory pieces of the initial array, so that any changes to the slice are visible in the initial array. I wrote an example workflow down below. It will hopefully make my intentions clearer.
My current implementation looks somewhat like this:
type
Offsets*[N: static[Positive]] = ref object
# Where the next byte will be written
writePos*: Atomic[csize_t]
# Where the next byte will be read from
readPos*: Atomic[csize_t]
lastPos*: Atomic[csize_t]
reserve*: Atomic[csize_t]
# Is there an active read grant?
readInProgress*: AtomicFlag
# Is there an active write grant?
writeInProgress*: AtomicFlag
# Have we already split?
alreadySplit*: Atomic[bool]
grantedWriteSize*: csize_t
grantedReadSize*: csize_t
BipBuffer*[N: static(Positive)] = object
buffer*: array[N, uint8]
offset*: Offsets[N]
I would like to give chunks of BipBuffer.buffer to the writers.
Example:
My problem is at 2. and 5. because f and g want to modify the slice, but it is immutable.
You can enable the experimental views feature and do it like this:
{.experimental: "views".}
var
buffer:array[20, int]
pos = 0
proc rent(buffer: var array[20, int], size: int): openarray[int] =
buffer.toOpenArray(pos, pos+size)
var space = buffer.rent(7)
for v in space.mitems:
v = 42
echo buffer
Otherwise I think your only option is to declare your own type with a pointer and length field and then implement a [] and []= proc to access and modify it.