diff --git a/src/core/io.zig b/src/core/io.zig index 11b7ed1..79b4b73 100644 --- a/src/core/io.zig +++ b/src/core/io.zig @@ -151,8 +151,6 @@ pub const Writer = meta.Function([]const u8, usize); /// /// Returns a sliced reference of the raw bytes in `pointer`. /// -/// **Note** that passing a slice will convert it to a byte slice. -/// pub fn bytesOf(pointer: anytype) switch (@typeInfo(@TypeOf(pointer))) { .Pointer => |info| if (info.is_const) []const u8 else []u8, else => @compileError("`pointer` must be a pointer type"), @@ -254,8 +252,10 @@ test "fill" { } /// -/// Searches for the first instance of an `Element` equal to `needle` in `haystack`, returning its -/// index or `null` if nothing was found. +/// Linearly searches for the first instance of an `Element` equal to `needle` in `haystack`, +/// returning its index or `null` if nothing was found. +/// +/// **Note** that this operation has `O(n)` time complexity. /// pub fn findFirst(comptime Element: type, haystack: []const Element, needle: Element, comptime testEquality: fn (Element, Element) bool) ?usize { @@ -282,6 +282,8 @@ test "findFirst" { /// Searches for the first instance of an `Element` sequence equal to the contents of `needle` in /// `haystack`, returning the starting index or `null` if nothing was found. /// +/// **Note** that this operation has `O(nm)` time complexity. +/// pub fn findFirstOf(comptime Element: type, haystack: []const Element, needle: []const Element, comptime testEquality: fn (Element, Element) bool) ?usize { diff --git a/src/core/math.zig b/src/core/math.zig index 52c74a5..733a9dc 100644 --- a/src/core/math.zig +++ b/src/core/math.zig @@ -1,6 +1,7 @@ const std = @import("std"); const testing = @import("./testing.zig"); +// TODO: Remove stdlib dependency. pub const IntFittingRange = std.math.IntFittingRange; /// diff --git a/src/core/stack.zig b/src/core/stack.zig index c83b35a..609d66c 100755 --- a/src/core/stack.zig +++ b/src/core/stack.zig @@ -46,22 +46,23 @@ pub fn Fixed(comptime Element: type) type { } /// - /// Attempts to push `element` into `self`, returning a [PushError] if it failed. + /// Attempts to push `element` into `self`, returning a [FixedPushError] if it failed. /// - pub fn push(self: *Self, element: Element) PushError!void { - if (self.isFull()) return error.OutOfMemory; + pub fn push(self: *Self, element: Element) FixedPushError!void { + if (self.isFull()) return error.BufferOverflow; self.buffer[self.filled] = element; self.filled += 1; } /// - /// Attempts to push all of `elements` into `self`, returning a [PushError] if it failed. + /// Attempts to push all of `elements` into `self`, returning a [FixedPushError] if it + /// failed. /// - pub fn pushAll(self: *Self, elements: []const Element) PushError!void { + pub fn pushAll(self: *Self, elements: []const Element) FixedPushError!void { const filled = (self.filled + elements.len); - if (filled > self.buffer.len) return error.OutOfMemory; + if (filled > self.buffer.len) return error.BufferOverflow; io.copy(Element, self.buffer[self.filled ..], elements); @@ -69,13 +70,13 @@ pub fn Fixed(comptime Element: type) type { } /// - /// Attempts to push `count` instances of `element` into `self`, returning a [PushError] if - /// it failed. + /// Attempts to push `count` instances of `element` into `self`, returning a + /// [FixedPushError] if it failed. /// - pub fn pushMany(self: *Self, element: Element, count: usize) PushError!void { + pub fn pushMany(self: *Self, element: Element, count: usize) FixedPushError!void { const filled = (self.filled + count); - if (filled > self.buffer.len) return error.OutOfMemory; + if (filled > self.buffer.len) return error.BufferOverflow; io.fill(Element, self.buffer[self.filled ..], element); @@ -131,9 +132,11 @@ test "Fixed([]const u8)" { } /// -/// Potential errors that may occur while trying to push one or more elements into a stack. +/// Potential errors that may occur while trying to push one or more elements into a [Fixed] stack. /// -pub const PushError = io.MakeError; +pub const FixedPushError = error { + BufferOverflow, +}; /// /// Creates and returns a [io.Allocator] value wrapping `fixed_stack`. @@ -154,8 +157,10 @@ pub fn fixedAllocator(fixed_stack: *Fixed(u8)) io.Allocator { if (buffer_address < stack_address or buffer_address >= (stack_address + stack.filled)) return buffer; - // TODO: Investigate ways of freeing if it is the last allocation. + // TODO: Investigate ways of actually freeing if it is the last allocation. return null; + } else { + // TODO: Investigate ways of in-place relocating if it is the last allocation. }; // Reallocate / allocate the memory. @@ -232,7 +237,7 @@ pub fn fixedWriter(fixed_stack: *Fixed(u8)) io.Writer { return io.Writer.fromClosure(fixed_stack, struct { fn write(stack: *Fixed(u8), buffer: []const u8) usize { stack.pushAll(buffer) catch |err| switch (err) { - error.OutOfMemory => return 0, + error.BufferOverflow => return 0, }; return buffer.len; diff --git a/src/core/table.zig b/src/core/table.zig index 1458060..8cfb978 100644 --- a/src/core/table.zig +++ b/src/core/table.zig @@ -97,7 +97,7 @@ pub fn Hashed(comptime Key: type, comptime Value: type, /// [InsertError] if it fails. /// pub fn insert(self: *Self, key: Key, value: Value) InsertError!void { - if (self.loadFactor() >= self.load_limit) { + if (self.isOverloaded()) { const old_buckets = self.buckets; defer io.free(self.allocator, old_buckets); @@ -131,17 +131,18 @@ pub fn Hashed(comptime Key: type, comptime Value: type, } /// - /// Returns the current load factor of `self`, which is derived from the number of capacity - /// that has been filled. + /// Returns `true` if the current load factor, derived from the number of elements filling + /// the bucket table, is greater than the current load limit. /// - pub fn loadFactor(self: Self) f32 { - return @intToFloat(f32, self.filled) / @intToFloat(f32, self.buckets.len); + pub fn isOverloaded(self: Self) bool { + return (@intToFloat(f32, self.filled) / + @intToFloat(f32, self.buckets.len)) >= self.load_limit; } /// /// Searches for a value indexed with `key` in `self`. /// - /// The found value is returned or `null` if an key matching `key` failed to be found. + /// The found value is returned or `null` if any key matching `key` failed to be found. /// pub fn lookup(self: Self, key: Key) ?Value { var bucket = &(self.buckets[@mod(key_context.hash(key), self.buckets.len)]); diff --git a/src/ona/main.zig b/src/ona/main.zig index e8e8718..0045c34 100644 --- a/src/ona/main.zig +++ b/src/ona/main.zig @@ -3,13 +3,16 @@ const std = @import("std"); const sys = @import("./sys.zig"); /// -/// Starts the the game engine. +/// Application entry-point. /// pub fn main() anyerror!void { - return nosuspend await async sys.display(anyerror, run); + return nosuspend await async sys.display(anyerror, runEngine); } -fn run(app: *sys.App, graphics: *sys.Graphics) anyerror!void { +/// +/// Runs the game engine. +/// +fn runEngine(app: *sys.App, graphics: *sys.Graphics) anyerror!void { var gpa = std.heap.GeneralPurposeAllocator(.{}){}; defer _ = gpa.deinit(); diff --git a/src/ona/oar.zig b/src/ona/oar.zig index 16feb84..05ee2df 100644 --- a/src/ona/oar.zig +++ b/src/ona/oar.zig @@ -6,7 +6,6 @@ const sys = @import("./sys.zig"); /// const Block = extern struct { signature: [signature_magic.len]u8 = signature_magic, - revision: u8 = 0, path: sys.Path = sys.Path.empty, data_size: u64 = 0, data_head: u64 = 0, @@ -15,19 +14,23 @@ const Block = extern struct { comptime { const entry_size = @sizeOf(@This()); - if (entry_size != 512) @compileError("EntryBlock is greater than 512 bytes"); + if (entry_size != 512) @compileError("EntryBlock is not 512 bytes"); } }; /// -/// +/// Reference to a file entry in an Oar archive, denoting the starting offset from the top of head +/// of the file and its size. /// pub const Entry = struct { head: u64, size: u64, /// + /// [FindError.EntryNotFound] occurs when no entry matched the parameters of the find operation. /// + /// [FindError.ArchiveUnsupported] occurs if the file provided to the find operation is not a + /// valid archive file. /// pub const FindError = error { EntryNotFound, @@ -35,7 +38,11 @@ pub const Entry = struct { }; /// + /// Attempts to perform a binary search on the entry blocks defined in `archive_file` for one + /// matching `entry_path`, returning an [Entry] referencing its data or a [FindError] if it + /// failed. /// + /// **Note** that this operation has `O(log n)` time complexity. /// pub fn find(archive_file: *sys.ReadableFile, entry_path: sys.Path) FindError!Entry { var header = Header{}; @@ -78,7 +85,11 @@ pub const Entry = struct { } /// + /// Reads the data from `entry` in `archive_file` from the byte at the entry-relative `offset` + /// into `buffer` until either the end of the entry data, end of archive file, or end of buffer + /// is reached. /// + /// The number of bytes read is returned or [sys.FileError] if it failed. /// pub fn read(entry: Entry, archive_file: *sys.ReadableFile, offset: u64, buffer: []u8) sys.FileError!usize { @@ -89,7 +100,7 @@ pub const Entry = struct { }; /// -/// +/// Header data that every Oar archive file starts with at byte offset `0`. /// const Header = extern struct { signature: [signature_magic.len]u8 = signature_magic, @@ -101,16 +112,16 @@ const Header = extern struct { comptime { const size = @sizeOf(@This()); - if (size != 512) @compileError("Header is greater than 512 bytes"); + if (size != 512) @compileError("Header is not 512 bytes"); } }; /// -/// +/// The magic revision number that this Oar software implementation understands. /// const revision_magic = 0; /// -/// Magic identifier used to validate [Entry] data. +/// Magic identifier used to validate [Header] and [Block] data. /// const signature_magic = [3]u8{'o', 'a', 'r'};