Hey there,
for a small concurrent container which basically only has
pub fn push(&self, value: T);
pub fn iter(&self) -> impl Iterator<Item = T>;
pub fn pop(&mut self) -> Option<T>;
as its API, I'm looking for ways to manage its actual memory.
What I need is some form of paging or growing in blocks, probably how std::vec::Vec does it: I start with some capacity, say 100, if the 100th element has been pushed, I grow for another 100 etc.
The point is: I need the memory to be addressable by an index (or pointer) or an offset, i.e. anything which can be atomically incremented.
Ignoring the concurrent aspect, a naive implementation would be something like this:
struct CStack<T> {
data: Vec<T>,
block_size: usize,
next_elem: usize,
}
// ...
fn grow(&mut self) {
self.data.extend_from_slice(&vec![T::default(); self.block_size]);
}
fn push(&mut self, value: T) {
if self.next_elem >= self.data.len() {
self.grow()
}
// this is crucial, access by index or offset or anything which can be atomically incremented:
self.data[self.next_elem] = value;
}
So, a few things feel off here:
Tneeds to haveimpl Default. I would rather dip and learn aboutMaybeUninitif this is the right direction?Vecseems to be the wrong choice. I'm not interested in its capacity, since the structure manages its capacity on its own. Something withBox<[T]>maybe? Or more raw?
Might this be a good time to learn about allocation in Rust?
The project is to learn more about low-level implementations, concurrency and sprinkles of unsafe (I'm reading "Rust Atomics and Locks" by Mara Bos and just playing around with ideas, trying to understand other stuff on the way as well).
Thanks in advance!