const std = @import("std"); const Allocator = std.mem.Allocator; const expect = std.testing.expect; const testingAllocator = std.testing.allocator; pub fn LList(comptime T: type) type { return struct { const Self = @This(); first: ?*Node(T), alloc: Allocator, counter: u64, pub fn init(this: *Self, allocator: Allocator) !void { this.alloc = allocator; this.first = null; this.counter = 0; } pub fn deinit(this: *Self) !void { //? If there is no created Node if (this.first == null) { //? Nothing to do return; } var currentNode: *Node(T) = this.first orelse unreachable; while (true) { if (currentNode.next == null){ break; } const nextNode = currentNode.next orelse unreachable; var breakNext = false; if (nextNode.next == null) { breakNext = true; } try currentNode.deinit(); currentNode = nextNode; if (breakNext == true) { break; } } try currentNode.deinit(); this.counter = 0; } pub fn add(this: *Self, value: T ) !*Node(T){ const newNode: *Node(T) = try this.alloc.create(Node(T)); try newNode.init(this.alloc, value, this.first); this.first = newNode; this.counter = this.counter + 1; return newNode; } pub fn size(this: *Self) !u64{ return this.counter; } }; } pub fn Node(comptime T: type) type { return struct { const Self = @This(); alloc: Allocator, next: ?*Self, value: *T, pub fn init(this: *Self, allocator: Allocator, value: T, next: ?*Self) !void { this.alloc = allocator; this.next = next; this.value = try this.alloc.create(T); this.value.* = value; } pub fn deinit(this: *Self) !void { this.alloc.destroy(this.value); this.alloc.destroy(this); } }; } test "leaks" { var testList: LList(u64) = undefined; try testList.init(testingAllocator); _ = try testList.add(1); _ = try testList.add(2); try testList.deinit(); } test "size" { var testList: LList(u64) = undefined; try testList.init(testingAllocator); _ = try testList.add(1); _ = try testList.add(2); _ = try testList.add(3); _ = try testList.add(4); try expect(try testList.size() == 4); try testList.deinit(); }