mirror of
https://github.com/ziglang/zig.git
synced 2025-12-06 14:23:09 +00:00
437 lines
14 KiB
Zig
437 lines
14 KiB
Zig
const std = @import("std");
|
|
const builtin = @import("builtin");
|
|
const assert = std.debug.assert;
|
|
const expect = std.testing.expect;
|
|
const expectEqual = std.testing.expectEqual;
|
|
const native_endian = builtin.cpu.arch.endian();
|
|
|
|
test "correct size of packed structs" {
|
|
// Stage2 has different packed struct semantics.
|
|
if (builtin.zig_backend != .stage1) return error.SkipZigTest;
|
|
const T1 = packed struct { one: u8, three: [3]u8 };
|
|
|
|
try expectEqual(4, @sizeOf(T1));
|
|
try expectEqual(4 * 8, @bitSizeOf(T1));
|
|
|
|
const T2 = packed struct { three: [3]u8, one: u8 };
|
|
|
|
try expectEqual(4, @sizeOf(T2));
|
|
try expectEqual(4 * 8, @bitSizeOf(T2));
|
|
|
|
const T3 = packed struct { _1: u1, x: u7, _: u24 };
|
|
|
|
try expectEqual(4, @sizeOf(T3));
|
|
try expectEqual(4 * 8, @bitSizeOf(T3));
|
|
|
|
const T4 = packed struct { _1: u1, x: u7, _2: u8, _3: u16 };
|
|
|
|
try expectEqual(4, @sizeOf(T4));
|
|
try expectEqual(4 * 8, @bitSizeOf(T4));
|
|
|
|
const T5 = packed struct { _1: u1, x: u7, _2: u16, _3: u8 };
|
|
|
|
try expectEqual(4, @sizeOf(T5));
|
|
try expectEqual(4 * 8, @bitSizeOf(T5));
|
|
}
|
|
|
|
test "flags in packed structs" {
|
|
if (builtin.zig_backend == .stage1) return error.SkipZigTest;
|
|
|
|
const Flags1 = packed struct {
|
|
// first 8 bits
|
|
b0_0: u1,
|
|
b0_1: u1,
|
|
b0_2: u1,
|
|
b0_3: u1,
|
|
b0_4: u1,
|
|
b0_5: u1,
|
|
b0_6: u1,
|
|
b0_7: u1,
|
|
|
|
// 7 more bits
|
|
b1_0: u1,
|
|
b1_1: u1,
|
|
b1_2: u1,
|
|
b1_3: u1,
|
|
b1_4: u1,
|
|
b1_5: u1,
|
|
b1_6: u1,
|
|
|
|
// some padding to fill to 24 bits
|
|
_: u9,
|
|
};
|
|
|
|
try expectEqual(@sizeOf(u24), @sizeOf(Flags1));
|
|
try expectEqual(24, @bitSizeOf(Flags1));
|
|
|
|
const Flags2 = packed struct {
|
|
// byte 0
|
|
b0_0: u1,
|
|
b0_1: u1,
|
|
b0_2: u1,
|
|
b0_3: u1,
|
|
b0_4: u1,
|
|
b0_5: u1,
|
|
b0_6: u1,
|
|
b0_7: u1,
|
|
|
|
// partial byte 1 (but not 8 bits)
|
|
b1_0: u1,
|
|
b1_1: u1,
|
|
b1_2: u1,
|
|
b1_3: u1,
|
|
b1_4: u1,
|
|
b1_5: u1,
|
|
b1_6: u1,
|
|
|
|
// some padding that should yield @sizeOf(Flags2) == 4
|
|
_: u10,
|
|
};
|
|
|
|
try expectEqual(@sizeOf(u25), @sizeOf(Flags2));
|
|
try expectEqual(25, @bitSizeOf(Flags2));
|
|
|
|
const Flags3 = packed struct {
|
|
// byte 0
|
|
b0_0: u1,
|
|
b0_1: u1,
|
|
b0_2: u1,
|
|
b0_3: u1,
|
|
b0_4: u1,
|
|
b0_5: u1,
|
|
b0_6: u1,
|
|
b0_7: u1,
|
|
|
|
// byte 1
|
|
b1_0: u1,
|
|
b1_1: u1,
|
|
b1_2: u1,
|
|
b1_3: u1,
|
|
b1_4: u1,
|
|
b1_5: u1,
|
|
b1_6: u1,
|
|
b1_7: u1,
|
|
|
|
// some padding that should yield @sizeOf(Flags2) == 4
|
|
_: u16, // it works, if the padding is 8-based
|
|
};
|
|
|
|
try expectEqual(@sizeOf(u32), @sizeOf(Flags3));
|
|
try expectEqual(32, @bitSizeOf(Flags3));
|
|
}
|
|
|
|
test "consistent size of packed structs" {
|
|
if (builtin.zig_backend == .stage1) return error.SkipZigTest;
|
|
|
|
const TxData1 = packed struct { data: u8, _23: u23, full: bool = false };
|
|
const TxData2 = packed struct { data: u9, _22: u22, full: bool = false };
|
|
|
|
const register_size_bits = 32;
|
|
const register_size_bytes = @sizeOf(u32);
|
|
|
|
try expectEqual(register_size_bits, @bitSizeOf(TxData1));
|
|
try expectEqual(register_size_bytes, @sizeOf(TxData1));
|
|
|
|
try expectEqual(register_size_bits, @bitSizeOf(TxData2));
|
|
try expectEqual(register_size_bytes, @sizeOf(TxData2));
|
|
|
|
const TxData4 = packed struct { a: u32, b: u24 };
|
|
const TxData6 = packed struct { a: u24, b: u32 };
|
|
|
|
const expectedBitSize = 56;
|
|
const expectedByteSize = @sizeOf(u56);
|
|
|
|
try expectEqual(expectedBitSize, @bitSizeOf(TxData4));
|
|
try expectEqual(expectedByteSize, @sizeOf(TxData4));
|
|
|
|
try expectEqual(expectedBitSize, @bitSizeOf(TxData6));
|
|
try expectEqual(expectedByteSize, @sizeOf(TxData6));
|
|
}
|
|
|
|
test "correct sizeOf and offsets in packed structs" {
|
|
if (builtin.zig_backend == .stage1) return error.SkipZigTest;
|
|
if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
|
|
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
|
|
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
|
|
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
|
|
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
|
|
|
|
const PStruct = packed struct {
|
|
bool_a: bool,
|
|
bool_b: bool,
|
|
bool_c: bool,
|
|
bool_d: bool,
|
|
bool_e: bool,
|
|
bool_f: bool,
|
|
u1_a: u1,
|
|
bool_g: bool,
|
|
u1_b: u1,
|
|
u3_a: u3,
|
|
u10_a: u10,
|
|
u10_b: u10,
|
|
};
|
|
try expectEqual(0, @offsetOf(PStruct, "bool_a"));
|
|
try expectEqual(0, @bitOffsetOf(PStruct, "bool_a"));
|
|
try expectEqual(0, @offsetOf(PStruct, "bool_b"));
|
|
try expectEqual(1, @bitOffsetOf(PStruct, "bool_b"));
|
|
try expectEqual(0, @offsetOf(PStruct, "bool_c"));
|
|
try expectEqual(2, @bitOffsetOf(PStruct, "bool_c"));
|
|
try expectEqual(0, @offsetOf(PStruct, "bool_d"));
|
|
try expectEqual(3, @bitOffsetOf(PStruct, "bool_d"));
|
|
try expectEqual(0, @offsetOf(PStruct, "bool_e"));
|
|
try expectEqual(4, @bitOffsetOf(PStruct, "bool_e"));
|
|
try expectEqual(0, @offsetOf(PStruct, "bool_f"));
|
|
try expectEqual(5, @bitOffsetOf(PStruct, "bool_f"));
|
|
try expectEqual(0, @offsetOf(PStruct, "u1_a"));
|
|
try expectEqual(6, @bitOffsetOf(PStruct, "u1_a"));
|
|
try expectEqual(0, @offsetOf(PStruct, "bool_g"));
|
|
try expectEqual(7, @bitOffsetOf(PStruct, "bool_g"));
|
|
try expectEqual(1, @offsetOf(PStruct, "u1_b"));
|
|
try expectEqual(8, @bitOffsetOf(PStruct, "u1_b"));
|
|
try expectEqual(1, @offsetOf(PStruct, "u3_a"));
|
|
try expectEqual(9, @bitOffsetOf(PStruct, "u3_a"));
|
|
try expectEqual(1, @offsetOf(PStruct, "u10_a"));
|
|
try expectEqual(12, @bitOffsetOf(PStruct, "u10_a"));
|
|
try expectEqual(2, @offsetOf(PStruct, "u10_b"));
|
|
try expectEqual(22, @bitOffsetOf(PStruct, "u10_b"));
|
|
try expectEqual(4, @sizeOf(PStruct));
|
|
|
|
if (native_endian == .Little) {
|
|
const s1 = @bitCast(PStruct, @as(u32, 0x12345678));
|
|
try expectEqual(false, s1.bool_a);
|
|
try expectEqual(false, s1.bool_b);
|
|
try expectEqual(false, s1.bool_c);
|
|
try expectEqual(true, s1.bool_d);
|
|
try expectEqual(true, s1.bool_e);
|
|
try expectEqual(true, s1.bool_f);
|
|
try expectEqual(@as(u1, 1), s1.u1_a);
|
|
try expectEqual(false, s1.bool_g);
|
|
try expectEqual(@as(u1, 0), s1.u1_b);
|
|
try expectEqual(@as(u3, 3), s1.u3_a);
|
|
try expectEqual(@as(u10, 0b1101000101), s1.u10_a);
|
|
try expectEqual(@as(u10, 0b0001001000), s1.u10_b);
|
|
|
|
const s2 = @bitCast(packed struct { x: u1, y: u7, z: u24 }, @as(u32, 0xd5c71ff4));
|
|
try expectEqual(@as(u1, 0), s2.x);
|
|
try expectEqual(@as(u7, 0b1111010), s2.y);
|
|
try expectEqual(@as(u24, 0xd5c71f), s2.z);
|
|
}
|
|
}
|
|
|
|
test "nested packed structs" {
|
|
if (builtin.zig_backend == .stage1) return error.SkipZigTest;
|
|
if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
|
|
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
|
|
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
|
|
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
|
|
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
|
|
|
|
const S1 = packed struct { a: u8, b: u8, c: u8 };
|
|
|
|
const S2 = packed struct { d: u8, e: u8, f: u8 };
|
|
|
|
const S3 = packed struct { x: S1, y: S2 };
|
|
const S3Padded = packed struct { s3: S3, pad: u16 };
|
|
|
|
try expectEqual(48, @bitSizeOf(S3));
|
|
try expectEqual(@sizeOf(u48), @sizeOf(S3));
|
|
|
|
try expectEqual(3, @offsetOf(S3, "y"));
|
|
try expectEqual(24, @bitOffsetOf(S3, "y"));
|
|
|
|
if (native_endian == .Little) {
|
|
const s3 = @bitCast(S3Padded, @as(u64, 0xe952d5c71ff4)).s3;
|
|
try expectEqual(@as(u8, 0xf4), s3.x.a);
|
|
try expectEqual(@as(u8, 0x1f), s3.x.b);
|
|
try expectEqual(@as(u8, 0xc7), s3.x.c);
|
|
try expectEqual(@as(u8, 0xd5), s3.y.d);
|
|
try expectEqual(@as(u8, 0x52), s3.y.e);
|
|
try expectEqual(@as(u8, 0xe9), s3.y.f);
|
|
}
|
|
|
|
const S4 = packed struct { a: i32, b: i8 };
|
|
const S5 = packed struct { a: i32, b: i8, c: S4 };
|
|
const S6 = packed struct { a: i32, b: S4, c: i8 };
|
|
|
|
const expectedBitSize = 80;
|
|
const expectedByteSize = @sizeOf(u80);
|
|
try expectEqual(expectedBitSize, @bitSizeOf(S5));
|
|
try expectEqual(expectedByteSize, @sizeOf(S5));
|
|
try expectEqual(expectedBitSize, @bitSizeOf(S6));
|
|
try expectEqual(expectedByteSize, @sizeOf(S6));
|
|
|
|
try expectEqual(5, @offsetOf(S5, "c"));
|
|
try expectEqual(40, @bitOffsetOf(S5, "c"));
|
|
try expectEqual(9, @offsetOf(S6, "c"));
|
|
try expectEqual(72, @bitOffsetOf(S6, "c"));
|
|
}
|
|
|
|
test "regular in irregular packed struct" {
|
|
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;
|
|
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
|
|
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
|
|
|
|
const Irregular = packed struct {
|
|
bar: Regular = Regular{},
|
|
_: u24 = 0,
|
|
pub const Regular = packed struct { a: u16 = 0, b: u8 = 0 };
|
|
};
|
|
|
|
var foo = Irregular{};
|
|
foo.bar.a = 235;
|
|
foo.bar.b = 42;
|
|
|
|
try expectEqual(@as(u16, 235), foo.bar.a);
|
|
try expectEqual(@as(u8, 42), foo.bar.b);
|
|
}
|
|
|
|
test "byte-aligned field pointer offsets" {
|
|
if (builtin.zig_backend == .stage1) return error.SkipZigTest;
|
|
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;
|
|
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
|
|
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
|
|
|
|
const S = struct {
|
|
const A = packed struct {
|
|
a: u8,
|
|
b: u8,
|
|
c: u8,
|
|
d: u8,
|
|
};
|
|
|
|
const B = packed struct {
|
|
a: u16,
|
|
b: u16,
|
|
};
|
|
|
|
fn doTheTest() !void {
|
|
var a: A = .{
|
|
.a = 1,
|
|
.b = 2,
|
|
.c = 3,
|
|
.d = 4,
|
|
};
|
|
switch (comptime builtin.cpu.arch.endian()) {
|
|
.Little => {
|
|
comptime assert(@TypeOf(&a.a) == *align(4) u8);
|
|
comptime assert(@TypeOf(&a.b) == *u8);
|
|
comptime assert(@TypeOf(&a.c) == *align(2) u8);
|
|
comptime assert(@TypeOf(&a.d) == *u8);
|
|
},
|
|
.Big => {
|
|
// TODO re-evaluate packed struct endianness
|
|
comptime assert(@TypeOf(&a.a) == *align(4:0:4) u8);
|
|
comptime assert(@TypeOf(&a.b) == *align(4:8:4) u8);
|
|
comptime assert(@TypeOf(&a.c) == *align(4:16:4) u8);
|
|
comptime assert(@TypeOf(&a.d) == *align(4:24:4) u8);
|
|
},
|
|
}
|
|
try expect(a.a == 1);
|
|
try expect(a.b == 2);
|
|
try expect(a.c == 3);
|
|
try expect(a.d == 4);
|
|
|
|
a.a += 1;
|
|
try expect(a.a == 2);
|
|
try expect(a.b == 2);
|
|
try expect(a.c == 3);
|
|
try expect(a.d == 4);
|
|
|
|
a.b += 1;
|
|
try expect(a.a == 2);
|
|
try expect(a.b == 3);
|
|
try expect(a.c == 3);
|
|
try expect(a.d == 4);
|
|
|
|
a.c += 1;
|
|
try expect(a.a == 2);
|
|
try expect(a.b == 3);
|
|
try expect(a.c == 4);
|
|
try expect(a.d == 4);
|
|
|
|
a.d += 1;
|
|
try expect(a.a == 2);
|
|
try expect(a.b == 3);
|
|
try expect(a.c == 4);
|
|
try expect(a.d == 5);
|
|
|
|
var b: B = .{
|
|
.a = 1,
|
|
.b = 2,
|
|
};
|
|
switch (comptime builtin.cpu.arch.endian()) {
|
|
.Little => {
|
|
comptime assert(@TypeOf(&b.a) == *align(4) u16);
|
|
comptime assert(@TypeOf(&b.b) == *u16);
|
|
},
|
|
.Big => {
|
|
comptime assert(@TypeOf(&b.a) == *align(4:0:4) u16);
|
|
comptime assert(@TypeOf(&b.b) == *align(4:16:4) u16);
|
|
},
|
|
}
|
|
try expect(b.a == 1);
|
|
try expect(b.b == 2);
|
|
|
|
b.a += 1;
|
|
try expect(b.a == 2);
|
|
try expect(b.b == 2);
|
|
|
|
b.b += 1;
|
|
try expect(b.a == 2);
|
|
try expect(b.b == 3);
|
|
}
|
|
};
|
|
|
|
try S.doTheTest();
|
|
comptime try S.doTheTest();
|
|
}
|
|
|
|
test "load pointer from packed struct" {
|
|
if (builtin.zig_backend == .stage1) return error.SkipZigTest;
|
|
if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
|
|
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
|
|
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
|
|
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
|
|
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
|
|
|
|
const A = struct {
|
|
index: u16,
|
|
};
|
|
const B = packed struct {
|
|
x: *A,
|
|
y: u32,
|
|
};
|
|
var a: A = .{ .index = 123 };
|
|
var b_list: []B = &.{.{ .x = &a, .y = 99 }};
|
|
for (b_list) |b| {
|
|
var i = b.x.index;
|
|
try expect(i == 123);
|
|
}
|
|
}
|
|
|
|
test "@ptrToInt on a packed struct field" {
|
|
if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
|
|
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
|
|
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
|
|
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
|
|
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
|
|
|
|
const S = struct {
|
|
const P = packed struct {
|
|
x: u8,
|
|
y: u8,
|
|
z: u32,
|
|
};
|
|
var p0: P = P{
|
|
.x = 1,
|
|
.y = 2,
|
|
.z = 0,
|
|
};
|
|
};
|
|
try expect(@ptrToInt(&S.p0.z) - @ptrToInt(&S.p0.x) == 2);
|
|
}
|