Search code examples
zig

Zig: comptime params and alloc


i was trying to implement a List(like c#) in zig, but i get an error in alloc:

C:\ProgramData\chocolatey\lib\zig\tools\zig-windows-x86_64-0.12.0\lib\std\heap\arena_allocator.zig:181:38: error: unable to evaluate comptime expression var cur_node = if (self.state.buffer_list.first) |first_node|

Here is the code:

const std = @import("std");
const e = error{ OutOfMemory, ErrorReAlloc };

var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator);
pub fn Slice(size: usize, comptime T: type) !type {
    const alloc = arena.allocator();
    const tmemory = alloc.alloc(T, size) catch return e.OutOfMemory;
    return struct {
        const This = @This();
        var len = size;
        var memory = tmemory;
        fn Add(position: usize, value: anytype) !void {
            if (This.memory.len == 0) This.memory = try alloc.alloc(T, This.len);
            if (position >= This.len) {
                This.len += position - This.len + This.len / 2;
                const newM = alloc.realloc(This.memory, This.len) catch return e.ErrorReAlloc;
                std.mem.copyForwards(T, newM, This.memory);
                This.memory = tmemory;
            }
            This.memory[position] = value;
        }
        fn Get(position: usize) !u8 {
            if (position >= This.len) {
                return e.OutOfMemory;
            }
            return This.memory[position];
        }
    };
}
fn prova(a: u8) type {
    _ = a;
    return struct {};
}
pub fn main() !void {
    comptime var r = try Slice(2, u8);
    try r.Add(0, 1);
    try r.Add(1, 0);
    try r.Add(2, 9);
    for (0..r.len) |i| {
        std.debug.print("{d} = {d}\n", .{ i, try r.Get(i) }); // try r.Get(i);

    }
    defer arena.deinit();
}

i expecting that the alloc works, since at runtime there would be the type, don't understand why i can do this. If i do alloc into a function it work perfectly(using a type)


Solution

  • You're trying to allocate memory at compile time, which is not allowed.

    The function fn Slice(size: usize, comptime T: type) !type returns a type, this means that the function must be ran at compile time. That's why the call to alloc.alloc(T, size) fails.

    What is usually done is to add a function called init to the struct you are returning, and this function makes the allocations and returns an instance of Slice.

    As sigod suggested, this is the pattern that ArrayList uses. Also check out the tests of ArrayList for how this pattern is used.