const HeapAllocator: type = switch (builtin.os.tag) { .windows => struct { heap_handle: ?HeapHandle, const HeapHandle = os.windows.HANDLE; pub fn init() HeapAllocator { return HeapAllocator{ .heap_handle = null, }; } pub fn allocator(self: *HeapAllocator) Allocator { return .{ .ptr = self, .vtable = &.{ .alloc = alloc, .resize = resize, .free = free, }, }; } pub fn deinit(self: *HeapAllocator) void { if (self.heap_handle) |heap_handle| { os.windows.HeapDestroy(heap_handle); } } fn getRecordPtr(buf: []u8) *align(1) usize { return @as(*align(1) usize, @ptrFromInt(@intFromPtr(buf.ptr) + buf.len)); } fn alloc( ctx: *anyopaque, n: usize, log2_ptr_align: u8, return_address: usize, ) ?[*]u8 { _ = return_address; const self: *HeapAllocator = @ptrCast(@alignCast(ctx)); const ptr_align = @as(usize, 1) << @as(Allocator.Log2Align, @intCast(log2_ptr_align)); const amt = n + ptr_align - 1 + @sizeOf(usize); const optional_heap_handle = @atomicLoad(?HeapHandle, &self.heap_handle, .SeqCst); const heap_handle = optional_heap_handle orelse blk: { const options = if (builtin.single_threaded) os.windows.HEAP_NO_SERIALIZE else 0; const hh = os.windows.kernel32.HeapCreate(options, amt, 0) orelse return null; const other_hh = @cmpxchgStrong(?HeapHandle, &self.heap_handle, null, hh, .SeqCst, .SeqCst) orelse break :blk hh; os.windows.HeapDestroy(hh); break :blk other_hh.?; // can't be null because of the cmpxchg }; const ptr = os.windows.kernel32.HeapAlloc(heap_handle, 0, amt) orelse return null; const root_addr = @intFromPtr(ptr); const aligned_addr = mem.alignForward(usize, root_addr, ptr_align); const buf = @as([*]u8, @ptrFromInt(aligned_addr))[0..n]; getRecordPtr(buf).* = root_addr; return buf.ptr; } fn resize( ctx: *anyopaque, buf: []u8, log2_buf_align: u8, new_size: usize, return_address: usize, ) bool { _ = log2_buf_align; _ = return_address; const self: *HeapAllocator = @ptrCast(@alignCast(ctx)); const root_addr = getRecordPtr(buf).*; const align_offset = @intFromPtr(buf.ptr) - root_addr; const amt = align_offset + new_size + @sizeOf(usize); const new_ptr = os.windows.kernel32.HeapReAlloc( self.heap_handle.?, os.windows.HEAP_REALLOC_IN_PLACE_ONLY, @as(*anyopaque, @ptrFromInt(root_addr)), amt, ) orelse return false; assert(new_ptr == @as(*anyopaque, @ptrFromInt(root_addr))); getRecordPtr(buf.ptr[0..new_size]).* = root_addr; return true; } fn free( ctx: *anyopaque, buf: []u8, log2_buf_align: u8, return_address: usize, ) void { _ = log2_buf_align; _ = return_address; const self: *HeapAllocator = @ptrCast(@alignCast(ctx)); os.windows.HeapFree(self.heap_handle.?, 0, @as(*anyopaque, @ptrFromInt(getRecordPtr(buf).*))); } }, else => @compileError("Unsupported OS"), };
[src]