Add additional memory utils to core module

This commit is contained in:
kayomn 2022-10-27 16:51:11 +01:00
parent 7599ce61f2
commit b4816a34f6
1 changed files with 34 additions and 104 deletions

View File

@ -7,102 +7,6 @@ const std = @import("std");
///
pub const Allocator = std.mem.Allocator;
///
/// File-system agnostic abstraction for manipulating a file.
///
pub const FileAccess = struct {
context: *anyopaque,
implementation: *const Implementation,
///
/// Provides a set of implementation-specific behaviors to a [FileAccess] instance.
///
pub const Implementation = struct {
close: fn (*anyopaque) void,
queryCursor: fn (*anyopaque) Error!u64,
queryLength: fn (*anyopaque) Error!u64,
read: fn (*anyopaque, []u8) Error!usize,
seek: fn (*anyopaque, u64) Error!void,
seekToEnd: fn (*anyopaque) Error!void,
skip: fn (*anyopaque, i64) Error!void,
};
///
/// [Error.FileInaccessible] is a generic catch-all for a [FileAccess] reference no longer
/// pointing to a file or the file becomming invalid for whatever reason.
///
pub const Error = error {
FileInaccessible,
};
///
/// Close the file referenced by `file_access` on the main thread, invalidating the reference to
/// it and releasing any associated resources.
///
/// Freeing an invalid `file_access` has no effect on the file and logs a warning over the
/// wasted effort.
///
pub fn close(file_access: FileAccess) void {
return file_access.implementation.close(file_access.context);
}
///
/// Attempts to query the current cursor position for the file referenced by `file_access`.
///
/// Returns the number of bytes into the file that the cursor is relative to its beginning or a
/// [Error] on failure.
///
pub fn queryCursor(file_access: FileAccess) Error!u64 {
return file_access.implementation.queryCursor(file_access.context);
}
///
/// Attempts to query the current length for the file referenced by `file_access`.
///
/// Returns the current length of the file at the time of the operation or a [Error] if the file
/// failed to be queried.
///
pub fn queryLength(file_access: FileAccess) Error!u64 {
return file_access.implementation.queryLength(file_access.context);
}
///
/// Attempts to read `file_access` from the its current position into `buffer`.
///
/// Returns the number of bytes that were available to be read, otherwise an [Error] on failure.
///
pub fn read(file_access: FileAccess, buffer: []u8) Error!usize {
return file_access.implementation.read(file_access.context, buffer);
}
///
/// Attempts to seek `file_access` from the beginning of the file to `cursor` bytes.
///
/// Returns [Error] on failure.
///
pub fn seek(file_access: FileAccess, cursor: u64) Error!void {
return file_access.implementation.seek(file_access.context, cursor);
}
///
/// Attempts to seek `file_access` to the end of the file.
///
/// Returns [Error] on failure.
///
pub fn seekToEnd(file_access: FileAccess) Error!void {
return file_access.implementation.seekToEnd(file_access.context);
}
///
/// Attempts to seek `file_access` by `offset` from the current file position.
///
/// Returns [Error] on failure;
///
pub fn skip(file_access: FileAccess, offset: i64) Error!void {
return file_access.implementation.skip(file_access.context, offset);
}
};
///
/// Closure that captures a reference to readable resources like block devices, memory buffers,
/// network sockets, and more.
@ -161,7 +65,7 @@ test "Spliterating text" {
var index = @as(usize, 0);
while (spliterator.next()) |split| : (index += 1) {
try testing.expect(std.mem.eql(u8, split, components[index]));
try testing.expect(equals(u8, split, components[index]));
}
}
@ -176,7 +80,7 @@ test "Spliterating text" {
var index = @as(usize, 0);
while (spliterator.next()) |split| : (index += 1) {
try testing.expect(std.mem.eql(u8, split, components[index]));
try testing.expect(equals(u8, split, components[index]));
}
}
}
@ -209,7 +113,7 @@ test "Check memory begins with" {
///
/// **Note** that passing a slice will convert it to a byte slice.
///
pub fn bytes(pointer: anytype) switch (@typeInfo(@TypeOf(pointer))) {
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"),
} {
@ -233,7 +137,35 @@ test "Bytes of types" {
var foo: u32 = 10;
testing.expectEqual(bytes(&foo), 0x0a);
testing.expectEqual(bytesOf(&foo), 0x0a);
}
///
/// Compares `this` to `that`, returning the difference between the first byte deviation in the two
/// sequences, otherwise `0` if they are identical.
///
pub fn compareBytes(this: []const u8, that: []const u8) isize {
var cursor: usize = 0;
while (cursor != this.len) : (cursor += 1) {
const this_byte = this[cursor];
if (cursor != that.len) return this_byte;
const that_byte = that[cursor];
if (this_byte != that_byte) return (this_byte - that_byte);
}
return 0;
}
test "Compare bytes" {
const testing = std.testing;
try testing.expectEquals(compareBytes(&.{69, 42, 0}, &.{69, 42, 0}), 0);
try testing.expectEquals(compareBytes(&.{69, 42, 0}, &.{69, 42}), 42);
try testing.expectEquals(compareBytes(&.{69, 42}, &.{69, 42, 0}), -42);
}
///
@ -243,11 +175,9 @@ test "Bytes of types" {
pub fn equals(comptime Element: type, this: []const Element, that: []const Element) bool {
if (this.len != that.len) return false;
{
var i = std.mem.zeroes(usize);
var i = std.mem.zeroes(usize);
while (i < this.len) : (i += 1) if (this[i] != that[i]) return false;
}
while (i < this.len) : (i += 1) if (this[i] != that[i]) return false;
return true;
}