Simple array of ?ObjectPointer with automatic resizing and automatic storage allocation.
const ObjectArray = struct
const ObjectArray = struct {
const ObjectPointer = *anyopaque;
// content of the array
slots: []?ObjectPointer,
/// create a new ObjectArray with n slots. must call deinit() to deallocate.
pub fn init(n: usize) *ObjectArray {
const array = simple_allocator.alloc(ObjectArray);
array.* = ObjectArray{
.slots = simple_allocator.allocSlice(?ObjectPointer, n),
};
for (array.slots) |*object| {
object.* = null;
}
return array;
}
/// deallocate the ObjectArray.
pub fn deinit(self: *ObjectArray) void {
// deallocated used objects in the array
for (self.slots) |*object| {
simple_allocator.free(object.*);
}
simple_allocator.free(self.slots);
simple_allocator.free(self);
}
/// resize the ObjectArray if needed.
pub fn ensureLength(self: *ObjectArray, new_len: usize) *ObjectArray {
const old_len = self.slots.len;
if (old_len > new_len) {
return self;
}
// reallocate
self.slots = simple_allocator.reallocSlice(?ObjectPointer, self.slots, new_len);
// init newly added slots
for (self.slots[old_len..]) |*object| {
object.* = null;
}
return self;
}
/// Retrieve the pointer at request index, using control to initialize it if needed.
pub fn getPointer(self: *ObjectArray, index: usize, control: *emutls_control) ObjectPointer {
if (self.slots[index] == null) {
// initialize the slot
const size = control.size;
const alignment: u29 = @truncate(control.alignment);
var data = simple_allocator.advancedAlloc(alignment, size);
errdefer simple_allocator.free(data);
if (control.default_value) |value| {
// default value: copy the content to newly allocated object.
@memcpy(data[0..size], @as([*]const u8, @ptrCast(value)));
} else {
// no default: return zeroed memory.
@memset(data[0..size], 0);
}
self.slots[index] = data;
}
return self.slots[index].?;
}
}