mirror of
https://github.com/oven-sh/bun
synced 2026-02-13 20:39:05 +00:00
105 lines
3.1 KiB
Zig
105 lines
3.1 KiB
Zig
const std = @import("std");
|
|
const assert = std.debug.assert;
|
|
|
|
/// An intrusive first in/first out linked list.
|
|
/// The element type T must have a field called "next" of type ?*T
|
|
pub fn FIFO(comptime T: type) type {
|
|
return struct {
|
|
const Self = @This();
|
|
|
|
in: ?*T = null,
|
|
out: ?*T = null,
|
|
|
|
pub fn push(self: *Self, elem: *T) void {
|
|
assert(elem.next == null);
|
|
if (self.in) |in| {
|
|
in.next = elem;
|
|
self.in = elem;
|
|
} else {
|
|
assert(self.out == null);
|
|
self.in = elem;
|
|
self.out = elem;
|
|
}
|
|
}
|
|
|
|
pub fn pop(self: *Self) ?*T {
|
|
const ret = self.out orelse return null;
|
|
self.out = ret.next;
|
|
ret.next = null;
|
|
if (self.in == ret) self.in = null;
|
|
return ret;
|
|
}
|
|
|
|
pub fn peek(self: Self) ?*T {
|
|
return self.out;
|
|
}
|
|
|
|
/// Remove an element from the FIFO. Asserts that the element is
|
|
/// in the FIFO. This operation is O(N), if this is done often you
|
|
/// probably want a different data structure.
|
|
pub fn remove(self: *Self, to_remove: *T) void {
|
|
if (to_remove == self.out) {
|
|
_ = self.pop();
|
|
return;
|
|
}
|
|
var it = self.out;
|
|
while (it) |elem| : (it = elem.next) {
|
|
if (to_remove == elem.next) {
|
|
if (to_remove == self.in) self.in = elem;
|
|
elem.next = to_remove.next;
|
|
to_remove.next = null;
|
|
break;
|
|
}
|
|
} else unreachable;
|
|
}
|
|
};
|
|
}
|
|
|
|
test "push/pop/peek/remove" {
|
|
const testing = @import("std").testing;
|
|
|
|
const Foo = struct { next: ?*@This() = null };
|
|
|
|
var one: Foo = .{};
|
|
var two: Foo = .{};
|
|
var three: Foo = .{};
|
|
|
|
var fifo: FIFO(Foo) = .{};
|
|
|
|
fifo.push(&one);
|
|
try testing.expectEqual(@as(?*Foo, &one), fifo.peek());
|
|
|
|
fifo.push(&two);
|
|
fifo.push(&three);
|
|
try testing.expectEqual(@as(?*Foo, &one), fifo.peek());
|
|
|
|
fifo.remove(&one);
|
|
try testing.expectEqual(@as(?*Foo, &two), fifo.pop());
|
|
try testing.expectEqual(@as(?*Foo, &three), fifo.pop());
|
|
try testing.expectEqual(@as(?*Foo, null), fifo.pop());
|
|
|
|
fifo.push(&one);
|
|
fifo.push(&two);
|
|
fifo.push(&three);
|
|
fifo.remove(&two);
|
|
try testing.expectEqual(@as(?*Foo, &one), fifo.pop());
|
|
try testing.expectEqual(@as(?*Foo, &three), fifo.pop());
|
|
try testing.expectEqual(@as(?*Foo, null), fifo.pop());
|
|
|
|
fifo.push(&one);
|
|
fifo.push(&two);
|
|
fifo.push(&three);
|
|
fifo.remove(&three);
|
|
try testing.expectEqual(@as(?*Foo, &one), fifo.pop());
|
|
try testing.expectEqual(@as(?*Foo, &two), fifo.pop());
|
|
try testing.expectEqual(@as(?*Foo, null), fifo.pop());
|
|
|
|
fifo.push(&one);
|
|
fifo.push(&two);
|
|
fifo.remove(&two);
|
|
fifo.push(&three);
|
|
try testing.expectEqual(@as(?*Foo, &one), fifo.pop());
|
|
try testing.expectEqual(@as(?*Foo, &three), fifo.pop());
|
|
try testing.expectEqual(@as(?*Foo, null), fifo.pop());
|
|
}
|