| ... | ... | @@ -5,6 +5,8 @@ const expect = std.testing.expect; |
| 5 | 5 | |
| 6 | 6 | /// Many producer, many consumer, non-allocating, thread-safe. |
| 7 | 7 | /// Uses a mutex to protect access. |
| 8 | /// The queue does not manage ownership and the user is responsible to |
| 9 | /// manage the storage of the nodes. |
| 8 | 10 | pub fn Queue(comptime T: type) type { |
| 9 | 11 | return struct { |
| 10 | 12 | head: ?*Node, |
| ... | ... | @@ -14,6 +16,8 @@ pub fn Queue(comptime T: type) type { |
| 14 | 16 | pub const Self = @This(); |
| 15 | 17 | pub const Node = std.TailQueue(T).Node; |
| 16 | 18 | |
| 19 | /// Initializes a new queue. The queue does not provide a `deinit()` |
| 20 | /// function, so the user must take care of cleaning up the queue elements. |
| 17 | 21 | pub fn init() Self { |
| 18 | 22 | return Self{ |
| 19 | 23 | .head = null, |
| ... | ... | @@ -22,6 +26,8 @@ pub fn Queue(comptime T: type) type { |
| 22 | 26 | }; |
| 23 | 27 | } |
| 24 | 28 | |
| 29 | /// Appends `node` to the queue. |
| 30 | /// The lifetime of `node` must be longer than lifetime of queue. |
| 25 | 31 | pub fn put(self: *Self, node: *Node) void { |
| 26 | 32 | node.next = null; |
| 27 | 33 | |
| ... | ... | @@ -38,6 +44,9 @@ pub fn Queue(comptime T: type) type { |
| 38 | 44 | } |
| 39 | 45 | } |
| 40 | 46 | |
| 47 | /// Gets a previously inserted node or returns `null` if there is none. |
| 48 | /// It is safe to `get()` a node from the queue while another thread tries |
| 49 | /// to `remove()` the same node at the same time. |
| 41 | 50 | pub fn get(self: *Self) ?*Node { |
| 42 | 51 | const held = self.mutex.acquire(); |
| 43 | 52 | defer held.release(); |
| ... | ... | @@ -71,7 +80,9 @@ pub fn Queue(comptime T: type) type { |
| 71 | 80 | } |
| 72 | 81 | } |
| 73 | 82 | |
| 74 | | /// Thread-safe with get() and remove(). Returns whether node was actually removed. |
| 83 | /// Removes a node from the queue, returns whether node was actually removed. |
| 84 | /// It is safe to `remove()` a node from the queue while another thread tries |
| 85 | /// to `get()` the same node at the same time. |
| 75 | 86 | pub fn remove(self: *Self, node: *Node) bool { |
| 76 | 87 | const held = self.mutex.acquire(); |
| 77 | 88 | defer held.release(); |
| ... | ... | @@ -95,16 +106,23 @@ pub fn Queue(comptime T: type) type { |
| 95 | 106 | return true; |
| 96 | 107 | } |
| 97 | 108 | |
| 109 | /// Returns `true` if the queue is currently empty. |
| 110 | /// Note that in a multi-consumer environment a return value of `false` |
| 111 | /// does not mean that `get` will yield a non-`null` value! |
| 98 | 112 | pub fn isEmpty(self: *Self) bool { |
| 99 | 113 | const held = self.mutex.acquire(); |
| 100 | 114 | defer held.release(); |
| 101 | 115 | return self.head == null; |
| 102 | 116 | } |
| 103 | 117 | |
| 118 | /// Dumps the contents of the queue to `stderr`. |
| 104 | 119 | pub fn dump(self: *Self) void { |
| 105 | 120 | self.dumpToStream(std.io.getStdErr().outStream()) catch return; |
| 106 | 121 | } |
| 107 | 122 | |
| 123 | /// Dumps the contents of the queue to `stream`. |
| 124 | /// Up to 4 elements from the head are dumped and the tail of the queue is |
| 125 | /// dumped as well. |
| 108 | 126 | pub fn dumpToStream(self: *Self, stream: var) !void { |
| 109 | 127 | const S = struct { |
| 110 | 128 | fn dumpRecursive( |