Hi! I’m implementing a basic reference-counted pointer wrapper struct, RcPtr
, to use in a WASM library. Most of the implementation is straightforward, but I’m stuck on writing the deinit
method.
The struct looks like this:
pub fn RcPtr(comptime T: type) type {
return extern struct {
len: usize,
ptr: *T,
self_ptr: *RcPtr(T),
root_ptr: *RcPtr(T),
// Creating new reference = adding clone
clones: ?*ArrayList(*RcPtr(T)),
};
}
RcPtr.ptr could be a single item pointer (eg. T = *u8
) — or something that can be cast to a multi item pointer (eg. []u8
or [*]u8). Most of the implementation is straightforward, but I’m stuck on deinit. Deallocating the memory for RcPtr’s underlying value requires knowing whether to call allocator.free
, if T is a multi-item pointer, or allocator.destroy
if it’s a single item pointer.
My code looks like this:
pub fn deinit(comptime T: type, rc_ptr: RcPtr(T), allocator: Allocator) void {
var clones = rc_ptr.root_ptr.*.clones.?.*;
const ref_count = clones.items.len;
std.log.debug("Refcount {d}", .{ref_count});
if (ref_count > 0) {
allocator.destroy(rc_ptr.self_ptr);
return;
}
// No living refs, initialize self destruct sequence!
const value_ptr = rc_ptr.ptr;
if (isMultiItemPointer(value_ptr)) {
// Multi item pointer
allocator.free(value_ptr.*);
} else {
// Single item pointer
allocator.destroy(value_ptr);
}
// This will destroy rc_ptr, since it's in clones, so it's invalid from here on out
while (clones.popOrNull()) |c| {
allocator.destroy(c);
}
clones.deinit();
}
How can I implement isMultiItemPointer(value_ptr)
?