Application Context Implementation #4
|
@ -13,7 +13,7 @@ pub const Allocation = struct {
|
||||||
};
|
};
|
||||||
|
|
||||||
///
|
///
|
||||||
/// Dynamic memory allocation interface.
|
/// Closure for dynamic memory allocation through the referenced allocator state machine capture.
|
||||||
///
|
///
|
||||||
pub const Allocator = meta.Function(Allocation, ?[*]u8);
|
pub const Allocator = meta.Function(Allocation, ?[*]u8);
|
||||||
|
|
||||||
|
@ -78,7 +78,7 @@ pub fn Spliterator(comptime Element: type) type {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
test "Spliterator of string literals" {
|
test "Spliterator(u8)" {
|
||||||
// Empty source.
|
// Empty source.
|
||||||
{
|
{
|
||||||
var spliterator = Spliterator(u8){
|
var spliterator = Spliterator(u8){
|
||||||
|
@ -172,7 +172,7 @@ pub fn bytesOf(pointer: anytype) switch (@typeInfo(@TypeOf(pointer))) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
test "Bytes of types" {
|
test "bytesOf" {
|
||||||
var foo: u32 = 10;
|
var foo: u32 = 10;
|
||||||
|
|
||||||
try testing.expect(bytesOf(&foo)[0] == 0x0a);
|
try testing.expect(bytesOf(&foo)[0] == 0x0a);
|
||||||
|
@ -195,7 +195,7 @@ pub fn compareBytes(this: []const u8, that: []const u8) isize {
|
||||||
return (@intCast(isize, this.len) - @intCast(isize, that.len));
|
return (@intCast(isize, this.len) - @intCast(isize, that.len));
|
||||||
}
|
}
|
||||||
|
|
||||||
test "Compare bytes" {
|
test "compareBytes" {
|
||||||
try testing.expect(compareBytes(&.{69, 42, 0}, &.{69, 42, 0}) == 0);
|
try testing.expect(compareBytes(&.{69, 42, 0}, &.{69, 42, 0}) == 0);
|
||||||
try testing.expect(compareBytes(&.{69, 42, 11}, &.{69, 42}) == 1);
|
try testing.expect(compareBytes(&.{69, 42, 11}, &.{69, 42}) == 1);
|
||||||
try testing.expect(compareBytes(&.{69, 42}, &.{69, 42, 11}) == -1);
|
try testing.expect(compareBytes(&.{69, 42}, &.{69, 42, 11}) == -1);
|
||||||
|
@ -208,7 +208,7 @@ pub fn copy(comptime Element: type, target: []Element, source: []const Element)
|
||||||
for (source) |element, index| target[index] = element;
|
for (source) |element, index| target[index] = element;
|
||||||
}
|
}
|
||||||
|
|
||||||
test "Copy data" {
|
test "copy" {
|
||||||
var buffer = [_]u32{0} ** 20;
|
var buffer = [_]u32{0} ** 20;
|
||||||
const data = [_]u32{3, 20, 8000};
|
const data = [_]u32{3, 20, 8000};
|
||||||
|
|
||||||
|
@ -231,7 +231,7 @@ pub fn equals(comptime Element: type, this: []const Element, that: []const Eleme
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
test "Check memory is equal" {
|
test "equals" {
|
||||||
const bytes_sequence = &.{69, 42, 0};
|
const bytes_sequence = &.{69, 42, 0};
|
||||||
|
|
||||||
try testing.expect(equals(u8, bytes_sequence, bytes_sequence));
|
try testing.expect(equals(u8, bytes_sequence, bytes_sequence));
|
||||||
|
@ -245,7 +245,7 @@ pub fn fill(comptime Element: type, target: []Element, source: Element) void {
|
||||||
for (target) |_, index| target[index] = source;
|
for (target) |_, index| target[index] = source;
|
||||||
}
|
}
|
||||||
|
|
||||||
test "Fill data" {
|
test "fill" {
|
||||||
var buffer = [_]u32{0} ** 8;
|
var buffer = [_]u32{0} ** 8;
|
||||||
|
|
||||||
fill(u32, &buffer, 1);
|
fill(u32, &buffer, 1);
|
||||||
|
@ -265,7 +265,7 @@ pub fn findFirst(comptime Element: type, haystack: []const Element,
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
test "Find first of element" {
|
test "findFirst" {
|
||||||
const haystack = &.{"", "", "foo"};
|
const haystack = &.{"", "", "foo"};
|
||||||
|
|
||||||
const testEquality = struct {
|
const testEquality = struct {
|
||||||
|
@ -298,7 +298,7 @@ pub fn findFirstOf(comptime Element: type, haystack: []const Element,
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
test "Find first of sequence" {
|
test "findFirstOf" {
|
||||||
const haystack = &.{"foo", "bar", "baz"};
|
const haystack = &.{"foo", "bar", "baz"};
|
||||||
|
|
||||||
const testEquality = struct {
|
const testEquality = struct {
|
||||||
|
@ -333,6 +333,16 @@ pub fn free(allocator: Allocator, allocated_memory: anytype) void {
|
||||||
}) != null) unreachable;
|
}) != null) unreachable;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
test "free" {
|
||||||
|
var buffer = [_]u8{0} ** 4096;
|
||||||
|
var memory = stack.Fixed(u8){.buffer = &buffer};
|
||||||
|
const fixed_allocator = stack.fixedAllocator(&memory);
|
||||||
|
const block_size = 8;
|
||||||
|
const allocated_block = (try makeMany(u8, fixed_allocator, block_size))[0 .. block_size];
|
||||||
|
|
||||||
|
defer free(fixed_allocator, allocated_block);
|
||||||
|
}
|
||||||
|
|
||||||
///
|
///
|
||||||
/// Returns a deterministic hash code compiled from each byte in `bytes`.
|
/// Returns a deterministic hash code compiled from each byte in `bytes`.
|
||||||
///
|
///
|
||||||
|
@ -346,7 +356,7 @@ pub fn hashBytes(bytes: []const u8) usize {
|
||||||
return hash;
|
return hash;
|
||||||
}
|
}
|
||||||
|
|
||||||
test "Hashing bytes" {
|
test "hashBytes" {
|
||||||
const bytes_sequence = &.{69, 42, 0};
|
const bytes_sequence = &.{69, 42, 0};
|
||||||
|
|
||||||
try testing.expect(hashBytes(bytes_sequence) == hashBytes(bytes_sequence));
|
try testing.expect(hashBytes(bytes_sequence) == hashBytes(bytes_sequence));
|
||||||
|
@ -360,15 +370,42 @@ test "Hashing bytes" {
|
||||||
pub fn makeMany(comptime Element: type, allocator: Allocator, size: usize) MakeError![*]Element {
|
pub fn makeMany(comptime Element: type, allocator: Allocator, size: usize) MakeError![*]Element {
|
||||||
const alignment = @alignOf(Element);
|
const alignment = @alignOf(Element);
|
||||||
|
|
||||||
if (allocator.call(.{
|
return @ptrCast([*]Element, @alignCast(alignment, allocator.call(.{
|
||||||
.existing = null,
|
.existing = null,
|
||||||
.size = @sizeOf(Element) * size,
|
.size = @sizeOf(Element) * size,
|
||||||
.alignment = alignment,
|
.alignment = alignment,
|
||||||
})) |buffer| {
|
}) orelse return error.OutOfMemory));
|
||||||
return @ptrCast([*]Element, @alignCast(alignment, buffer));
|
}
|
||||||
}
|
|
||||||
|
|
||||||
return error.OutOfMemory;
|
test "makeMany" {
|
||||||
|
var buffer = [_]u8{0} ** 4096;
|
||||||
|
var memory = stack.Fixed(u8){.buffer = &buffer};
|
||||||
|
const block_size = 8;
|
||||||
|
|
||||||
|
// Don't care about the actual allocation - just assertions about it.
|
||||||
|
_ = (try makeMany(u8, stack.fixedAllocator(&memory), block_size))[0 .. block_size];
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Attempts to allocate a buffer of `1` `Element` using `allocator`, returning it or a [MakeError]
|
||||||
|
/// if it failed.
|
||||||
|
///
|
||||||
|
pub fn makeOne(comptime Element: type, allocator: Allocator) MakeError!*Element {
|
||||||
|
const alignment = @alignOf(Element);
|
||||||
|
|
||||||
|
return @ptrCast(*Element, @alignCast(alignment, allocator.call(.{
|
||||||
|
.existing = null,
|
||||||
|
.size = @sizeOf(Element),
|
||||||
|
.alignment = alignment,
|
||||||
|
}) orelse return error.OutOfMemory));
|
||||||
|
}
|
||||||
|
|
||||||
|
test "makeOne" {
|
||||||
|
var buffer = [_]u8{0} ** 4096;
|
||||||
|
var memory = stack.Fixed(u8){.buffer = &buffer};
|
||||||
|
|
||||||
|
// Don't care about the actual allocation - just assertions about it.
|
||||||
|
_ = try makeOne(u8, stack.fixedAllocator(&memory));
|
||||||
}
|
}
|
||||||
|
|
||||||
///
|
///
|
||||||
|
@ -380,7 +417,7 @@ pub fn swap(comptime Data: type, this: *Data, that: *Data) void {
|
||||||
that.* = temp;
|
that.* = temp;
|
||||||
}
|
}
|
||||||
|
|
||||||
test "Data swapping" {
|
test "swap" {
|
||||||
var a: u64 = 0;
|
var a: u64 = 0;
|
||||||
var b: u64 = 1;
|
var b: u64 = 1;
|
||||||
|
|
||||||
|
@ -403,7 +440,7 @@ pub const null_writer = Writer.from(struct {
|
||||||
}
|
}
|
||||||
}.write);
|
}.write);
|
||||||
|
|
||||||
test "Null writing" {
|
test "null_writer" {
|
||||||
const sequence = "foo";
|
const sequence = "foo";
|
||||||
|
|
||||||
try testing.expect(null_writer.call(sequence) == sequence.len);
|
try testing.expect(null_writer.call(sequence) == sequence.len);
|
||||||
|
|
|
@ -1,10 +1,12 @@
|
||||||
|
const std = @import("std");
|
||||||
|
const testing = @import("./testing.zig");
|
||||||
|
|
||||||
pub const IntFittingRange = @import("std").math.IntFittingRange;
|
pub const IntFittingRange = std.math.IntFittingRange;
|
||||||
kayomn marked this conversation as resolved
Outdated
|
|||||||
|
|
||||||
///
|
///
|
||||||
/// Returns the maximum value of `Integer`.
|
/// Returns the highest integer value representable by `Integer`.
|
||||||
///
|
///
|
||||||
pub fn maxInt(comptime Integer: type) comptime_int {
|
pub fn maxIntValue(comptime Integer: type) comptime_int {
|
||||||
return switch (@typeInfo(Integer)) {
|
return switch (@typeInfo(Integer)) {
|
||||||
.Int => |info| if (info.bits == 0) 0 else
|
.Int => |info| if (info.bits == 0) 0 else
|
||||||
((1 << (info.bits - @boolToInt(info.signedness == .signed))) - 1),
|
((1 << (info.bits - @boolToInt(info.signedness == .signed))) - 1),
|
||||||
|
@ -13,6 +15,32 @@ pub fn maxInt(comptime Integer: type) comptime_int {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
test "maxIntValue" {
|
||||||
|
try testing.expect(maxIntValue(u8) == 255);
|
||||||
|
try testing.expect(maxIntValue(i8) == 127);
|
||||||
|
|
||||||
|
try testing.expect(maxIntValue(u16) == 65535);
|
||||||
|
try testing.expect(maxIntValue(i16) == 32767);
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Returns the highest `Number` value between `this` and `that`.
|
||||||
|
///
|
||||||
|
pub fn max(comptime Number: type, this: Number, that: Number) Number {
|
||||||
|
return switch (@typeInfo(Number)) {
|
||||||
|
.Int, .Float, .ComptimeInt, .ComptimeFloat => if (this > that) this else that,
|
||||||
|
|
||||||
|
else => @compileError("`" ++ @typeName(Number) ++
|
||||||
|
"` must be an int, float, comptime_int, or comptime_float"),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
test "max" {
|
||||||
|
try testing.expect(max(f32, 0.1, 1.0) == 1.0);
|
||||||
|
try testing.expect(max(f64, 1.0, 1.01) == 1.01);
|
||||||
|
try testing.expect(max(u32, 35615, 2873) == 35615);
|
||||||
|
}
|
||||||
|
|
||||||
///
|
///
|
||||||
/// Returns the lowest `Number` value between `this` and `that`.
|
/// Returns the lowest `Number` value between `this` and `that`.
|
||||||
///
|
///
|
||||||
|
@ -24,3 +52,9 @@ pub fn min(comptime Number: type, this: Number, that: Number) Number {
|
||||||
"` must be an int, float, comptime_int, or comptime_float"),
|
"` must be an int, float, comptime_int, or comptime_float"),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
test "min" {
|
||||||
|
try testing.expect(min(f32, 0.1, 1.0) == 0.1);
|
||||||
|
try testing.expect(min(f64, 1.0, 1.01) == 1.0);
|
||||||
|
try testing.expect(min(u32, 35615, 2873) == 2873);
|
||||||
|
}
|
||||||
|
|
|
@ -22,6 +22,13 @@ pub fn Fixed(comptime Element: type) type {
|
||||||
self.filled = 0;
|
self.filled = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Returns `true` if `self` has filled its buffer to maximum capacity, otherwise `false`.
|
||||||
|
///
|
||||||
|
pub fn isFull(self: Self) bool {
|
||||||
|
return (self.filled == self.buffer.len);
|
||||||
|
}
|
||||||
|
|
||||||
///
|
///
|
||||||
/// If `self` is filled with at least `1` value, it is decremented by `1`, otherwise leaving
|
/// If `self` is filled with at least `1` value, it is decremented by `1`, otherwise leaving
|
||||||
/// the actual memory contents of the buffer untouched until it is later overwritten by
|
/// the actual memory contents of the buffer untouched until it is later overwritten by
|
||||||
|
@ -42,7 +49,7 @@ 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 [PushError] if it failed.
|
||||||
///
|
///
|
||||||
pub fn push(self: *Self, element: Element) PushError!void {
|
pub fn push(self: *Self, element: Element) PushError!void {
|
||||||
if (self.filled == self.buffer.len) return error.OutOfMemory;
|
if (self.isFull()) return error.OutOfMemory;
|
||||||
|
|
||||||
self.buffer[self.filled] = element;
|
self.buffer[self.filled] = element;
|
||||||
self.filled += 1;
|
self.filled += 1;
|
||||||
|
@ -77,7 +84,7 @@ pub fn Fixed(comptime Element: type) type {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
test "Fixed stack of string literals" {
|
test "Fixed([]const u8)" {
|
||||||
const default_value = "";
|
const default_value = "";
|
||||||
var buffer = [_][]const u8{default_value} ** 4;
|
var buffer = [_][]const u8{default_value} ** 4;
|
||||||
var shopping_list = Fixed([]const u8){.buffer = &buffer};
|
var shopping_list = Fixed([]const u8){.buffer = &buffer};
|
||||||
|
@ -140,12 +147,12 @@ pub fn fixedAllocator(fixed_stack: *Fixed(u8)) io.Allocator {
|
||||||
if (allocation.existing) |buffer| if (allocation.size == 0) {
|
if (allocation.existing) |buffer| if (allocation.size == 0) {
|
||||||
// Deallocate the memory.
|
// Deallocate the memory.
|
||||||
const buffer_address = @ptrToInt(buffer);
|
const buffer_address = @ptrToInt(buffer);
|
||||||
const stack_buffer_address = @ptrToInt(stack.buffer.ptr);
|
const stack_address = @ptrToInt(stack.buffer.ptr);
|
||||||
|
|
||||||
// Check the buffer is within the address space of the stack buffer. If not, it
|
// Check the buffer is within the address space of the stack buffer. If not, it
|
||||||
// should just be returned to let the caller know it cannot be freed.
|
// should just be returned to let the caller know it cannot be freed.
|
||||||
if ((buffer_address < stack_buffer_address) or
|
if (buffer_address < stack_address or buffer_address >=
|
||||||
(buffer_address >= (stack_buffer_address + stack.filled))) return buffer;
|
(stack_address + stack.filled)) return buffer;
|
||||||
|
|
||||||
// TODO: Investigate ways of freeing if it is the last allocation.
|
// TODO: Investigate ways of freeing if it is the last allocation.
|
||||||
return null;
|
return null;
|
||||||
kayomn marked this conversation as resolved
Outdated
kayomn
commented
Reallocation could benefit from the same kind of last-alloc check optimization as deallocation. May be worth clarifying that in the comment and code structure. Reallocation could benefit from the same kind of last-alloc check optimization as deallocation.
May be worth clarifying that in the comment and code structure.
|
|||||||
|
@ -167,6 +174,54 @@ pub fn fixedAllocator(fixed_stack: *Fixed(u8)) io.Allocator {
|
||||||
}.alloc);
|
}.alloc);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
test "fixedAllocator" {
|
||||||
|
var buffer = [_]u8{0} ** 32;
|
||||||
|
var stack = Fixed(u8){.buffer = &buffer};
|
||||||
|
const allocator = fixedAllocator(&stack);
|
||||||
|
|
||||||
|
// Allocation
|
||||||
|
var block_memory = allocator.call(.{
|
||||||
|
.existing = null,
|
||||||
|
.alignment = @alignOf(u64),
|
||||||
|
.size = @sizeOf(u64),
|
||||||
|
});
|
||||||
|
|
||||||
|
try testing.expect(block_memory != null);
|
||||||
|
|
||||||
|
const buffer_address_head = @ptrToInt(&buffer);
|
||||||
|
const buffer_address_tail = @ptrToInt(&buffer) + buffer.len;
|
||||||
|
|
||||||
|
{
|
||||||
|
const block_memory_address = @ptrToInt(block_memory);
|
||||||
|
|
||||||
|
try testing.expect(block_memory_address >= buffer_address_head and
|
||||||
|
block_memory_address < buffer_address_tail);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reallocation.
|
||||||
|
block_memory = allocator.call(.{
|
||||||
|
.existing = block_memory,
|
||||||
|
.alignment = @alignOf(u64),
|
||||||
|
.size = @sizeOf(u64),
|
||||||
|
});
|
||||||
|
|
||||||
|
try testing.expect(block_memory != null);
|
||||||
|
|
||||||
|
{
|
||||||
|
const block_memory_address = @ptrToInt(block_memory);
|
||||||
|
|
||||||
|
try testing.expect(block_memory_address >= buffer_address_head and
|
||||||
|
block_memory_address < buffer_address_tail);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deallocation.
|
||||||
|
try testing.expect(allocator.call(.{
|
||||||
|
.existing = block_memory,
|
||||||
|
.alignment = 0,
|
||||||
|
.size = 0,
|
||||||
|
}) == null);
|
||||||
|
}
|
||||||
|
|
||||||
///
|
///
|
||||||
/// Returns an [io.Writer] wrapping `fixed_stack`.
|
/// Returns an [io.Writer] wrapping `fixed_stack`.
|
||||||
///
|
///
|
||||||
|
@ -185,7 +240,7 @@ pub fn fixedWriter(fixed_stack: *Fixed(u8)) io.Writer {
|
||||||
}.write);
|
}.write);
|
||||||
}
|
}
|
||||||
|
|
||||||
test "Fixed writer" {
|
test "fixedWriter" {
|
||||||
var buffer = [_]u8{0} ** 4;
|
var buffer = [_]u8{0} ** 4;
|
||||||
var sequence_stack = Fixed(u8){.buffer = &buffer};
|
var sequence_stack = Fixed(u8){.buffer = &buffer};
|
||||||
const sequence_data = [_]u8{8, 16, 32, 64};
|
const sequence_data = [_]u8{8, 16, 32, 64};
|
||||||
|
|
|
@ -197,12 +197,12 @@ pub const string_literal_context = KeyContext([]const u8){
|
||||||
}.stringsEqual,
|
}.stringsEqual,
|
||||||
};
|
};
|
||||||
|
|
||||||
test "Hash table manipulation with string literal context" {
|
test "Hashed([]const u8, u32, string_literal_context)" {
|
||||||
var buffer = [_]u8{0} ** 4096;
|
var buffer = [_]u8{0} ** 4096;
|
||||||
var fixed_stack = stack.Fixed(u8){.buffer = &buffer};
|
var memory = stack.Fixed(u8){.buffer = &buffer};
|
||||||
|
|
||||||
var table = try Hashed([]const u8, u32, string_literal_context).
|
var table = try Hashed([]const u8, u32, string_literal_context).
|
||||||
init(stack.fixedAllocator(&fixed_stack));
|
init(stack.fixedAllocator(&memory));
|
||||||
|
|
||||||
defer table.deinit();
|
defer table.deinit();
|
||||||
|
|
||||||
|
|
|
@ -13,6 +13,10 @@ pub fn expect(ok: bool) TestError!void {
|
||||||
if (!ok) return error.UnexpectedResult;
|
if (!ok) return error.UnexpectedResult;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Implement tests.
|
test "expect" {
|
||||||
|
try expect(true);
|
||||||
|
|
||||||
|
expect(false) catch {};
|
||||||
|
}
|
||||||
|
|
||||||
pub const expectError = @import("std").testing.expectError;
|
pub const expectError = @import("std").testing.expectError;
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
const io = @import("./io.zig");
|
const io = @import("./io.zig");
|
||||||
const math = @import("./math.zig");
|
const math = @import("./math.zig");
|
||||||
|
const stack = @import("./stack.zig");
|
||||||
|
const testing = @import("./testing.zig");
|
||||||
|
|
||||||
///
|
///
|
||||||
/// [PrintError.WriteFailure] occurs when the underlying [io.Writer] implementation failed to write
|
/// [PrintError.WriteFailure] occurs when the underlying [io.Writer] implementation failed to write
|
||||||
|
@ -10,7 +12,7 @@ pub const PrintError = error {
|
||||||
};
|
};
|
||||||
|
|
||||||
///
|
///
|
||||||
/// Number formatting modes supported by [printInt].
|
/// Named identifiers for number formats used in printing functions.
|
||||||
///
|
///
|
||||||
pub const Radix = enum {
|
pub const Radix = enum {
|
||||||
binary,
|
binary,
|
||||||
|
@ -28,6 +30,29 @@ pub const Radix = enum {
|
||||||
tetradecimal,
|
tetradecimal,
|
||||||
pentadecimal,
|
pentadecimal,
|
||||||
hexadecimal,
|
hexadecimal,
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Returns the base number of `radix`.
|
||||||
|
///
|
||||||
|
pub fn base(radix: Radix) u8 {
|
||||||
|
return switch (radix) {
|
||||||
|
.binary => 2,
|
||||||
|
.tinary => 3,
|
||||||
|
.quaternary => 4,
|
||||||
|
.quinary => 5,
|
||||||
|
.senary => 6,
|
||||||
|
.septenary => 7,
|
||||||
|
.octal => 8,
|
||||||
|
.nonary => 9,
|
||||||
|
.decimal => 10,
|
||||||
|
.undecimal => 11,
|
||||||
|
.duodecimal => 12,
|
||||||
|
.tridecimal => 13,
|
||||||
|
.tetradecimal => 14,
|
||||||
|
.pentadecimal => 15,
|
||||||
|
.hexadecimal => 16,
|
||||||
|
};
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
///
|
///
|
||||||
|
@ -40,35 +65,39 @@ pub fn printInt(writer: io.Writer, radix: Radix, value: anytype) PrintError!void
|
||||||
const Int = @TypeOf(value);
|
const Int = @TypeOf(value);
|
||||||
|
|
||||||
switch (@typeInfo(Int)) {
|
switch (@typeInfo(Int)) {
|
||||||
.Int => |int_info| {
|
.Int => |info| {
|
||||||
if (value == 0) return writer.apply("0");
|
if (value == 0) {
|
||||||
|
const zero = "0";
|
||||||
|
|
||||||
const base = @enumToInt(radix);
|
if (writer.call(zero) != zero.len) return error.WriteFailure;
|
||||||
const is_signed = (int_info.signedness == .signed);
|
} else {
|
||||||
|
// Big enough to hold the hexadecimal representation of the integer type, which is
|
||||||
|
// the largest number format accomodated for in [Radix].
|
||||||
|
var buffer = [_]u8{0} ** (@sizeOf(Int) * (@bitSizeOf(u8) / 4));
|
||||||
|
var buffer_count: usize = 0;
|
||||||
|
var n1 = value;
|
||||||
|
|
||||||
var buffer = [_]u8{0} ** (math.ceil(math.log(math.
|
if (info.signedness == .signed and value < 0) {
|
||||||
maxInt(Int), base)) + @boolToInt(is_signed));
|
// Negative value.
|
||||||
|
n1 = -value;
|
||||||
|
buffer[0] = '-';
|
||||||
|
buffer_count += 1;
|
||||||
|
}
|
||||||
|
|
||||||
var buffer_count: usize = 0;
|
while (n1 != 0) {
|
||||||
var n1 = value;
|
const base = radix.base();
|
||||||
|
|
||||||
if (is_signed and (value < 0)) {
|
buffer[buffer_count] = @intCast(u8, (n1 % base) + '0');
|
||||||
// Negative value.
|
n1 = (n1 / base);
|
||||||
n1 = -value;
|
buffer_count += 1;
|
||||||
buffer[0] = '-';
|
}
|
||||||
buffer_count += 1;
|
|
||||||
|
for (buffer[0 .. (buffer_count / 2)]) |_, i|
|
||||||
|
io.swap(u8, &buffer[i], &buffer[buffer_count - i - 1]);
|
||||||
|
|
||||||
|
if (writer.call(buffer[0 .. buffer_count]) != buffer_count)
|
||||||
|
return error.WriteFailure;
|
||||||
}
|
}
|
||||||
|
|
||||||
while (n1 != 0) {
|
|
||||||
buffer[buffer_count] = @intCast(u8, (n1 % base) + '0');
|
|
||||||
n1 = (n1 / base);
|
|
||||||
buffer_count += 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (buffer[0 .. (buffer_count / 2)]) |_, i|
|
|
||||||
io.swap(u8, &buffer[i], &buffer[buffer_count - i - 1]);
|
|
||||||
|
|
||||||
if (writer.call(buffer[0 .. buffer_count]) != buffer_count) return error.WriteFailure;
|
|
||||||
},
|
},
|
||||||
|
|
||||||
// Cast comptime int into known-size integer and try again.
|
// Cast comptime int into known-size integer and try again.
|
||||||
|
@ -79,6 +108,12 @@ pub fn printInt(writer: io.Writer, radix: Radix, value: anytype) PrintError!void
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
test "Print 64-bit signed integer" {
|
test "printInt" {
|
||||||
// TODO: implement.
|
// Max digits to represent a decimal u8 is 3 (i.e. 127 / 255).
|
||||||
|
var decimal_buffer = [_]u8{0} ** 3;
|
||||||
|
var decimal_stack = stack.Fixed(u8){.buffer = &decimal_buffer};
|
||||||
|
var decimal_writer = stack.fixedWriter(&decimal_stack);
|
||||||
|
|
||||||
|
try printInt(decimal_writer, .decimal, 365);
|
||||||
|
try testing.expect(decimal_stack.isFull());
|
||||||
}
|
}
|
||||||
|
|
|
@ -114,7 +114,10 @@ pub const ReadableFile = opaque {
|
||||||
{
|
{
|
||||||
ext.SDL_ClearError();
|
ext.SDL_ClearError();
|
||||||
|
|
||||||
var sought = core.math.min(u64, offset, core.math.maxInt(i64));
|
const math = core.math;
|
||||||
|
const min = math.min;
|
||||||
|
const maxIntValue = math.maxIntValue;
|
||||||
|
var sought = min(u64, offset, maxIntValue(i64));
|
||||||
|
|
||||||
if (ext.SDL_RWseek(rw_ops, @intCast(i64, sought), ext.RW_SEEK_SET) < 0)
|
if (ext.SDL_RWseek(rw_ops, @intCast(i64, sought), ext.RW_SEEK_SET) < 0)
|
||||||
return error.FileInaccessible;
|
return error.FileInaccessible;
|
||||||
|
@ -122,7 +125,7 @@ pub const ReadableFile = opaque {
|
||||||
var to_seek = offset - sought;
|
var to_seek = offset - sought;
|
||||||
|
|
||||||
while (to_seek != 0) {
|
while (to_seek != 0) {
|
||||||
sought = core.math.min(u64, to_seek, core.math.maxInt(i64));
|
sought = min(u64, to_seek, maxIntValue(i64));
|
||||||
|
|
||||||
ext.SDL_ClearError();
|
ext.SDL_ClearError();
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Warrants
TODO
comment mentioning that this stdlib dependency should be removed in future.