diff --git a/README.md b/README.md index 3a65a0e..7ee8b94 100644 --- a/README.md +++ b/README.md @@ -1,20 +1,23 @@ -**Includes** -- ANSI -- SlotMap | KeyedSlotMap -- Custom Log +# Includes + +## Arrays +- SlotMap +- KeyedSlotMap + +- FixedSlotMap +- FixedArrayList +- RingBuffer +- Handle(T) **Generational** + +## Misc +- log +- ansi (colors etc) - TypeID -**Logs** -```zig -log.warn("...", .{}); -log.err("...", .{}); -log.info("...", .{}); -log.debug("...", .{}); -log.trace("...", .{}); -log.fatal("...", .{}); -``` +# Examples + +## KeyedSlotMap -**KeyedSlotMap** ```zig // --- SHADER MAP --- var shaders: KeyedSlotMap(ShaderID, GPUShader) = .init(alloc); @@ -25,7 +28,8 @@ const shader_handle = try shaders.put(.pbr, .{ .raw = undefined }); defer shaders.remove(shader_handle); ``` -**TypeID** +## TypeID + ```zig const Player = struct {}; std.debug.print("TypeID(Player): {}\n", .{TypeID(Player)}); @@ -34,15 +38,26 @@ std.debug.print("TypeID(Player): {}\n", .{TypeID(Player)}); Output: TypeID(Player): 2462284566368800629 ``` -# NicePrint +## Logs -## Styles +```zig +log.warn("...", .{}); +log.err("...", .{}); +log.info("...", .{}); +log.debug("...", .{}); +log.trace("...", .{}); +log.fatal("...", .{}); +``` + +## NicePrint + +### Styles - default - rounded - pipe - custom -## Example +### Example ```zig // --- PRINT --- if (log.print(.debug, "DEVICE INFO", ansi.bold ++ ansi.red)) |a| { @@ -61,7 +76,7 @@ if (log.print(.debug, "DEVICE INFO", ansi.bold ++ ansi.red)) |a| { } ``` -## Output +### Output ```text ┏━ DEVICE INFO ┃ device -> GTX @@ -71,3 +86,6 @@ if (log.print(.debug, "DEVICE INFO", ansi.bold ++ ansi.red)) |a| { ┃ ┗━ ┗━ ``` + +# TODO +[ ] Lear how to properly structure markdown 🥀️ diff --git a/src/fixed_array_list.zig b/src/fixed_array_list.zig new file mode 100644 index 0000000..992ea12 --- /dev/null +++ b/src/fixed_array_list.zig @@ -0,0 +1,134 @@ +const std = @import("std"); + +/// ---------------------------------------------------- +/// ---------------------------------------------------- +pub fn FixedArrayList( + comptime T: type, + comptime Capacity: usize, +) type { + return struct { + const Self = @This(); + + // + // FIELDS + // + + data: [Capacity]T, + cursor: usize = 0, + + /// ---------------------------------------------------- + /// ---------------------------------------------------- + pub const empty = Self{ + .data = undefined, + .cursor = 0, + }; + + /// ---------------------------------------------------- + /// ---------------------------------------------------- + pub fn append(self: *Self, item: T) error{Full}!void { + if (self.isFull()) return error.Full; + self.data[self.cursor] = item; + self.cursor += 1; + } + + /// ---------------------------------------------------- + /// ---------------------------------------------------- + pub fn appendMany(self: *Self, values: []const T) error{Full}!void { + if (self.cursor + values.len > Capacity) return error.Full; + + @memcpy( + self.data[self.cursor .. self.cursor + values.len], + values, + ); + + self.cursor += values.len; + } + + /// ---------------------------------------------------- + /// ---------------------------------------------------- + pub fn pop(self: *Self) ?T { + if (self.cursor == 0) return null; + self.cursor -= 1; + return self.data[self.cursor]; + } + + /// ---------------------------------------------------- + /// ---------------------------------------------------- + pub fn swapRemove(self: *Self, i: usize) ?T { + if (i >= self.cursor) return null; + + const removed: T = self.data[i]; + + self.cursor -= 1; + + if (i != self.cursor) { + self.data[i] = self.data[self.cursor]; + } + + return removed; + } + + /// ---------------------------------------------------- + /// ---------------------------------------------------- + pub fn get(self: *Self, i: usize) ?T { + if (i >= self.cursor) return null; + return self.data[i]; + } + + /// ---------------------------------------------------- + /// ---------------------------------------------------- + pub fn getPtr(self: *Self, i: usize) ?*T { + if (i >= self.cursor) return null; + return &self.data[i]; + } + + /// ---------------------------------------------------- + /// ---------------------------------------------------- + pub fn getConstPtr(self: *const Self, i: usize) ?*const T { + if (i >= self.cursor) return null; + return &self.data[i]; + } + + /// ---------------------------------------------------- + /// ---------------------------------------------------- + pub fn items(self: *Self) []T { + return self.data[0..self.cursor]; + } + + /// ---------------------------------------------------- + /// ---------------------------------------------------- + pub fn len(self: *const Self) usize { + return self.cursor; + } + + /// ---------------------------------------------------- + /// ---------------------------------------------------- + pub fn capacity(_: *const Self) usize { + return Capacity; + } + + /// ---------------------------------------------------- + /// ---------------------------------------------------- + pub fn available(self: *const Self) usize { + return Capacity - self.cursor; + } + + /// ---------------------------------------------------- + /// ---------------------------------------------------- + pub fn clear(self: *Self) void { + self.cursor = 0; + } + + /// ---------------------------------------------------- + /// ---------------------------------------------------- + pub fn isEmpty(self: *const Self) bool { + return self.cursor == 0; + } + + /// ---------------------------------------------------- + /// ---------------------------------------------------- + pub fn isFull(self: *const Self) bool { + return self.cursor == Capacity; + } + }; +} diff --git a/src/fixed_slot_map.zig b/src/fixed_slot_map.zig new file mode 100644 index 0000000..a3d89da --- /dev/null +++ b/src/fixed_slot_map.zig @@ -0,0 +1,105 @@ +const std = @import("std"); +const FixedArrayList = @import("fixed_array_list.zig").FixedArrayList; +const Handle = @import("handle.zig").Handle; + +/// ---------------------------------------------------- +/// # Example +/// +/// ```zig +/// ``` +/// ---------------------------------------------------- +pub fn FixedSlotMap( + comptime T: type, + comptime Capacity: usize, +) type { + return struct { + const Self = @This(); + + // + // FIELDS + // + + // --- VALUES --- + values: FixedArrayList(T, Capacity), + + // --- LIFE TIMES --- + generations: FixedArrayList(u32, Capacity), + free_list: FixedArrayList(u32, Capacity), + + /// ---------------------------------------------------- + /// ---------------------------------------------------- + pub const empty = Self{ + .values = .empty, + .generations = .empty, + .free_list = .empty, + }; + + /// ---------------------------------------------------- + /// ---------------------------------------------------- + pub fn put( + self: *Self, + value: T, + ) error{Full}!Handle(T) { + // --- NEW GENERATION --- + if (self.free_list.pop()) |idx| { + self.values.data[@intCast(idx)] = value; + self.generations.data[@intCast(idx)] += 1; + + return .{ + .idx = idx, + .gen = self.generations.data[idx], + }; + } + + // --- METADATA --- + const idx = self.values.len(); + const handle: Handle(T) = .{ + .idx = @intCast(idx), + .gen = 1, + }; + + // --- NEW VALUE --- + try self.values.append(value); + errdefer _ = self.values.swapRemove(idx); + + // --- NEW GENERATION --- + try self.generations.append(1); + + // --- RESULT --- + return handle; + } + + /// ---------------------------------------------------- + /// ---------------------------------------------------- + pub fn remove( + self: *Self, + handle: Handle(T), + ) void { + const idx: u32 = handle.idx; + + // --- CHECK IF STALE --- + if (idx >= self.generations.len()) return; + if (self.generations.data[idx] != handle.gen) return; + + // --- GENERATION --- + self.generations.data[idx] +|= 1; + self.free_list.append(idx) catch |err| { + std.debug.print("[SLOTMAP_ERROR] {s}\n", .{@errorName(err)}); + }; + } + + /// ---------------------------------------------------- + /// ---------------------------------------------------- + pub fn get(self: *Self, handle: Handle(T)) ?*T { + if (handle.idx >= self.values.len()) return null; + if (self.generations.data[handle.idx] != handle.gen) return null; + return &self.values.data[handle.idx]; + } + + /// ---------------------------------------------------- + /// ---------------------------------------------------- + pub fn items(self: *Self) []T { + return self.values.items(); + } + }; +} diff --git a/src/gtl.zig b/src/gtl.zig index 2929486..2ccc890 100644 --- a/src/gtl.zig +++ b/src/gtl.zig @@ -11,10 +11,14 @@ const std = @import("std"); pub const log = @import("log.zig"); pub const ansi = @import("ansi.zig"); pub const Handle = @import("handle.zig").Handle; +pub const TypeID = @import("type_id.zig").of; + +// --- ARRAYS --- pub const SlotMap = @import("slot_map.zig").SlotMap; pub const KeyedSlotMap = @import("keyed_slot_map.zig").KeyedSlotMap; +pub const FixedArrayList = @import("fixed_array_list.zig").FixedArrayList; +pub const FixedSlotMap = @import("fixed_slot_map.zig").FixedSlotMap; pub const RingBuffer = @import("ring_buffer.zig").RingBuffer; -pub const TypeID = @import("type_id.zig").of; // // STRUCTS @@ -28,12 +32,6 @@ const GPUShader = struct { raw: *anyopaque }; const PipelineKey = struct { shader: ShaderID }; const GPUPipeline = struct { raw: *anyopaque }; -// --- MATERIAL --- -const MaterialDep = struct { - shader: ShaderID = .pbr, - albedo: @Vector(4, f32) = .{ 0, 0, 0, 1 }, -}; - /// ---------------------------------------------------- /// ---------------------------------------------------- const Material = struct { @@ -170,10 +168,10 @@ test "SlotMap-DEP" { } } } +} - // - // RING BUFFER EXAMPLE - // +test "RingBuffer" { + std.debug.print("{s}━━━ RING BUFFER ━━━{s}\n", .{ ansi.blue, ansi.reset }); var prev_inputs: RingBuffer([]const u8, 256) = .{}; @@ -185,6 +183,36 @@ test "SlotMap-DEP" { var i: usize = 0; while (prev_inputs.pop()) |data| { defer i += 1; - log.debug("[{}][PreviousInputs] -> \"{s}\"", .{ i, data }, null); + std.debug.print("[{}][PreviousInputs] -> \"{s}\"\n", .{ i, data }); + } +} + +test "FixedArrayList" { + std.debug.print("{s}━━━ FIXED ARRAY LIST ━━━{s}\n", .{ ansi.blue, ansi.reset }); + + var entities: FixedArrayList(u32, 4) = .empty; + + try entities.append(1); + try entities.append(2); + try entities.append(3); + + if (entities.getPtr(0)) |v| v.* = 69; + + for (entities.items()) |item| { + std.debug.print("Entity: {}\n", .{item}); + } +} + +test "FixedSlotMap" { + std.debug.print("{s}━━━ FIXED SLOT MAP ━━━{s}\n", .{ ansi.blue, ansi.reset }); + + var materials: FixedSlotMap(Material, 3) = .empty; + + _ = try materials.put(.{}); + _ = try materials.put(.{}); + const handle = try materials.put(.{ .unique = .{ .topology = .line_list } }); + + if (materials.get(handle)) |v| { + std.debug.print("Material: {}\n", .{v.unique.topology}); } }