From 6dba1f1c8eee5e2f037c7ef216bc64423aef8e00 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Sun, 12 Feb 2017 17:22:35 -0500 Subject: slice and array re-work plus some misc. changes * `@truncate` builtin allows casting to the same size integer. It also performs two's complement casting between signed and unsigned integers. * The idiomatic way to convert between bytes and numbers is now `mem.readInt` and `mem.writeInt` instead of an unsafe cast. It works at compile time, is safer, and looks cleaner. * Implicitly casting an array to a slice is allowed only if the slice is const. * Constant pointer values know if their memory is from a compile- time constant value or a compile-time variable. * Cast from [N]u8 to []T no longer allowed, but [N]u8 to []const T still allowed. * Fix inability to pass a mutable pointer to comptime variable at compile-time to a function and have the function modify the memory pointed to by the pointer. * Add the `comptime T: type` parameter back to mem.eql. Prevents accidentally creating instantiations for arrays. --- std/mem.zig | 101 ++++++++++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 78 insertions(+), 23 deletions(-) (limited to 'std/mem.zig') diff --git a/std/mem.zig b/std/mem.zig index 45734ce869..dba0422081 100644 --- a/std/mem.zig +++ b/std/mem.zig @@ -68,50 +68,105 @@ pub fn cmp(comptime T: type, a: []const T, b: []const T) -> Cmp { return if (a.len > b.len) Cmp.Greater else if (a.len < b.len) Cmp.Less else Cmp.Equal; } -pub fn sliceAsInt(buf: []u8, is_be: bool, comptime T: type) -> T { - var result: T = undefined; - const result_slice = ([]u8)((&result)[0...1]); - set(u8, result_slice, 0); - const padding = @sizeOf(T) - buf.len; - - if (is_be == @compileVar("is_big_endian")) { - copy(u8, result_slice, buf); +/// Compares two slices and returns whether they are equal. +pub fn eql(comptime T: type, a: []const T, b: []const T) -> bool { + if (a.len != b.len) return false; + for (a) |item, index| { + if (b[index] != item) return false; + } + return true; +} + +/// Reads an integer from memory with size equal to bytes.len. +/// T specifies the return type, which must be large enough to store +/// the result. +pub fn readInt(bytes: []const u8, comptime T: type, big_endian: bool) -> T { + var result: T = 0; + if (big_endian) { + for (bytes) |b| { + result = (result << 8) | b; + } } else { - for (buf) |b, i| { - const index = result_slice.len - i - 1 - padding; - result_slice[index] = b; + for (bytes) |b, index| { + result = result | (T(b) << T(index * 8)); } } return result; } -/// Compares two slices and returns whether they are equal. -pub fn eql(a: var, b: var) -> bool { - if (a.len != b.len) return false; - for (a) |item, index| { - if (b[index] != item) return false; +/// Writes an integer to memory with size equal to bytes.len. Pads with zeroes +/// to fill the entire buffer provided. +/// value must be an integer. +pub fn writeInt(buf: []u8, value: var, big_endian: bool) { + const uint = @intType(false, @typeOf(value).bit_count); + var bits = @truncate(uint, value); + if (big_endian) { + var index: usize = buf.len; + while (index != 0) { + index -= 1; + + buf[index] = @truncate(u8, bits); + bits >>= 8; + } + } else { + for (buf) |*b| { + *b = @truncate(u8, bits); + bits >>= 8; + } } - return true; + assert(bits == 0); } fn testStringEquality() { @setFnTest(this); - assert(eql("abcd", "abcd")); - assert(!eql("abcdef", "abZdef")); - assert(!eql("abcdefg", "abcdef")); + assert(eql(u8, "abcd", "abcd")); + assert(!eql(u8, "abcdef", "abZdef")); + assert(!eql(u8, "abcdefg", "abcdef")); } -fn testSliceAsInt() { +fn testReadInt() { @setFnTest(this); + + testReadIntImpl(); + comptime testReadIntImpl(); +} +fn testReadIntImpl() { + { + const bytes = []u8{ 0x12, 0x34, 0x56, 0x78 }; + assert(readInt(bytes, u32, true) == 0x12345678); + assert(readInt(bytes, u32, false) == 0x78563412); + } { const buf = []u8{0x00, 0x00, 0x12, 0x34}; - const answer = sliceAsInt(buf[0...], true, u64); + const answer = readInt(buf, u64, true); assert(answer == 0x00001234); } { const buf = []u8{0x12, 0x34, 0x00, 0x00}; - const answer = sliceAsInt(buf[0...], false, u64); + const answer = readInt(buf, u64, false); assert(answer == 0x00003412); } } + +fn testWriteInt() { + @setFnTest(this); + + testWriteIntImpl(); + comptime testWriteIntImpl(); +} +fn testWriteIntImpl() { + var bytes: [4]u8 = undefined; + + writeInt(bytes[0...], u32(0x12345678), true); + assert(eql(u8, bytes, []u8{ 0x12, 0x34, 0x56, 0x78 })); + + writeInt(bytes[0...], u32(0x78563412), false); + assert(eql(u8, bytes, []u8{ 0x12, 0x34, 0x56, 0x78 })); + + writeInt(bytes[0...], u16(0x1234), true); + assert(eql(u8, bytes, []u8{ 0x00, 0x00, 0x12, 0x34 })); + + writeInt(bytes[0...], u16(0x1234), false); + assert(eql(u8, bytes, []u8{ 0x34, 0x12, 0x00, 0x00 })); +} -- cgit v1.2.3