Probably the following is possible. Maybe someone has a brilliant way…
I have this generic Map which basically stores an array of width * height elements and lots of methods to operate on that 2-dimensional data using indexing y * width + x
.
pub fn Map(comptime T: type) type
{
return struct
{
allocator: std.mem.Allocator,
width: u32,
height: u32,
data: []T,
// ... lots of methods...
};
}
Now I would like to have a fixed version as well without duplicating code.
// const len = comptime known width / height
data: [len]T
And what about the allocator?
A fixed version would have the benefit of not having to free resources.
Another problem is that some operations are not possible in the fixed version of the Map, like resize
. There we could maybe insert @compileError("not allowed on fixed map")
;
And: is it a good idea anyway to do this?
I actually think the standard library should do what you’re talking about here in their own containers. There’s currently a lot of duplicated logic between BoundedArray
and ArrayList
. I started writing a PR for it but never finished.
What you need to do is extract everything that differs between the concrete implementations into an object that you receive as a parameter:
pub fn Map(comptime T: type, comptime Memory: type) type {
return struct{
memory: Memory
width: u32,
height: u32,
pub fn get(self: *@This(), x: u32, y: u32) *T{
const data: []T = self.memory.data();
return &data[getIndex(x, y)];
}
};
}
fn DynamicMemory(comptime T: type) type{
return struct{
allocator: Allocator,
slice: []T,
pub fn data(self: *@This()) []T{
return self.slice;
}
};
}
fn FixedMemory(comptime T: type, comptime size: usize) type{
return struct{
array: [size]T
pub fn data(self: *@This()) []T{
return &self.array;
}
};
}
1 Like
I was a bit experimenting and turned it like this (code not 100% correct but you get the idea probably). And not yet sure if it would work…
The thing is restricting some methods with compile-errors and no allocator in case of fixed.
pub const Size = struct
{
width: u32, height: u32
};
pub fn Map(comptime T: type) type
{
return VolatileMap(T, null);
}
pub fn FixedMap(comptime T: type, comptime size: Size) type
{
return VolatileMap(T, size);
}
pub fn VolatileMap(comptime T: type, comptime size: ?Size) type
{
return struct
{
const IS_FIXED: bool = if (size) |s| true else false;
const DataType: if (size) |s| [size.width * size.height]T else []T;
allocator: std.mem.Allocator,
width: u32,
height: u32,
data: DataType,
// ... lots of methods...
};
}