mirror of
https://github.com/ziglang/zig.git
synced 2026-02-14 05:20:34 +00:00
Merge pull request #10542 from Hejsil/stage2-bit-offset-of
Stage2 bitOffsetOf and offsetOf builtin functions
This commit is contained in:
commit
7651913fd2
58
src/Sema.zig
58
src/Sema.zig
@ -11046,15 +11046,63 @@ fn zirShrExact(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
|
||||
}
|
||||
|
||||
fn zirBitOffsetOf(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
|
||||
const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
|
||||
const src = inst_data.src();
|
||||
return sema.fail(block, src, "TODO: Sema.zirBitOffsetOf", .{});
|
||||
const offset = try bitOffsetOf(sema, block, inst);
|
||||
return sema.addIntUnsigned(Type.comptime_int, offset);
|
||||
}
|
||||
|
||||
fn zirOffsetOf(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
|
||||
const offset = try bitOffsetOf(sema, block, inst);
|
||||
return sema.addIntUnsigned(Type.comptime_int, offset / 8);
|
||||
}
|
||||
|
||||
fn bitOffsetOf(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!u64 {
|
||||
const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
|
||||
const src = inst_data.src();
|
||||
return sema.fail(block, src, "TODO: Sema.zirOffsetOf", .{});
|
||||
sema.src = .{ .node_offset_bin_op = inst_data.src_node };
|
||||
const lhs_src: LazySrcLoc = .{ .node_offset_bin_lhs = inst_data.src_node };
|
||||
const rhs_src: LazySrcLoc = .{ .node_offset_bin_rhs = inst_data.src_node };
|
||||
const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data;
|
||||
|
||||
const ty = try sema.resolveType(block, lhs_src, extra.lhs);
|
||||
const field_name = try sema.resolveConstString(block, rhs_src, extra.rhs);
|
||||
|
||||
try sema.resolveTypeLayout(block, lhs_src, ty);
|
||||
if (ty.tag() != .@"struct") {
|
||||
return sema.fail(
|
||||
block,
|
||||
lhs_src,
|
||||
"expected struct type, found '{}'",
|
||||
.{ty},
|
||||
);
|
||||
}
|
||||
|
||||
const index = ty.structFields().getIndex(field_name) orelse {
|
||||
return sema.fail(
|
||||
block,
|
||||
rhs_src,
|
||||
"struct '{}' has no field '{s}'",
|
||||
.{ ty, field_name },
|
||||
);
|
||||
};
|
||||
|
||||
const target = sema.mod.getTarget();
|
||||
const layout = ty.containerLayout();
|
||||
if (layout == .Packed) {
|
||||
var it = ty.iteratePackedStructOffsets(target);
|
||||
while (it.next()) |field_offset| {
|
||||
if (field_offset.field == index) {
|
||||
return (field_offset.offset * 8) + field_offset.running_bits;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
var it = ty.iterateStructOffsets(target);
|
||||
while (it.next()) |field_offset| {
|
||||
if (field_offset.field == index) {
|
||||
return field_offset.offset * 8;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
unreachable;
|
||||
}
|
||||
|
||||
/// Returns `true` if the type was a comptime_int.
|
||||
|
||||
186
src/type.zig
186
src/type.zig
@ -2922,6 +2922,15 @@ pub const Type = extern union {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn containerLayout(ty: Type) std.builtin.TypeInfo.ContainerLayout {
|
||||
return switch (ty.tag()) {
|
||||
.@"struct" => ty.castTag(.@"struct").?.data.layout,
|
||||
.@"union" => ty.castTag(.@"union").?.data.layout,
|
||||
.union_tagged => ty.castTag(.union_tagged).?.data.layout,
|
||||
else => unreachable,
|
||||
};
|
||||
}
|
||||
|
||||
/// Asserts that the type is an error union.
|
||||
pub fn errorUnionPayload(self: Type) Type {
|
||||
return switch (self.tag()) {
|
||||
@ -3765,6 +3774,116 @@ pub const Type = extern union {
|
||||
}
|
||||
}
|
||||
|
||||
pub const PackedFieldOffset = struct {
|
||||
field: usize,
|
||||
offset: u64,
|
||||
running_bits: u16,
|
||||
};
|
||||
|
||||
pub const PackedStructOffsetIterator = struct {
|
||||
field: usize = 0,
|
||||
offset: u64 = 0,
|
||||
big_align: u32 = 0,
|
||||
running_bits: u16 = 0,
|
||||
struct_obj: *Module.Struct,
|
||||
target: Target,
|
||||
|
||||
pub fn next(it: *PackedStructOffsetIterator) ?PackedFieldOffset {
|
||||
comptime assert(Type.packed_struct_layout_version == 1);
|
||||
if (it.struct_obj.fields.count() <= it.field)
|
||||
return null;
|
||||
|
||||
const field = it.struct_obj.fields.values()[it.field];
|
||||
defer it.field += 1;
|
||||
if (!field.ty.hasCodeGenBits()) {
|
||||
return PackedFieldOffset{
|
||||
.field = it.field,
|
||||
.offset = it.offset,
|
||||
.running_bits = it.running_bits,
|
||||
};
|
||||
}
|
||||
|
||||
const field_align = field.packedAlignment();
|
||||
if (field_align == 0) {
|
||||
defer it.running_bits += @intCast(u16, field.ty.bitSize(it.target));
|
||||
return PackedFieldOffset{
|
||||
.field = it.field,
|
||||
.offset = it.offset,
|
||||
.running_bits = it.running_bits,
|
||||
};
|
||||
} else {
|
||||
it.big_align = @maximum(it.big_align, field_align);
|
||||
|
||||
if (it.running_bits != 0) {
|
||||
var int_payload: Payload.Bits = .{
|
||||
.base = .{ .tag = .int_unsigned },
|
||||
.data = it.running_bits,
|
||||
};
|
||||
const int_ty: Type = .{ .ptr_otherwise = &int_payload.base };
|
||||
const int_align = int_ty.abiAlignment(it.target);
|
||||
it.big_align = @maximum(it.big_align, int_align);
|
||||
it.offset = std.mem.alignForwardGeneric(u64, it.offset, int_align);
|
||||
it.offset += int_ty.abiSize(it.target);
|
||||
it.running_bits = 0;
|
||||
}
|
||||
it.offset = std.mem.alignForwardGeneric(u64, it.offset, field_align);
|
||||
defer it.offset += field.ty.abiSize(it.target);
|
||||
return PackedFieldOffset{
|
||||
.field = it.field,
|
||||
.offset = it.offset,
|
||||
.running_bits = it.running_bits,
|
||||
};
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/// Get an iterator that iterates over all the struct field, returning the field and
|
||||
/// offset of that field. Asserts that the type is a none packed struct.
|
||||
pub fn iteratePackedStructOffsets(ty: Type, target: Target) PackedStructOffsetIterator {
|
||||
const struct_obj = ty.castTag(.@"struct").?.data;
|
||||
assert(struct_obj.haveLayout());
|
||||
assert(struct_obj.layout == .Packed);
|
||||
return .{ .struct_obj = struct_obj, .target = target };
|
||||
}
|
||||
|
||||
pub const FieldOffset = struct {
|
||||
field: usize,
|
||||
offset: u64,
|
||||
};
|
||||
|
||||
pub const StructOffsetIterator = struct {
|
||||
field: usize = 0,
|
||||
offset: u64 = 0,
|
||||
big_align: u32 = 0,
|
||||
struct_obj: *Module.Struct,
|
||||
target: Target,
|
||||
|
||||
pub fn next(it: *StructOffsetIterator) ?FieldOffset {
|
||||
if (it.struct_obj.fields.count() <= it.field)
|
||||
return null;
|
||||
|
||||
const field = it.struct_obj.fields.values()[it.field];
|
||||
defer it.field += 1;
|
||||
if (!field.ty.hasCodeGenBits())
|
||||
return FieldOffset{ .field = it.field, .offset = it.offset };
|
||||
|
||||
const field_align = field.normalAlignment(it.target);
|
||||
it.big_align = @maximum(it.big_align, field_align);
|
||||
it.offset = std.mem.alignForwardGeneric(u64, it.offset, field_align);
|
||||
defer it.offset += field.ty.abiSize(it.target);
|
||||
return FieldOffset{ .field = it.field, .offset = it.offset };
|
||||
}
|
||||
};
|
||||
|
||||
/// Get an iterator that iterates over all the struct field, returning the field and
|
||||
/// offset of that field. Asserts that the type is a none packed struct.
|
||||
pub fn iterateStructOffsets(ty: Type, target: Target) StructOffsetIterator {
|
||||
const struct_obj = ty.castTag(.@"struct").?.data;
|
||||
assert(struct_obj.haveLayout());
|
||||
assert(struct_obj.layout != .Packed);
|
||||
return .{ .struct_obj = struct_obj, .target = target };
|
||||
}
|
||||
|
||||
/// Supports structs and unions.
|
||||
/// For packed structs, it returns the byte offset of the containing integer.
|
||||
pub fn structFieldOffset(ty: Type, index: usize, target: Target) u64 {
|
||||
@ -3774,65 +3893,34 @@ pub const Type = extern union {
|
||||
assert(struct_obj.haveLayout());
|
||||
const is_packed = struct_obj.layout == .Packed;
|
||||
if (!is_packed) {
|
||||
var offset: u64 = 0;
|
||||
var big_align: u32 = 0;
|
||||
for (struct_obj.fields.values()) |field, i| {
|
||||
if (!field.ty.hasCodeGenBits()) continue;
|
||||
|
||||
const field_align = field.normalAlignment(target);
|
||||
big_align = @maximum(big_align, field_align);
|
||||
offset = std.mem.alignForwardGeneric(u64, offset, field_align);
|
||||
if (i == index) return offset;
|
||||
offset += field.ty.abiSize(target);
|
||||
var it = ty.iterateStructOffsets(target);
|
||||
while (it.next()) |field_offset| {
|
||||
if (index == field_offset.field)
|
||||
return field_offset.offset;
|
||||
}
|
||||
offset = std.mem.alignForwardGeneric(u64, offset, big_align);
|
||||
return offset;
|
||||
|
||||
return std.mem.alignForwardGeneric(u64, it.offset, it.big_align);
|
||||
}
|
||||
|
||||
comptime assert(Type.packed_struct_layout_version == 1);
|
||||
var offset: u64 = 0;
|
||||
var big_align: u32 = 0;
|
||||
var running_bits: u16 = 0;
|
||||
for (struct_obj.fields.values()) |field, i| {
|
||||
if (!field.ty.hasCodeGenBits()) continue;
|
||||
|
||||
const field_align = field.packedAlignment();
|
||||
if (field_align == 0) {
|
||||
if (i == index) return offset;
|
||||
running_bits += @intCast(u16, field.ty.bitSize(target));
|
||||
} else {
|
||||
big_align = @maximum(big_align, field_align);
|
||||
|
||||
if (running_bits != 0) {
|
||||
var int_payload: Payload.Bits = .{
|
||||
.base = .{ .tag = .int_unsigned },
|
||||
.data = running_bits,
|
||||
};
|
||||
const int_ty: Type = .{ .ptr_otherwise = &int_payload.base };
|
||||
const int_align = int_ty.abiAlignment(target);
|
||||
big_align = @maximum(big_align, int_align);
|
||||
offset = std.mem.alignForwardGeneric(u64, offset, int_align);
|
||||
offset += int_ty.abiSize(target);
|
||||
running_bits = 0;
|
||||
}
|
||||
offset = std.mem.alignForwardGeneric(u64, offset, field_align);
|
||||
if (i == index) return offset;
|
||||
offset += field.ty.abiSize(target);
|
||||
}
|
||||
var it = ty.iteratePackedStructOffsets(target);
|
||||
while (it.next()) |field_offset| {
|
||||
if (index == field_offset.field)
|
||||
return field_offset.offset;
|
||||
}
|
||||
if (running_bits != 0) {
|
||||
|
||||
if (it.running_bits != 0) {
|
||||
var int_payload: Payload.Bits = .{
|
||||
.base = .{ .tag = .int_unsigned },
|
||||
.data = running_bits,
|
||||
.data = it.running_bits,
|
||||
};
|
||||
const int_ty: Type = .{ .ptr_otherwise = &int_payload.base };
|
||||
const int_align = int_ty.abiAlignment(target);
|
||||
big_align = @maximum(big_align, int_align);
|
||||
offset = std.mem.alignForwardGeneric(u64, offset, int_align);
|
||||
offset += int_ty.abiSize(target);
|
||||
it.big_align = @maximum(it.big_align, int_align);
|
||||
it.offset = std.mem.alignForwardGeneric(u64, it.offset, int_align);
|
||||
it.offset += int_ty.abiSize(target);
|
||||
}
|
||||
offset = std.mem.alignForwardGeneric(u64, offset, big_align);
|
||||
return offset;
|
||||
it.offset = std.mem.alignForwardGeneric(u64, it.offset, it.big_align);
|
||||
return it.offset;
|
||||
},
|
||||
.@"union" => return 0,
|
||||
.union_tagged => {
|
||||
|
||||
@ -81,6 +81,7 @@ test {
|
||||
_ = @import("behavior/bugs/1310.zig");
|
||||
_ = @import("behavior/bugs/1381.zig");
|
||||
_ = @import("behavior/bugs/1500.zig");
|
||||
_ = @import("behavior/bugs/1735.zig");
|
||||
_ = @import("behavior/bugs/1741.zig");
|
||||
_ = @import("behavior/bugs/2006.zig");
|
||||
_ = @import("behavior/bugs/2578.zig");
|
||||
@ -98,6 +99,7 @@ test {
|
||||
_ = @import("behavior/generics_llvm.zig");
|
||||
_ = @import("behavior/math.zig");
|
||||
_ = @import("behavior/maximum_minimum.zig");
|
||||
_ = @import("behavior/merge_error_sets.zig");
|
||||
_ = @import("behavior/namespace_depends_on_compile_var.zig");
|
||||
_ = @import("behavior/null_llvm.zig");
|
||||
_ = @import("behavior/optional_llvm.zig");
|
||||
@ -137,7 +139,6 @@ test {
|
||||
_ = @import("behavior/bugs/1421.zig");
|
||||
_ = @import("behavior/bugs/1442.zig");
|
||||
_ = @import("behavior/bugs/1607.zig");
|
||||
_ = @import("behavior/bugs/1735.zig");
|
||||
_ = @import("behavior/bugs/1851.zig");
|
||||
_ = @import("behavior/bugs/1914.zig");
|
||||
_ = @import("behavior/bugs/2114.zig");
|
||||
@ -171,7 +172,6 @@ test {
|
||||
_ = @import("behavior/if_stage1.zig");
|
||||
_ = @import("behavior/ir_block_deps.zig");
|
||||
_ = @import("behavior/math_stage1.zig");
|
||||
_ = @import("behavior/merge_error_sets.zig");
|
||||
_ = @import("behavior/misc.zig");
|
||||
_ = @import("behavior/muladd.zig");
|
||||
_ = @import("behavior/null_stage1.zig");
|
||||
|
||||
@ -47,3 +47,116 @@ fn fn1(alpha: bool) void {
|
||||
test "lazy @sizeOf result is checked for definedness" {
|
||||
_ = fn1;
|
||||
}
|
||||
|
||||
const A = struct {
|
||||
a: u8,
|
||||
b: u32,
|
||||
c: u8,
|
||||
d: u3,
|
||||
e: u5,
|
||||
f: u16,
|
||||
g: u16,
|
||||
h: u9,
|
||||
i: u7,
|
||||
};
|
||||
|
||||
const P = packed struct {
|
||||
a: u8,
|
||||
b: u32,
|
||||
c: u8,
|
||||
d: u3,
|
||||
e: u5,
|
||||
f: u16,
|
||||
g: u16,
|
||||
h: u9,
|
||||
i: u7,
|
||||
};
|
||||
|
||||
test "@offsetOf" {
|
||||
|
||||
// Packed structs have fixed memory layout
|
||||
try expect(@offsetOf(P, "a") == 0);
|
||||
try expect(@offsetOf(P, "b") == 1);
|
||||
try expect(@offsetOf(P, "c") == 5);
|
||||
try expect(@offsetOf(P, "d") == 6);
|
||||
try expect(@offsetOf(P, "e") == 6);
|
||||
try expect(@offsetOf(P, "f") == 7);
|
||||
try expect(@offsetOf(P, "g") == 9);
|
||||
try expect(@offsetOf(P, "h") == 11);
|
||||
try expect(@offsetOf(P, "i") == 12);
|
||||
|
||||
// // Normal struct fields can be moved/padded
|
||||
var a: A = undefined;
|
||||
try expect(@ptrToInt(&a.a) - @ptrToInt(&a) == @offsetOf(A, "a"));
|
||||
try expect(@ptrToInt(&a.b) - @ptrToInt(&a) == @offsetOf(A, "b"));
|
||||
try expect(@ptrToInt(&a.c) - @ptrToInt(&a) == @offsetOf(A, "c"));
|
||||
try expect(@ptrToInt(&a.d) - @ptrToInt(&a) == @offsetOf(A, "d"));
|
||||
try expect(@ptrToInt(&a.e) - @ptrToInt(&a) == @offsetOf(A, "e"));
|
||||
try expect(@ptrToInt(&a.f) - @ptrToInt(&a) == @offsetOf(A, "f"));
|
||||
try expect(@ptrToInt(&a.g) - @ptrToInt(&a) == @offsetOf(A, "g"));
|
||||
try expect(@ptrToInt(&a.h) - @ptrToInt(&a) == @offsetOf(A, "h"));
|
||||
try expect(@ptrToInt(&a.i) - @ptrToInt(&a) == @offsetOf(A, "i"));
|
||||
}
|
||||
|
||||
test "@offsetOf packed struct, array length not power of 2 or multiple of native pointer width in bytes" {
|
||||
const p3a_len = 3;
|
||||
const P3 = packed struct {
|
||||
a: [p3a_len]u8,
|
||||
b: usize,
|
||||
};
|
||||
try std.testing.expect(0 == @offsetOf(P3, "a"));
|
||||
try std.testing.expect(p3a_len == @offsetOf(P3, "b"));
|
||||
|
||||
const p5a_len = 5;
|
||||
const P5 = packed struct {
|
||||
a: [p5a_len]u8,
|
||||
b: usize,
|
||||
};
|
||||
try std.testing.expect(0 == @offsetOf(P5, "a"));
|
||||
try std.testing.expect(p5a_len == @offsetOf(P5, "b"));
|
||||
|
||||
const p6a_len = 6;
|
||||
const P6 = packed struct {
|
||||
a: [p6a_len]u8,
|
||||
b: usize,
|
||||
};
|
||||
try std.testing.expect(0 == @offsetOf(P6, "a"));
|
||||
try std.testing.expect(p6a_len == @offsetOf(P6, "b"));
|
||||
|
||||
const p7a_len = 7;
|
||||
const P7 = packed struct {
|
||||
a: [p7a_len]u8,
|
||||
b: usize,
|
||||
};
|
||||
try std.testing.expect(0 == @offsetOf(P7, "a"));
|
||||
try std.testing.expect(p7a_len == @offsetOf(P7, "b"));
|
||||
|
||||
const p9a_len = 9;
|
||||
const P9 = packed struct {
|
||||
a: [p9a_len]u8,
|
||||
b: usize,
|
||||
};
|
||||
try std.testing.expect(0 == @offsetOf(P9, "a"));
|
||||
try std.testing.expect(p9a_len == @offsetOf(P9, "b"));
|
||||
|
||||
// 10, 11, 12, 13, 14, 15, 17, 18, 19, 20, 21, 22, 23, 25 etc. are further cases
|
||||
}
|
||||
|
||||
test "@bitOffsetOf" {
|
||||
// Packed structs have fixed memory layout
|
||||
try expect(@bitOffsetOf(P, "a") == 0);
|
||||
try expect(@bitOffsetOf(P, "b") == 8);
|
||||
try expect(@bitOffsetOf(P, "c") == 40);
|
||||
try expect(@bitOffsetOf(P, "d") == 48);
|
||||
try expect(@bitOffsetOf(P, "e") == 51);
|
||||
try expect(@bitOffsetOf(P, "f") == 56);
|
||||
try expect(@bitOffsetOf(P, "g") == 72);
|
||||
|
||||
try expect(@offsetOf(A, "a") * 8 == @bitOffsetOf(A, "a"));
|
||||
try expect(@offsetOf(A, "b") * 8 == @bitOffsetOf(A, "b"));
|
||||
try expect(@offsetOf(A, "c") * 8 == @bitOffsetOf(A, "c"));
|
||||
try expect(@offsetOf(A, "d") * 8 == @bitOffsetOf(A, "d"));
|
||||
try expect(@offsetOf(A, "e") * 8 == @bitOffsetOf(A, "e"));
|
||||
try expect(@offsetOf(A, "f") * 8 == @bitOffsetOf(A, "f"));
|
||||
try expect(@offsetOf(A, "g") * 8 == @bitOffsetOf(A, "g"));
|
||||
}
|
||||
|
||||
@ -2,118 +2,6 @@ const std = @import("std");
|
||||
const expect = std.testing.expect;
|
||||
const expectEqual = std.testing.expectEqual;
|
||||
|
||||
const A = struct {
|
||||
a: u8,
|
||||
b: u32,
|
||||
c: u8,
|
||||
d: u3,
|
||||
e: u5,
|
||||
f: u16,
|
||||
g: u16,
|
||||
h: u9,
|
||||
i: u7,
|
||||
};
|
||||
|
||||
const P = packed struct {
|
||||
a: u8,
|
||||
b: u32,
|
||||
c: u8,
|
||||
d: u3,
|
||||
e: u5,
|
||||
f: u16,
|
||||
g: u16,
|
||||
h: u9,
|
||||
i: u7,
|
||||
};
|
||||
|
||||
test "@offsetOf" {
|
||||
// Packed structs have fixed memory layout
|
||||
try expect(@offsetOf(P, "a") == 0);
|
||||
try expect(@offsetOf(P, "b") == 1);
|
||||
try expect(@offsetOf(P, "c") == 5);
|
||||
try expect(@offsetOf(P, "d") == 6);
|
||||
try expect(@offsetOf(P, "e") == 6);
|
||||
try expect(@offsetOf(P, "f") == 7);
|
||||
try expect(@offsetOf(P, "g") == 9);
|
||||
try expect(@offsetOf(P, "h") == 11);
|
||||
try expect(@offsetOf(P, "i") == 12);
|
||||
|
||||
// Normal struct fields can be moved/padded
|
||||
var a: A = undefined;
|
||||
try expect(@ptrToInt(&a.a) - @ptrToInt(&a) == @offsetOf(A, "a"));
|
||||
try expect(@ptrToInt(&a.b) - @ptrToInt(&a) == @offsetOf(A, "b"));
|
||||
try expect(@ptrToInt(&a.c) - @ptrToInt(&a) == @offsetOf(A, "c"));
|
||||
try expect(@ptrToInt(&a.d) - @ptrToInt(&a) == @offsetOf(A, "d"));
|
||||
try expect(@ptrToInt(&a.e) - @ptrToInt(&a) == @offsetOf(A, "e"));
|
||||
try expect(@ptrToInt(&a.f) - @ptrToInt(&a) == @offsetOf(A, "f"));
|
||||
try expect(@ptrToInt(&a.g) - @ptrToInt(&a) == @offsetOf(A, "g"));
|
||||
try expect(@ptrToInt(&a.h) - @ptrToInt(&a) == @offsetOf(A, "h"));
|
||||
try expect(@ptrToInt(&a.i) - @ptrToInt(&a) == @offsetOf(A, "i"));
|
||||
}
|
||||
|
||||
test "@offsetOf packed struct, array length not power of 2 or multiple of native pointer width in bytes" {
|
||||
const p3a_len = 3;
|
||||
const P3 = packed struct {
|
||||
a: [p3a_len]u8,
|
||||
b: usize,
|
||||
};
|
||||
try std.testing.expectEqual(0, @offsetOf(P3, "a"));
|
||||
try std.testing.expectEqual(p3a_len, @offsetOf(P3, "b"));
|
||||
|
||||
const p5a_len = 5;
|
||||
const P5 = packed struct {
|
||||
a: [p5a_len]u8,
|
||||
b: usize,
|
||||
};
|
||||
try std.testing.expectEqual(0, @offsetOf(P5, "a"));
|
||||
try std.testing.expectEqual(p5a_len, @offsetOf(P5, "b"));
|
||||
|
||||
const p6a_len = 6;
|
||||
const P6 = packed struct {
|
||||
a: [p6a_len]u8,
|
||||
b: usize,
|
||||
};
|
||||
try std.testing.expectEqual(0, @offsetOf(P6, "a"));
|
||||
try std.testing.expectEqual(p6a_len, @offsetOf(P6, "b"));
|
||||
|
||||
const p7a_len = 7;
|
||||
const P7 = packed struct {
|
||||
a: [p7a_len]u8,
|
||||
b: usize,
|
||||
};
|
||||
try std.testing.expectEqual(0, @offsetOf(P7, "a"));
|
||||
try std.testing.expectEqual(p7a_len, @offsetOf(P7, "b"));
|
||||
|
||||
const p9a_len = 9;
|
||||
const P9 = packed struct {
|
||||
a: [p9a_len]u8,
|
||||
b: usize,
|
||||
};
|
||||
try std.testing.expectEqual(0, @offsetOf(P9, "a"));
|
||||
try std.testing.expectEqual(p9a_len, @offsetOf(P9, "b"));
|
||||
|
||||
// 10, 11, 12, 13, 14, 15, 17, 18, 19, 20, 21, 22, 23, 25 etc. are further cases
|
||||
}
|
||||
|
||||
test "@bitOffsetOf" {
|
||||
// Packed structs have fixed memory layout
|
||||
try expect(@bitOffsetOf(P, "a") == 0);
|
||||
try expect(@bitOffsetOf(P, "b") == 8);
|
||||
try expect(@bitOffsetOf(P, "c") == 40);
|
||||
try expect(@bitOffsetOf(P, "d") == 48);
|
||||
try expect(@bitOffsetOf(P, "e") == 51);
|
||||
try expect(@bitOffsetOf(P, "f") == 56);
|
||||
try expect(@bitOffsetOf(P, "g") == 72);
|
||||
|
||||
try expect(@offsetOf(A, "a") * 8 == @bitOffsetOf(A, "a"));
|
||||
try expect(@offsetOf(A, "b") * 8 == @bitOffsetOf(A, "b"));
|
||||
try expect(@offsetOf(A, "c") * 8 == @bitOffsetOf(A, "c"));
|
||||
try expect(@offsetOf(A, "d") * 8 == @bitOffsetOf(A, "d"));
|
||||
try expect(@offsetOf(A, "e") * 8 == @bitOffsetOf(A, "e"));
|
||||
try expect(@offsetOf(A, "f") * 8 == @bitOffsetOf(A, "f"));
|
||||
try expect(@offsetOf(A, "g") * 8 == @bitOffsetOf(A, "g"));
|
||||
}
|
||||
|
||||
test "@sizeOf(T) == 0 doesn't force resolving struct size" {
|
||||
const S = struct {
|
||||
const Foo = struct {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user