@@ -9,8 +9,26 @@ const builtin = @import("builtin");
9
9
10
10
pub const Error = error {OutOfMemory };
11
11
12
- // The type erased pointer to the allocator implementation
13
- ptr : * anyopaque ,
12
+ // The type erased pointer to the allocator implementation. Stored in a union to
13
+ // allow the pointer to be either const or not without using tricks like
14
+ // @ptrToInt, which could hurt optimisation. We use a packed union to avoid safe
15
+ // builds from storing a tag with the union, which would increase the size of an
16
+ // Allocator and potentially hurt runtime performance.
17
+ pub const ImplPtr = packed union {
18
+ c : * const anyopaque ,
19
+ m : * anyopaque ,
20
+
21
+ inline fn convert (self : ImplPtr , comptime Ptr : type ) Ptr {
22
+ const alignment = std .meta .alignment (Ptr );
23
+
24
+ return if (comptime std .meta .trait .isConstPtr (Ptr ))
25
+ @ptrCast (Ptr , @alignCast (alignment , self .c ))
26
+ else
27
+ @ptrCast (Ptr , @alignCast (alignment , self .m ));
28
+ }
29
+ };
30
+
31
+ ptr : ImplPtr ,
14
32
vtable : * const VTable ,
15
33
16
34
pub const VTable = struct {
@@ -23,7 +41,7 @@ pub const VTable = struct {
23
41
///
24
42
/// `ret_addr` is optionally provided as the first return address of the allocation call stack.
25
43
/// If the value is `0` it means no return address has been provided.
26
- alloc : std .meta .FnPtr (fn (ptr : * anyopaque , len : usize , ptr_align : u29 , len_align : u29 , ret_addr : usize ) Error ! []u8 ),
44
+ alloc : std .meta .FnPtr (fn (ptr : ImplPtr , len : usize , ptr_align : u29 , len_align : u29 , ret_addr : usize ) Error ! []u8 ),
27
45
28
46
/// Attempt to expand or shrink memory in place. `buf.len` must equal the most recent
29
47
/// length returned by `alloc` or `resize`. `buf_align` must equal the same value
@@ -42,14 +60,14 @@ pub const VTable = struct {
42
60
///
43
61
/// `ret_addr` is optionally provided as the first return address of the allocation call stack.
44
62
/// If the value is `0` it means no return address has been provided.
45
- resize : std .meta .FnPtr (fn (ptr : * anyopaque , buf : []u8 , buf_align : u29 , new_len : usize , len_align : u29 , ret_addr : usize ) ? usize ),
63
+ resize : std .meta .FnPtr (fn (ptr : ImplPtr , buf : []u8 , buf_align : u29 , new_len : usize , len_align : u29 , ret_addr : usize ) ? usize ),
46
64
47
65
/// Free and invalidate a buffer. `buf.len` must equal the most recent length returned by `alloc` or `resize`.
48
66
/// `buf_align` must equal the same value that was passed as the `ptr_align` parameter to the original `alloc` call.
49
67
///
50
68
/// `ret_addr` is optionally provided as the first return address of the allocation call stack.
51
69
/// If the value is `0` it means no return address has been provided.
52
- free : std .meta .FnPtr (fn (ptr : * anyopaque , buf : []u8 , buf_align : u29 , ret_addr : usize ) void ),
70
+ free : std .meta .FnPtr (fn (ptr : ImplPtr , buf : []u8 , buf_align : u29 , ret_addr : usize ) void ),
53
71
};
54
72
55
73
pub fn init (
@@ -64,21 +82,18 @@ pub fn init(
64
82
assert (ptr_info == .Pointer ); // Must be a pointer
65
83
assert (ptr_info .Pointer .size == .One ); // Must be a single-item pointer
66
84
67
- const alignment = ptr_info .Pointer .alignment ;
85
+ const impl_ptr : ImplPtr = if ( ptr_info .Pointer .is_const ) .{ . c = pointer } else .{ . m = pointer } ;
68
86
69
87
const gen = struct {
70
- fn allocImpl (ptr : * anyopaque , len : usize , ptr_align : u29 , len_align : u29 , ret_addr : usize ) Error ! []u8 {
71
- const self = @ptrCast (Ptr , @alignCast (alignment , ptr ));
72
- return @call (.{ .modifier = .always_inline }, allocFn , .{ self , len , ptr_align , len_align , ret_addr });
88
+ fn allocImpl (ptr : ImplPtr , len : usize , ptr_align : u29 , len_align : u29 , ret_addr : usize ) Error ! []u8 {
89
+ return @call (.{ .modifier = .always_inline }, allocFn , .{ ptr .convert (Ptr ), len , ptr_align , len_align , ret_addr });
73
90
}
74
- fn resizeImpl (ptr : * anyopaque , buf : []u8 , buf_align : u29 , new_len : usize , len_align : u29 , ret_addr : usize ) ? usize {
91
+ fn resizeImpl (ptr : ImplPtr , buf : []u8 , buf_align : u29 , new_len : usize , len_align : u29 , ret_addr : usize ) ? usize {
75
92
assert (new_len != 0 );
76
- const self = @ptrCast (Ptr , @alignCast (alignment , ptr ));
77
- return @call (.{ .modifier = .always_inline }, resizeFn , .{ self , buf , buf_align , new_len , len_align , ret_addr });
93
+ return @call (.{ .modifier = .always_inline }, resizeFn , .{ ptr .convert (Ptr ), buf , buf_align , new_len , len_align , ret_addr });
78
94
}
79
- fn freeImpl (ptr : * anyopaque , buf : []u8 , buf_align : u29 , ret_addr : usize ) void {
80
- const self = @ptrCast (Ptr , @alignCast (alignment , ptr ));
81
- @call (.{ .modifier = .always_inline }, freeFn , .{ self , buf , buf_align , ret_addr });
95
+ fn freeImpl (ptr : ImplPtr , buf : []u8 , buf_align : u29 , ret_addr : usize ) void {
96
+ @call (.{ .modifier = .always_inline }, freeFn , .{ ptr .convert (Ptr ), buf , buf_align , ret_addr });
82
97
}
83
98
84
99
const vtable = VTable {
@@ -89,16 +104,16 @@ pub fn init(
89
104
};
90
105
91
106
return .{
92
- .ptr = pointer ,
107
+ .ptr = impl_ptr ,
93
108
.vtable = & gen .vtable ,
94
109
};
95
110
}
96
111
97
112
/// Set resizeFn to `NoResize(AllocatorType).noResize` if in-place resize is not supported.
98
- pub fn NoResize (comptime AllocatorType : type ) type {
113
+ pub fn NoResize (comptime AllocatorType : ? type ) type {
99
114
return struct {
100
115
pub fn noResize (
101
- self : * AllocatorType ,
116
+ self : if ( AllocatorType ) | T | * T else ImplPtr ,
102
117
buf : []u8 ,
103
118
buf_align : u29 ,
104
119
new_len : usize ,
@@ -115,10 +130,10 @@ pub fn NoResize(comptime AllocatorType: type) type {
115
130
}
116
131
117
132
/// Set freeFn to `NoOpFree(AllocatorType).noOpFree` if free is a no-op.
118
- pub fn NoOpFree (comptime AllocatorType : type ) type {
133
+ pub fn NoOpFree (comptime AllocatorType : ? type ) type {
119
134
return struct {
120
135
pub fn noOpFree (
121
- self : * AllocatorType ,
136
+ self : if ( AllocatorType ) | T | * T else ImplPtr ,
122
137
buf : []u8 ,
123
138
buf_align : u29 ,
124
139
ret_addr : usize ,
@@ -132,10 +147,10 @@ pub fn NoOpFree(comptime AllocatorType: type) type {
132
147
}
133
148
134
149
/// Set freeFn to `PanicFree(AllocatorType).panicFree` if free is not a supported operation.
135
- pub fn PanicFree (comptime AllocatorType : type ) type {
150
+ pub fn PanicFree (comptime AllocatorType : ? type ) type {
136
151
return struct {
137
152
pub fn panicFree (
138
- self : * AllocatorType ,
153
+ self : if ( AllocatorType ) | T | * T else ImplPtr ,
139
154
buf : []u8 ,
140
155
buf_align : u29 ,
141
156
ret_addr : usize ,
0 commit comments