Application Context Implementation #4

Closed
kayomn wants to merge 93 commits from event-loop-dev into main
6 changed files with 57 additions and 34 deletions
Showing only changes of commit 4f0224a029 - Show all commits

View File

@ -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 {

View File

@ -1,6 +1,7 @@
const std = @import("std");
const testing = @import("./testing.zig");
// TODO: Remove stdlib dependency.
pub const IntFittingRange = std.math.IntFittingRange;
///

View File

@ -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;

View File

@ -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)]);

View File

@ -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();

View File

@ -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'};