this appears to work, in that i have a “circular list” with pointers being represented as indicies into my array:
const std = @import("std");
const Elem = struct {
pub const NIL = ~@as(u16, 0);
data: u32,
next: u16 = NIL,
pub fn getNext(self: @This()) ?*Elem {
if (self.next == NIL) {
return null;
} else {
return &elem_table[self.next];
}
}
};
var elem_table = [_]Elem{
Elem{ .data = 10, .next = 1 },
Elem{ .data = 20, .next = 2 },
Elem{ .data = 30, .next = 0 },
};
var head = &elem_table[0];
pub fn main() void {
var e = head;
while (true) {
std.log.debug("{d}", .{e.data});
if (e.getNext() == null) break;
e = e.getNext().?;
if (e == head) break;
}
}
the trick, of course, is to ensure getNext
incurs little/no overhead… given that initial value of elem_table
is known at comptime
, you’d think there would be some way to perform another comptime
transformation that executes getNext
with a known set of .next
values on an elem_table
that’s known…
in my use-case, i will be GENERATING a file that contains these static initializations; and adding some additional (advanced) comptime
initialization is not a problem for me…
the goal remains to minimize memory footprint on my MCU target – pushing as much work as possible to an upstream pass (which actually generates the aforementioned file) as well as any “exotic” initialization idioms…