I implemented a tagged pointers and tried to make it work with different word sizes. My only question is that if I wanted to make this properly cross platform, do I ever have to worry about the field ordering not working if pointers were implemented on a platform such that the least significant bit is first? (e.g. alignment starts from the left but the tag is positioned at the right)
What is a tagged pointer?
When a pointer is aligned to N, the log2(N) least significant bits are always zero so you can store information there.
pub fn TaggedPointer(T: type) type {
const P = switch (@typeInfo(T)) {
.pointer => |P| P,
else => @compileError("expected pointer"),
};
if (2 <= (P.alignment orelse @alignOf(P.child))) {
@compileError("alignment must be aligned to 2 or greater");
}
return packed struct(usize) {
const I = @Int(.unsigned, @bitSizeOf(usize) - 1);
data: I,
tag: enum(u1) {
pointer = 0,
int,
},
const Self = @This();
pub fn asPointer(self: Self) T {
std.debug.assert(self.tag == .pointer);
return @ptrFromInt(@as(usize, @bitCast(self)));
}
pub fn asInt(self: Self) I {
std.debug.assert(self.tag == .int);
return self.data;
}
pub fn fromPointer(p: T) Self {
const v: Self = @bitCast(@intFromPtr(p));
std.debug.assert(v.tag == .pointer);
return v;
}
pub fn fromInt(i: I) Self {
const v: Self = .{ .data = i, .tag = .int };
return v;
}
};
}
I was also considering if it was worth it to allow larger custom tag types if the alignment was large enough, I would just have to assert it fits and find the zero value.
AI was not used.