46 lines
1.5 KiB
Zig
46 lines
1.5 KiB
Zig
/// Many reader, many writer, non-allocating, thread-safe, lock-free
|
|
pub fn Stack(comptime T: type) type {
|
|
return struct {
|
|
root: ?&Node,
|
|
|
|
pub const Self = this;
|
|
|
|
pub const Node = struct {
|
|
next: ?&Node,
|
|
data: T,
|
|
};
|
|
|
|
pub fn init() Self {
|
|
return Self {
|
|
.root = null,
|
|
};
|
|
}
|
|
|
|
/// push operation, but only if you are the first item in the stack. if you did not succeed in
|
|
/// being the first item in the stack, returns the other item that was there.
|
|
pub fn pushFirst(self: &Self, node: &Node) ?&Node {
|
|
node.next = null;
|
|
return @cmpxchgStrong(?&Node, &self.root, null, node, AtomicOrder.AcqRel, AtomicOrder.AcqRel);
|
|
}
|
|
|
|
pub fn push(self: &Self, node: &Node) void {
|
|
var root = @atomicLoad(?&Node, &self.root, AtomicOrder.Acquire);
|
|
while (true) {
|
|
node.next = root;
|
|
root = @cmpxchgWeak(?&Node, &self.root, root, node, AtomicOrder.Release, AtomicOrder.Acquire) ?? break;
|
|
}
|
|
}
|
|
|
|
pub fn pop(self: &Self) ?&Node {
|
|
var root = @atomicLoad(?&Node, &self.root, AtomicOrder.Acquire);
|
|
while (true) {
|
|
root = @cmpxchgWeak(?&Node, &self.root, root, (root ?? return null).next, AtomicOrder.Release, AtomicOrder.Acquire) ?? return root;
|
|
}
|
|
}
|
|
|
|
pub fn isEmpty(self: &Self) bool {
|
|
return @atomicLoad(?&Node, &self.root, AtomicOrder.Relaxed) == null;
|
|
}
|
|
};
|
|
}
|