i’d like to revisit this approach, with a slightly more generalized solution:
const std = @import("std");
pub const NIL = ~@as(u16, 0);
const Elem = struct {
data: u32,
next: u16 = NIL,
};
pub fn getElem(idx: u16) ?*Elem {
return if (idx == NIL) null else &elem_tab[idx];
}
var elem_tab = [_]Elem{
Elem{ .data = 10, .next = 1 },
Elem{ .data = 20, .next = 2 },
Elem{ .data = 30, .next = 0 },
};
var head = getElem(0);
pub fn main() void {
var e = head.?;
while (true) {
std.log.debug("data = {d}", .{e.data});
if (getElem(e.next) == null) break;
e = getElem(e.next).?;
if (e == head) break;
}
}
as before, elem_tab
effectively contains cycles… but since the next
field is represented as an index into elem_tab
, i avoid the compiler dependency loop error…
something else quite remarkable about this approach (which i’ve verified in a more memory-constrained target) is the overhead of getElem
is virtually equivalent to using pointers directly… this approach is also smaller than any of the approaches using run-time initialization of elem_tab
…
equally remarkable, the compiler in the example above will “downgrade” var elem_tab
to constant status – since it sees none of its values being mutated… the space shows up in the image’s .const
rather than .data
section…
the challenge, of course, is that using getElem
with some index value is inherently error-prone and dangerous… unlike a typed pointer, the vanilla u16
used for my indicies don’t say anything about the type of the referenced object let alone the name of the array to be used as a base…
seems simple enough to create some generic types to wrap these relationships… but the problem is (as i’ve discovered after painfully trying) is that any value of a generic type that somehow references elem_tab
cannot be placed inside elem_tab
itself!!!
even moving the getElem
function inside some generic Index type leads to a dependency loop… the compiler has so far seen through all of my attempts to mask what i’m really trying to do here
any thoughts on how i can improve the safety of my index-based solution, without creating an actually dependency loop within elem_tab
???