diff options
Diffstat (limited to 'std/atomic/stack.zig')
| -rw-r--r-- | std/atomic/stack.zig | 45 |
1 files changed, 45 insertions, 0 deletions
diff --git a/std/atomic/stack.zig b/std/atomic/stack.zig new file mode 100644 index 0000000000..4ceecb7b1d --- /dev/null +++ b/std/atomic/stack.zig @@ -0,0 +1,45 @@ +/// 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; + } + }; +} |
