From fd27f5c7a709def9876a4ec75043839fdbadcca9 Mon Sep 17 00:00:00 2001 From: pwbh Date: Sat, 31 Aug 2024 17:43:25 +0300 Subject: [PATCH] linked list --- src/linked_list.zig | 296 ++++++++++++++++++++++++++++++++++++++++++++ src/main.zig | 1 + src/root.zig | 32 +++-- 3 files changed, 319 insertions(+), 10 deletions(-) create mode 100644 src/linked_list.zig diff --git a/src/linked_list.zig b/src/linked_list.zig new file mode 100644 index 0000000..eb114fe --- /dev/null +++ b/src/linked_list.zig @@ -0,0 +1,296 @@ +const std = @import("std"); + +const Allocator = std.mem.Allocator; + +const expect = std.testing.expect; + +pub fn LinkedList(comptime T: type) type { + return struct { + head: ?*Node = null, + tail: ?*Node = null, + len: usize, + allocator: Allocator, + + const Self = @This(); + + const Node = struct { + next: ?*Node = null, + prev: ?*Node = null, + value: T, + }; + + pub fn init(allocator: Allocator) Self { + return .{ + .len = 0, + .allocator = allocator, + }; + } + + pub fn deinit(self: *Self) void { + while (self.popFront()) |_| {} + } + + pub fn appendFront(self: *Self, value: T) !void { + const node = try self.allocator.create(Node); + + if (self.head == null) { + node.* = .{ .value = value }; + self.head = node; + self.tail = node; + } else { + const current_head = self.head.?; + node.* = .{ .value = value, .next = current_head }; + current_head.prev = node; + self.head = node; + } + + self.len += 1; + } + + pub fn appendBack(self: *Self, value: T) !void { + if (self.tail == null) { + try self.appendFront(value); + } else { + const current_tail = self.tail.?; + const node = try self.allocator.create(Node); + node.* = .{ .value = value, .prev = current_tail }; + current_tail.next = node; + self.tail = node; + self.len += 1; + } + } + + pub fn popFront(self: *Self) ?T { + if (self.head == null) { + return null; + } + + const current_head = self.head.?; + self.head = current_head.next; + + if (self.len == 1) { + self.tail = null; + } + + const value = current_head.value; + self.allocator.destroy(current_head); + self.len -= 1; + + return value; + } + + pub fn popBack(self: *Self) ?T { + if (self.tail == null) { + return null; + } + + const current_tail = self.tail.?; + self.tail = current_tail.prev; + + if (self.len == 1) { + self.head = null; + } + + const value = current_tail.value; + self.allocator.destroy(current_tail); + self.len -= 1; + + return value; + } + + pub fn printChain(self: *Self) void { + var cursor = self.head; + + if (cursor == null) { + std.debug.print("\n[]\n", .{}); + return; + } + + std.debug.print("\n[", .{}); + while (cursor) |current_node| { + if (current_node.next != null) { + std.debug.print("{} -> ", .{current_node.value}); + cursor = current_node.next; + } else { + std.debug.print("{}]\n", .{current_node.value}); + break; + } + } + } + }; +} + +test "creates a linked list with appending via front and pops via back" { + const allocator = std.testing.allocator; + + const linked_list = LinkedList(u32); + + var list = linked_list.init(allocator); + + defer list.deinit(); + + try list.appendFront(1); + try list.appendFront(2); + try list.appendFront(3); + + list.printChain(); + + try expect(list.len == 3); + + try expect(list.popBack() == 1); + try expect(list.popBack() == 2); + try expect(list.popBack() == 3); + try expect(list.popBack() == null); + + try expect(list.len == 0); +} + +test "creates a linked list with appending via back and pops via front" { + const allocator = std.testing.allocator; + + var list = LinkedList(u32).init(allocator); + + defer list.deinit(); + + try list.appendBack(1); + try list.appendBack(2); + try list.appendBack(3); + + try expect(list.len == 3); + + try expect(list.popFront() == 1); + try expect(list.popFront() == 2); + try expect(list.popFront() == 3); + try expect(list.popFront() == null); + + try expect(list.len == 0); + + list.printChain(); +} + +test "creates a linked list with appending via back and front and pops via front" { + const allocator = std.testing.allocator; + + var list = LinkedList(u32).init(allocator); + + defer list.deinit(); + + try list.appendFront(1); + try list.appendFront(2); + try list.appendFront(3); + + try list.appendBack(1); + try list.appendBack(2); + try list.appendBack(3); + + list.printChain(); + + try expect(list.len == 6); + + try expect(list.popFront() == 3); + try expect(list.popFront() == 2); + try expect(list.popFront() == 1); + try expect(list.popFront() == 1); + try expect(list.popFront() == 2); + try expect(list.popFront() == 3); + try expect(list.popFront() == null); + + try expect(list.len == 0); +} + +test "creates a linked list with appending via back and front and pops via back" { + const allocator = std.testing.allocator; + + var list = LinkedList(u32).init(allocator); + + defer list.deinit(); + + try list.appendFront(1); + try list.appendFront(2); + try list.appendFront(3); + + try list.appendBack(1); + try list.appendBack(2); + try list.appendBack(3); + + list.printChain(); + + try expect(list.len == 6); + + try expect(list.popBack() == 3); + try expect(list.popBack() == 2); + try expect(list.popBack() == 1); + try expect(list.popBack() == 1); + try expect(list.popBack() == 2); + try expect(list.popBack() == 3); + try expect(list.popBack() == null); + + try expect(list.len == 0); +} + +test "creates a linked list with appending via front and auto pops via deinit" { + const allocator = std.testing.allocator; + + var list = LinkedList(u32).init(allocator); + + try list.appendFront(1); + try list.appendFront(2); + try list.appendFront(3); + + try list.appendBack(1); + try list.appendBack(2); + try list.appendBack(3); + + try expect(list.len == 6); + + list.printChain(); + list.deinit(); + + try expect(list.len == 0); + + try expect(list.popFront() == null); + try expect(list.popBack() == null); +} + +test "creates a linked list with elements appended mixed and popped via deinit" { + const allocator = std.testing.allocator; + + var list = LinkedList(u32).init(allocator); + + try list.appendFront(1); + try list.appendBack(2); + try list.appendFront(5); + try list.appendBack(2); + try list.appendBack(4); + try list.appendFront(3); + try list.appendFront(3); + + try expect(list.len == 7); + + list.printChain(); + list.deinit(); + + try expect(list.len == 0); +} + +test "creates a linked list with elements appended mixed and pop mixed" { + const allocator = std.testing.allocator; + + const linked_list = LinkedList(u32); + + var list = linked_list.init(allocator); + + try list.appendFront(1); + try list.appendBack(2); + try list.appendFront(5); + try list.appendBack(2); + try list.appendBack(4); + try list.appendFront(3); + try list.appendFront(3); + + try expect(list.len == 7); + + list.printChain(); + + try expect(list.len == 0); +} diff --git a/src/main.zig b/src/main.zig index 9793da3..247a389 100644 --- a/src/main.zig +++ b/src/main.zig @@ -36,6 +36,7 @@ const Details = struct { const Program = struct { name: []const u8, vs: Details, + fs: Details, }; const Shader = struct { diff --git a/src/root.zig b/src/root.zig index db2f804..e02479b 100644 --- a/src/root.zig +++ b/src/root.zig @@ -1,5 +1,7 @@ const std = @import("std"); +const LinkedList = @import("linked_list.zig").LinkedList; + const Allocator = std.mem.Allocator; const AnyReader = std.io.AnyReader; @@ -31,7 +33,7 @@ pub fn Ymlz(comptime Destination: type) type { allocator: Allocator, reader: ?AnyReader, allocations: std.ArrayList([]const u8), - suspensed: ?[]const u8, + suspensed: LinkedList([]const u8), const Self = @This(); @@ -40,7 +42,7 @@ pub fn Ymlz(comptime Destination: type) type { .allocator = allocator, .reader = null, .allocations = std.ArrayList([]const u8).init(allocator), - .suspensed = null, + .suspensed = LinkedList([]const u8).init(allocator), }; } @@ -126,6 +128,16 @@ pub fn Ymlz(comptime Destination: type) type { return INDENT_SIZE * depth; } + fn printFieldWithIdent(self: *Self, depth: usize, field_name: []const u8, raw_line: []const u8) void { + _ = self; + // std.debug.print("printFieldWithIdent:", .{}); + for (0..depth) |_| { + std.debug.print(" ", .{}); + } + + std.debug.print("{s} - {s}\n", .{ field_name, raw_line }); + } + fn parse(self: *Self, comptime T: type, depth: usize) !T { var destination: T = undefined; @@ -136,16 +148,15 @@ pub fn Ymlz(comptime Destination: type) type { var raw_line: []const u8 = undefined; - if (self.suspensed) |s| { + if (self.suspensed.popFront()) |s| { raw_line = s; - self.suspensed = null; } else { raw_line = try self.readLine() orelse break; } if (raw_line.len == 0) break; - // std.debug.print("{s}:\n", .{field.name}); + self.printFieldWithIdent(depth, field.name, raw_line); if (typeInfo != .Optional or (typeInfo == .Optional and try self.isOptionalFieldExists(field.name, raw_line, depth))) { const actualTypeInfo = if (typeInfo == .Optional) @typeInfo(typeInfo.Optional.child) else typeInfo; @@ -166,6 +177,7 @@ pub fn Ymlz(comptime Destination: type) type { } else if (actualTypeInfo.Pointer.size == .Slice and (actualTypeInfo.Pointer.child == []const u8 or actualTypeInfo.Pointer.child == []u8)) { @field(destination, field.name) = try self.parseStringArrayExpression(actualTypeInfo.Pointer.child, depth + 1); } else if (actualTypeInfo.Pointer.size == .Slice and @typeInfo(actualTypeInfo.Pointer.child) != .Pointer) { + std.debug.print("Entering array: {s}\n", .{field.name}); @field(destination, field.name) = try self.parseArrayExpression(actualTypeInfo.Pointer.child, depth + 1); } else { @panic("unexpected type recieved - " ++ @typeName(field.type) ++ "\n"); @@ -179,7 +191,6 @@ pub fn Ymlz(comptime Destination: type) type { }, } } else { - self.suspensed = raw_line; @field(destination, field.name) = null; } } @@ -263,7 +274,7 @@ pub fn Ymlz(comptime Destination: type) type { const raw_value_line = try self.readLine() orelse break; if (self.isNewExpression(raw_value_line, depth)) { - self.suspensed = raw_value_line; + try self.suspensed.appendBack(raw_value_line); break; } @@ -284,9 +295,10 @@ pub fn Ymlz(comptime Destination: type) type { while (true) { const raw_value_line = try self.readLine() orelse break; - self.suspensed = raw_value_line; + try self.suspensed.appendBack(raw_value_line); - if (raw_value_line.len < indent_depth or self.suspensed.?[indent_depth] != '-') { + // std.debug.print("before parseArrayExpression: {s}\n", .{raw_value_line}); + if (raw_value_line.len < indent_depth or raw_value_line[indent_depth] != '-') { break; } @@ -321,7 +333,7 @@ pub fn Ymlz(comptime Destination: type) type { const raw_value_line = try self.readLine() orelse break; if (self.isNewExpression(raw_value_line, depth)) { - self.suspensed = raw_value_line; + try self.suspensed.appendBack(raw_value_line); if (preserve_new_line) _ = list.pop(); break;