You can use a function instead of a field to get the remaining padding.
const std = @import("std");
const Location = struct {
_: void align(std.atomic.cache_line) = {},
state: std.atomic.Value(u32),
descriptor: Descriptor,
const last_used_byte = blk: {
var max: usize = 0;
for (std.meta.fieldNames(Location)) |field_name| {
const end = @offsetOf(Location, field_name) + @sizeOf(@FieldType(Location, field_name));
max = @max(max, end);
}
break :blk max;
};
const trailing_bytes_size = @sizeOf(Location) - last_used_byte;
pub fn trailingBytes(loc: *Location) *[trailing_bytes_size]u8 {
const bytes: [*]u8 = @ptrCast(loc);
return bytes[last_used_byte..@sizeOf(Location)];
}
};
Hacky, unreliable version (but we’re trusting Andrew for placement of _: void align(std.atomic.cache_line) = {},
, too (-: ) to get it as a field, thus hoping the auto
layout doesn’t do something too surprising:
const Location2 = struct {
_: void align(std.atomic.cache_line) = {},
state: std.atomic.Value(u32),
descriptor: Descriptor,
bytes: [trailing_bytes_size]u8,
const last_used_byte = blk: {
const Layout = struct {
state: std.atomic.Value(u32),
descriptor: Descriptor,
};
var max: usize = 0;
for (std.meta.fieldNames(Layout)) |field_name| {
const end = @offsetOf(Layout, field_name) + @sizeOf(@FieldType(Layout, field_name));
max = @max(max, end);
}
break :blk max;
};
const trailing_bytes_size = @sizeOf(Location) - last_used_byte;
};
But I’d stick with the first one.