1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
|
const mem = @import("std").mem;
const builtin = @import("std").builtin;
const std = @import("std");
const mimalloc = @import("./allocators/mimalloc.zig");
const c = struct {
pub const malloc_size = mimalloc.mi_malloc_size;
pub const malloc_usable_size = mimalloc.mi_malloc_usable_size;
pub const malloc = mimalloc.mi_malloc;
pub const free = mimalloc.mi_free;
};
const Allocator = mem.Allocator;
const assert = std.debug.assert;
const CAllocator = struct {
comptime {
if (!@import("builtin").link_libc) {
@compileError("C allocator is only available when linking against libc");
}
}
usingnamespace if (@hasDecl(c, "malloc_size"))
struct {
pub const supports_malloc_size = true;
pub const malloc_size = c.malloc_size;
}
else if (@hasDecl(c, "malloc_usable_size"))
struct {
pub const supports_malloc_size = true;
pub const malloc_size = c.malloc_usable_size;
}
else if (@hasDecl(c, "_msize"))
struct {
pub const supports_malloc_size = true;
pub const malloc_size = c._msize;
}
else
struct {
pub const supports_malloc_size = false;
};
pub const supports_posix_memalign = @hasDecl(c, "posix_memalign");
fn getHeader(ptr: [*]u8) *[*]u8 {
return @intToPtr(*[*]u8, @ptrToInt(ptr) - @sizeOf(usize));
}
fn alignedAlloc(len: usize, alignment: usize) ?[*]u8 {
if (supports_posix_memalign) {
// The posix_memalign only accepts alignment values that are a
// multiple of the pointer size
const eff_alignment = std.math.max(alignment, @sizeOf(usize));
var aligned_ptr: ?*anyopaque = undefined;
if (c.posix_memalign(&aligned_ptr, eff_alignment, len) != 0)
return null;
return @ptrCast([*]u8, aligned_ptr);
}
// Thin wrapper around regular malloc, overallocate to account for
// alignment padding and store the orignal malloc()'ed pointer before
// the aligned address.
var unaligned_ptr = @ptrCast([*]u8, c.malloc(len + alignment - 1 + @sizeOf(usize)) orelse return null);
const unaligned_addr = @ptrToInt(unaligned_ptr);
const aligned_addr = mem.alignForward(unaligned_addr + @sizeOf(usize), alignment);
var aligned_ptr = unaligned_ptr + (aligned_addr - unaligned_addr);
getHeader(aligned_ptr).* = unaligned_ptr;
return aligned_ptr;
}
fn alignedFree(ptr: [*]u8) void {
if (supports_posix_memalign) {
return c.free(ptr);
}
const unaligned_ptr = getHeader(ptr).*;
c.free(unaligned_ptr);
}
fn alignedAllocSize(ptr: [*]u8) usize {
if (supports_posix_memalign) {
return CAllocator.malloc_size(ptr);
}
const unaligned_ptr = getHeader(ptr).*;
const delta = @ptrToInt(ptr) - @ptrToInt(unaligned_ptr);
return CAllocator.malloc_size(unaligned_ptr) - delta;
}
fn alloc(
_: *anyopaque,
len: usize,
alignment: u29,
len_align: u29,
return_address: usize,
) error{OutOfMemory}![]u8 {
_ = return_address;
assert(len > 0);
assert(std.math.isPowerOfTwo(alignment));
var ptr = alignedAlloc(len, alignment) orelse return error.OutOfMemory;
if (len_align == 0) {
return ptr[0..len];
}
const full_len = init: {
if (CAllocator.supports_malloc_size) {
const s = alignedAllocSize(ptr);
assert(s >= len);
break :init s;
}
break :init len;
};
return ptr[0..mem.alignBackwardAnyAlign(full_len, len_align)];
}
fn resize(
_: *anyopaque,
buf: []u8,
buf_align: u29,
new_len: usize,
len_align: u29,
return_address: usize,
) ?usize {
_ = buf_align;
_ = return_address;
if (new_len <= buf.len) {
return mem.alignAllocLen(buf.len, new_len, len_align);
}
if (CAllocator.supports_malloc_size) {
const full_len = alignedAllocSize(buf.ptr);
if (new_len <= full_len) {
return mem.alignAllocLen(full_len, new_len, len_align);
}
}
return null;
}
fn free(
_: *anyopaque,
buf: []u8,
buf_align: u29,
return_address: usize,
) void {
_ = buf_align;
_ = return_address;
alignedFree(buf.ptr);
}
};
pub const c_allocator = Allocator{
.ptr = undefined,
.vtable = &c_allocator_vtable,
};
const c_allocator_vtable = Allocator.VTable{
.alloc = CAllocator.alloc,
.resize = CAllocator.resize,
.free = CAllocator.free,
};
|