U8 alignment and storing data types as bytes

Seems like my “hacky solution” is quite ok.

I tested my solution in godbolt to see the generated code.

Since zig doesn’t handle alignment over the minimum page size we can use std.mem.page_size as the maximum alignment.

// The Zig Allocator interface is not intended to solve alignments beyond
// the minimum OS page size. For these use cases, the caller must use OS
// APIs directly.

Link to comment

code (godbolt test)

export fn alignedAlloc(alignment: u32) usize {
    const Log2PageSizeType = std.math.IntFittingRange(0, std.math.log2(std.mem.page_size));
    const aligned: Log2PageSizeType = @intCast(std.math.log2(alignment));
    var b: usize = 0;
    switch (aligned) {
        inline else => |a| {
            b = 1 << a;
        },
    }
    return b;
}

generated assembly

alignedAlloc:
        lzcnt   eax, edi
        and     eax, 15
        xor     eax, 7
        mov     rax, qword ptr [8*rax + .Lswitch.table.alignedAlloc]
        ret

.Lswitch.table.alignedAlloc:
        .quad   256
        .quad   512
        .quad   1024
        .quad   2048
        .quad   4096
        .quad   8192
        .quad   16384
        .quad   32768
        .quad   1
        .quad   2
        .quad   4
        .quad   8
        .quad   16
        .quad   32
        .quad   64
        .quad   128

So the solution could look something like this:

pub fn alignedFree(allocator: Allocator, alignment: u29, memory: []u8) void {
    const Log2PageSizeType = std.math.IntFittingRange(0, std.math.log2(std.mem.page_size));
    const aligned: Log2PageSizeType = @intCast(std.math.log2(alignment));

    assert(std.mem.isValidAlign(alignment));
    assert(alignment <= std.mem.page_size);

    switch (aligned) {
        inline else => |a| {
            allocator.free(@as([]align(@as(usize, 1) << a) u8, @alignCast(memory)));
        },
    }
}

pub fn alignedAlloc(T: type, allocator: Allocator, alignment: u29, n: usize) ![]u8 {
    const Log2PageSizeType = std.math.IntFittingRange(0, std.math.log2(std.mem.page_size));
    const aligned: Log2PageSizeType = @intCast(std.math.log2(alignment));

    assert(std.mem.isValidAlign(alignment));

    switch (aligned) {
        inline else => |a| {
            if (builtin.mode == .Debug or builtin.mode == .ReleaseSafe) {
                if ((1 << a) <= std.mem.page_size) {
                    return try allocator.alignedAlloc(T, 1 << a, n);
                }
                panic("Alignment to big, maximum alignment is: {}.", .{std.mem.page_size});
            } else {
                return try allocator.alignedAlloc(T, 1 << a, n);
            }
        },
    }
}

Thanks for all the input, appriciate it!