Commit c586e3ba1b

Cody Tapscott <topolarity@tapscott.me>
2022-02-13 19:59:14
Add additional tests for `@bitCast`
1 parent 7b72fc6
Changed files (2)
lib
std
math
test
behavior
lib/std/math/big/int_test.zig
@@ -2550,6 +2550,43 @@ test "big int conversion read twos complement with padding" {
     try testing.expect(std.mem.eql(u8, buffer1, &[_]u8{ 0xff, 0xff, 0xff, 0xfe, 0xfd, 0xfc, 0xfb, 0xfa, 0xf9, 0xf8, 0xf7, 0xf6, 0xf5, 0xf4, 0xf3, 0xf3 }));
 }
 
+test "big int write twos complement +/- zero" {
+    var a = try Managed.initSet(testing.allocator, 0x0);
+    defer a.deinit();
+    var m = a.toMutable();
+
+    var buffer1 = try testing.allocator.alloc(u8, 16);
+    defer testing.allocator.free(buffer1);
+    @memset(buffer1.ptr, 0xaa, buffer1.len);
+
+    var bit_count: usize = 0;
+
+    // Test zero
+
+    m.toConst().writeTwosComplement(buffer1, bit_count, 13, .Little);
+    try testing.expect(std.mem.eql(u8, buffer1, &(([_]u8{0} ** 13) ++ ([_]u8{0xaa} ** 3))));
+    m.toConst().writeTwosComplement(buffer1, bit_count, 13, .Big);
+    try testing.expect(std.mem.eql(u8, buffer1, &(([_]u8{0} ** 13) ++ ([_]u8{0xaa} ** 3))));
+    m.toConst().writeTwosComplement(buffer1, bit_count, 16, .Little);
+    try testing.expect(std.mem.eql(u8, buffer1, &(([_]u8{0} ** 16))));
+    m.toConst().writeTwosComplement(buffer1, bit_count, 16, .Big);
+    try testing.expect(std.mem.eql(u8, buffer1, &(([_]u8{0} ** 16))));
+
+    @memset(buffer1.ptr, 0xaa, buffer1.len);
+    m.positive = false;
+
+    // Test negative zero
+
+    m.toConst().writeTwosComplement(buffer1, bit_count, 13, .Little);
+    try testing.expect(std.mem.eql(u8, buffer1, &(([_]u8{0} ** 13) ++ ([_]u8{0xaa} ** 3))));
+    m.toConst().writeTwosComplement(buffer1, bit_count, 13, .Big);
+    try testing.expect(std.mem.eql(u8, buffer1, &(([_]u8{0} ** 13) ++ ([_]u8{0xaa} ** 3))));
+    m.toConst().writeTwosComplement(buffer1, bit_count, 16, .Little);
+    try testing.expect(std.mem.eql(u8, buffer1, &(([_]u8{0} ** 16))));
+    m.toConst().writeTwosComplement(buffer1, bit_count, 16, .Big);
+    try testing.expect(std.mem.eql(u8, buffer1, &(([_]u8{0} ** 16))));
+}
+
 test "big int conversion write twos complement with padding" {
     var a = try Managed.initSet(testing.allocator, 0x01_ffffffff_ffffffff_ffffffff);
     defer a.deinit();
@@ -2564,6 +2601,8 @@ test "big int conversion write twos complement with padding" {
     var bit_count: usize = 12 * 8 + 1;
     var buffer: []const u8 = undefined;
 
+    // Test 0x01_02030405_06070809_0a0b0c0d
+
     buffer = &[_]u8{ 0xd, 0xc, 0xb, 0xa, 0x9, 0x8, 0x7, 0x6, 0x5, 0x4, 0x3, 0x2, 0xb };
     m.readTwosComplement(buffer, bit_count, 13, .Little, .unsigned);
     try testing.expect(m.toConst().orderAgainstScalar(0x01_02030405_06070809_0a0b0c0d) == .eq);
@@ -2582,6 +2621,8 @@ test "big int conversion write twos complement with padding" {
 
     bit_count = 12 * 8 + 2;
 
+    // Test -0x01_02030405_06070809_0a0b0c0d
+
     buffer = &[_]u8{ 0xf3, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0x02 };
     m.readTwosComplement(buffer, bit_count, 13, .Little, .signed);
     try testing.expect(m.toConst().orderAgainstScalar(-0x01_02030405_06070809_0a0b0c0d) == .eq);
@@ -2597,4 +2638,54 @@ test "big int conversion write twos complement with padding" {
     buffer = &[_]u8{ 0xaa, 0xaa, 0xaa, 0x02, 0xfd, 0xfc, 0xfb, 0xfa, 0xf9, 0xf8, 0xf7, 0xf6, 0xf5, 0xf4, 0xf3, 0xf3 };
     m.readTwosComplement(buffer, bit_count, 16, .Big, .signed);
     try testing.expect(m.toConst().orderAgainstScalar(-0x01_02030405_06070809_0a0b0c0d) == .eq);
+
+    // Test 0
+
+    buffer = &([_]u8{0} ** 16);
+    m.readTwosComplement(buffer, bit_count, 13, .Little, .unsigned);
+    try testing.expect(m.toConst().orderAgainstScalar(0x0) == .eq);
+    m.readTwosComplement(buffer, bit_count, 13, .Big, .unsigned);
+    try testing.expect(m.toConst().orderAgainstScalar(0x0) == .eq);
+    m.readTwosComplement(buffer, bit_count, 16, .Little, .unsigned);
+    try testing.expect(m.toConst().orderAgainstScalar(0x0) == .eq);
+    m.readTwosComplement(buffer, bit_count, 16, .Big, .unsigned);
+    try testing.expect(m.toConst().orderAgainstScalar(0x0) == .eq);
+
+    bit_count = 0;
+    buffer = &([_]u8{0xaa} ** 16);
+    m.readTwosComplement(buffer, bit_count, 13, .Little, .unsigned);
+    try testing.expect(m.toConst().orderAgainstScalar(0x0) == .eq);
+    m.readTwosComplement(buffer, bit_count, 13, .Big, .unsigned);
+    try testing.expect(m.toConst().orderAgainstScalar(0x0) == .eq);
+    m.readTwosComplement(buffer, bit_count, 16, .Little, .unsigned);
+    try testing.expect(m.toConst().orderAgainstScalar(0x0) == .eq);
+    m.readTwosComplement(buffer, bit_count, 16, .Big, .unsigned);
+    try testing.expect(m.toConst().orderAgainstScalar(0x0) == .eq);
+}
+
+test "big int conversion write twos complement zero" {
+    var a = try Managed.initSet(testing.allocator, 0x01_ffffffff_ffffffff_ffffffff);
+    defer a.deinit();
+
+    var m = a.toMutable();
+
+    // readTwosComplement:
+    // (1) should not read beyond buffer[0..abi_size]
+    // (2) should correctly interpret bytes based on the provided endianness
+    // (3) should ignore any bits from bit_count to 8 * abi_size
+
+    var bit_count: usize = 12 * 8 + 1;
+    var buffer: []const u8 = undefined;
+
+    buffer = &([_]u8{0} ** 13);
+    m.readTwosComplement(buffer, bit_count, 13, .Little, .unsigned);
+    try testing.expect(m.toConst().orderAgainstScalar(0x0) == .eq);
+    m.readTwosComplement(buffer, bit_count, 13, .Big, .unsigned);
+    try testing.expect(m.toConst().orderAgainstScalar(0x0) == .eq);
+
+    buffer = &([_]u8{0} ** 16);
+    m.readTwosComplement(buffer, bit_count, 16, .Little, .unsigned);
+    try testing.expect(m.toConst().orderAgainstScalar(0x0) == .eq);
+    m.readTwosComplement(buffer, bit_count, 16, .Big, .unsigned);
+    try testing.expect(m.toConst().orderAgainstScalar(0x0) == .eq);
 }
test/behavior/bitcast.zig
@@ -6,123 +6,53 @@ const maxInt = std.math.maxInt;
 const minInt = std.math.minInt;
 const native_endian = builtin.target.cpu.arch.endian();
 
-test "@bitCast i32 -> u32" {
-    try testBitCast_i32_u32();
-    comptime try testBitCast_i32_u32();
-}
-
-fn testBitCast_i32_u32() !void {
-    try expect(conv_i32(-1) == maxInt(u32));
-    try expect(conv_u32(maxInt(u32)) == -1);
-    try expect(conv_u32(0x8000_0000) == minInt(i32));
-    try expect(conv_i32(minInt(i32)) == 0x8000_0000);
-}
-
-fn conv_i32(x: i32) u32 {
-    return @bitCast(u32, x);
-}
-fn conv_u32(x: u32) i32 {
-    return @bitCast(i32, x);
-}
-
-test "@bitCast i48 -> u48" {
-    try testBitCast_i48_u48();
-    comptime try testBitCast_i48_u48();
-}
-
-fn testBitCast_i48_u48() !void {
-    if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
-    if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
-    if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
-
-    try expect(conv_i48(-1) == maxInt(u48));
-    try expect(conv_u48(maxInt(u48)) == -1);
-    try expect(conv_u48(0x8000_0000_0000) == minInt(i48));
-    try expect(conv_i48(minInt(i48)) == 0x8000_0000_0000);
-}
-
-fn conv_i48(x: i48) u48 {
-    return @bitCast(u48, x);
-}
-
-fn conv_u48(x: u48) i48 {
-    return @bitCast(i48, x);
-}
+test "@bitCast iX -> uX" {
+    const bit_values = [_]usize{ 8, 16, 32, 64 };
 
-test "@bitCast i27 -> u27" {
-    try testBitCast_i27_u27();
-    comptime try testBitCast_i27_u27();
+    inline for (bit_values) |bits| {
+        try testBitCast(bits);
+        comptime try testBitCast(bits);
+    }
 }
 
-fn testBitCast_i27_u27() !void {
+test "@bitCast iX -> uX exotic integers" {
     if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
     if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
     if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
 
-    try expect(conv_i27(-1) == maxInt(u27));
-    try expect(conv_u27(maxInt(u27)) == -1);
-    try expect(conv_u27(0x400_0000) == minInt(i27));
-    try expect(conv_i27(minInt(i27)) == 0x400_0000);
-}
-
-fn conv_i27(x: i27) u27 {
-    return @bitCast(u27, x);
-}
-
-fn conv_u27(x: u27) i27 {
-    return @bitCast(i27, x);
-}
-
-test "@bitCast i512 -> u512" {
-    try testBitCast_i512_u512();
-    comptime try testBitCast_i512_u512();
-}
-
-fn testBitCast_i512_u512() !void {
-    if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
-    if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
-    if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
+    const bit_values = [_]usize{ 1, 48, 27, 512, 493, 293, 125, 204, 112 };
 
-    try expect(conv_i512(-1) == maxInt(u512));
-    try expect(conv_u512(maxInt(u512)) == -1);
-    try expect(conv_u512(@as(u512, 1) << 511) == minInt(i512));
-    try expect(conv_i512(minInt(i512)) == (@as(u512, 1) << 511));
+    inline for (bit_values) |bits| {
+        try testBitCast(bits);
+        comptime try testBitCast(bits);
+    }
 }
 
-fn conv_i512(x: i512) u512 {
-    return @bitCast(u512, x);
-}
+fn testBitCast(comptime N: usize) !void {
+    const iN = std.meta.Int(.signed, N);
+    const uN = std.meta.Int(.unsigned, N);
 
-fn conv_u512(x: u512) i512 {
-    return @bitCast(i512, x);
-}
+    try expect(conv_iN(N, -1) == maxInt(uN));
+    try expect(conv_uN(N, maxInt(uN)) == -1);
 
-test "bitcast result to _" {
-    _ = @bitCast(u8, @as(i8, 1));
-}
+    try expect(conv_iN(N, maxInt(iN)) == maxInt(iN));
+    try expect(conv_uN(N, maxInt(iN)) == maxInt(iN));
 
-test "@bitCast i493 -> u493" {
-    try testBitCast_i493_u493();
-    comptime try testBitCast_i493_u493();
-}
+    try expect(conv_uN(N, 1 << (N - 1)) == minInt(iN));
+    try expect(conv_iN(N, minInt(iN)) == (1 << (N - 1)));
 
-fn testBitCast_i493_u493() !void {
-    if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
-    if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
-    if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
+    try expect(conv_uN(N, 0) == 0);
+    try expect(conv_iN(N, 0) == 0);
 
-    try expect(conv_i493(-1) == maxInt(u493));
-    try expect(conv_u493(maxInt(u493)) == -1);
-    try expect(conv_u493(@as(u493, 1) << 492) == minInt(i493));
-    try expect(conv_i493(minInt(i493)) == (@as(u493, 1) << 492));
+    try expect(conv_iN(N, -0) == 0);
 }
 
-fn conv_i493(x: i493) u493 {
-    return @bitCast(u493, x);
+fn conv_iN(comptime N: usize, x: std.meta.Int(.signed, N)) std.meta.Int(.unsigned, N) {
+    return @bitCast(std.meta.Int(.unsigned, N), x);
 }
 
-fn conv_u493(x: u493) i493 {
-    return @bitCast(i493, x);
+fn conv_uN(comptime N: usize, x: std.meta.Int(.unsigned, N)) std.meta.Int(.signed, N) {
+    return @bitCast(std.meta.Int(.signed, N), x);
 }
 
 test "nested bitcast" {