Application Context Implementation #4
|
@ -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 {
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
const std = @import("std");
|
||||
const testing = @import("./testing.zig");
|
||||
|
||||
// TODO: Remove stdlib dependency.
|
||||
pub const IntFittingRange = std.math.IntFittingRange;
|
||||
|
||||
///
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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)]);
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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'};
|
||||
|
|
Loading…
Reference in New Issue