Add more test coverage and clean up code
This commit is contained in:
		
							parent
							
								
									9251b11427
								
							
						
					
					
						commit
						4bb86c41bc
					
				| @ -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; | ||||||
| 
 | 
 | ||||||
| /// | /// | ||||||
| /// 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; | ||||||
| @ -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,19 +65,19 @@ 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); |  | ||||||
|             const is_signed = (int_info.signedness == .signed); |  | ||||||
| 
 |  | ||||||
|             var buffer = [_]u8{0} ** (math.ceil(math.log(math. |  | ||||||
|                 maxInt(Int), base)) + @boolToInt(is_signed)); |  | ||||||
| 
 | 
 | ||||||
|  |                 if (writer.call(zero) != zero.len) return error.WriteFailure; | ||||||
|  |             } 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 buffer_count: usize = 0; | ||||||
|                 var n1 = value; |                 var n1 = value; | ||||||
| 
 | 
 | ||||||
|             if (is_signed and (value < 0)) { |                 if (info.signedness == .signed and value < 0) { | ||||||
|                     // Negative value. |                     // Negative value. | ||||||
|                     n1 = -value; |                     n1 = -value; | ||||||
|                     buffer[0] = '-'; |                     buffer[0] = '-'; | ||||||
| @ -60,6 +85,8 @@ pub fn printInt(writer: io.Writer, radix: Radix, value: anytype) PrintError!void | |||||||
|                 } |                 } | ||||||
| 
 | 
 | ||||||
|                 while (n1 != 0) { |                 while (n1 != 0) { | ||||||
|  |                     const base = radix.base(); | ||||||
|  | 
 | ||||||
|                     buffer[buffer_count] = @intCast(u8, (n1 % base) + '0'); |                     buffer[buffer_count] = @intCast(u8, (n1 % base) + '0'); | ||||||
|                     n1 = (n1 / base); |                     n1 = (n1 / base); | ||||||
|                     buffer_count += 1; |                     buffer_count += 1; | ||||||
| @ -68,7 +95,9 @@ pub fn printInt(writer: io.Writer, radix: Radix, value: anytype) PrintError!void | |||||||
|                 for (buffer[0 .. (buffer_count / 2)]) |_, i| |                 for (buffer[0 .. (buffer_count / 2)]) |_, i| | ||||||
|                     io.swap(u8, &buffer[i], &buffer[buffer_count - i - 1]); |                     io.swap(u8, &buffer[i], &buffer[buffer_count - i - 1]); | ||||||
| 
 | 
 | ||||||
|             if (writer.call(buffer[0 .. buffer_count]) != buffer_count) return error.WriteFailure; |                 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…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user