#Runtime indexed access to packed struct fields

1 messages · Page 1 of 1 (latest)

brave lynx
#

Is anyone aware of a method to access packed struct fields based on a runtime index? Essentially replicating in a roundabout manner what field access of a “packed array” might look like.

Context: must work with very large (backed by u16448) packed structs that contain multiple order-dependent repeated fields. Think of, for an example, a packed struct that contains a status bit for every potentially connected device in the fashion:
device1_connected: bool,
device2_connected: bool,

device150_connected: bool,

Current (tedious) solution is to create a function for every field:
deviceConnected(self: MyPackedStruct, devno: u8) bool {
return switch (devno) {
0 => self.device1_connected,

149 => self.device150_connected,
else => unreachable,
};
}

Edit:
Packed struct fields can also be nested packed structs, such as:

device1_connected: packed struct(u2) {
    left: bool,
    right: bool,
}
limpid dirge
#

Not well versed with zig but what if you indexed into the args tuple from @typeInfo and then use the name field in that argument with @field

gray leaf
#

If you are ok with effectively that code but with typeable source:

fn deviceConnected(self: MyPackedStruct, devno: u8) bool {
    return switch (devno) {
        inline 0...149 => |ct_devno| @field(self, std.fmt.comptimePrint("device{d}_connected", .{ct_devno + 1})),
        else => unreachable,
    };
}
#

Otherwise, you would have to compute the bit location manually and load it.

brave lynx
brave lynx
wary lake
#

If it's literally consisting of bools, I believe std has a bitset type (although I never used it). Or, generally, for any regular-sized set of fields one could implement index-based setters and getters. And even if they are not, one probably could automatically (by scanning the struct's fields at comptime) create a global array of bit offsets/sizes or smth like this?

brave lynx
#

I think long term we’ll write up a proposal for packed arrays with our motivating use case, but @gray leaf’s solution helps greatly in the interim.

gray leaf
#

std packed arrays have a guaranteed layout

brave lynx
#

Sorry did you say packed arrays..?

#

I… didn’t know they existed..

gray leaf
#

well they are supposed to

#

they don't for no particular reason

brave lynx
#

Oh, std.PackedIntArray

gray leaf
#

oh you can use the slice version for an external guaranteed layout

brave lynx
#

Will definitely look into this, thanks again

gray leaf
#

it shouldn't be too hard to create a function that turns a pointer to packed struct + first and last field into one of those

#

afaict this is designed to be abi-compatible with zig packed structs

#

std.ArrayBitSet would be preferable for bools, but the abi differs

brave lynx
#

Oh interesting, so they can be initialized with a bitcast?

#

From docs I can only seem to find initialization from an unpacked array, which wouldn’t make them very useful

gray leaf
#

oh std.IntegerBitSet has the correct abi

#

it won't do the subslicing for you, so maybe not usable

brave lynx
#

Ah we can’t use bit sets

gray leaf
#

which causes me to realize how easy this is without std

brave lynx
#

The example was such that each field is one bit, but in practice we have fields that are themselves multi-bit packed structs

gray leaf
#

I'd need more information about the packed struct layout though

#

well if the fields are multiple bits then std.PackedIntSlice should work great

brave lynx
#

Hmm

gray leaf
#

afaict std.PackedIntSlice(packed struct { ... }) works fine

#

but there's no tests for that so it may need some minor changes to work

brave lynx
#

I’ll look into this further and potentially edit this post with a more detailed write up/samples, but will be heading off to catch some sleep for now

#

I appreciate the pointers

brave lynx