Skip to content

Commit

Permalink
Merge pull request #5064 from marler8997/newAllocator
Browse files Browse the repository at this point in the history
new allocator interface
  • Loading branch information
andrewrk authored Jun 27, 2020
2 parents 626b5ec + a728436 commit 0cfe8e5
Show file tree
Hide file tree
Showing 10 changed files with 610 additions and 457 deletions.
4 changes: 2 additions & 2 deletions lib/std/array_list.zig
Original file line number Diff line number Diff line change
Expand Up @@ -219,7 +219,7 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type {
if (better_capacity >= new_capacity) break;
}

const new_memory = try self.allocator.realloc(self.allocatedSlice(), better_capacity);
const new_memory = try self.allocator.reallocAtLeast(self.allocatedSlice(), better_capacity);
self.items.ptr = new_memory.ptr;
self.capacity = new_memory.len;
}
Expand Down Expand Up @@ -441,7 +441,7 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ
if (better_capacity >= new_capacity) break;
}

const new_memory = try allocator.realloc(self.allocatedSlice(), better_capacity);
const new_memory = try allocator.reallocAtLeast(self.allocatedSlice(), better_capacity);
self.items.ptr = new_memory.ptr;
self.capacity = new_memory.len;
}
Expand Down
11 changes: 11 additions & 0 deletions lib/std/c.zig
Original file line number Diff line number Diff line change
Expand Up @@ -233,6 +233,17 @@ pub extern "c" fn setuid(uid: c_uint) c_int;

pub extern "c" fn aligned_alloc(alignment: usize, size: usize) ?*c_void;
pub extern "c" fn malloc(usize) ?*c_void;

pub usingnamespace switch (builtin.os.tag) {
.linux, .freebsd, .kfreebsd, .netbsd, .openbsd => struct {
pub extern "c" fn malloc_usable_size(?*const c_void) usize;
},
.macosx, .ios, .watchos, .tvos => struct {
pub extern "c" fn malloc_size(?*const c_void) usize;
},
else => struct {},
};

pub extern "c" fn realloc(?*c_void, usize) ?*c_void;
pub extern "c" fn free(*c_void) void;
pub extern "c" fn posix_memalign(memptr: **c_void, alignment: usize, size: usize) c_int;
Expand Down
584 changes: 265 additions & 319 deletions lib/std/heap.zig

Large diffs are not rendered by default.

27 changes: 6 additions & 21 deletions lib/std/heap/arena_allocator.zig
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@ pub const ArenaAllocator = struct {
pub fn promote(self: State, child_allocator: *Allocator) ArenaAllocator {
return .{
.allocator = Allocator{
.reallocFn = realloc,
.shrinkFn = shrink,
.allocFn = alloc,
.resizeFn = Allocator.noResize,
},
.child_allocator = child_allocator,
.state = self,
Expand Down Expand Up @@ -61,38 +61,23 @@ pub const ArenaAllocator = struct {
return buf_node;
}

fn alloc(allocator: *Allocator, n: usize, alignment: u29) ![]u8 {
fn alloc(allocator: *Allocator, n: usize, ptr_align: u29, len_align: u29) ![]u8 {
const self = @fieldParentPtr(ArenaAllocator, "allocator", allocator);

var cur_node = if (self.state.buffer_list.first) |first_node| first_node else try self.createNode(0, n + alignment);
var cur_node = if (self.state.buffer_list.first) |first_node| first_node else try self.createNode(0, n + ptr_align);
while (true) {
const cur_buf = cur_node.data[@sizeOf(BufNode)..];
const addr = @ptrToInt(cur_buf.ptr) + self.state.end_index;
const adjusted_addr = mem.alignForward(addr, alignment);
const adjusted_addr = mem.alignForward(addr, ptr_align);
const adjusted_index = self.state.end_index + (adjusted_addr - addr);
const new_end_index = adjusted_index + n;
if (new_end_index > cur_buf.len) {
cur_node = try self.createNode(cur_buf.len, n + alignment);
cur_node = try self.createNode(cur_buf.len, n + ptr_align);
continue;
}
const result = cur_buf[adjusted_index..new_end_index];
self.state.end_index = new_end_index;
return result;
}
}

fn realloc(allocator: *Allocator, old_mem: []u8, old_align: u29, new_size: usize, new_align: u29) ![]u8 {
if (new_size <= old_mem.len and new_align <= new_size) {
// We can't do anything with the memory, so tell the client to keep it.
return error.OutOfMemory;
} else {
const result = try alloc(allocator, new_size, new_align);
@memcpy(result.ptr, old_mem.ptr, std.math.min(old_mem.len, result.len));
return result;
}
}

fn shrink(allocator: *Allocator, old_mem: []u8, old_align: u29, new_size: usize, new_align: u29) []u8 {
return old_mem[0..new_size];
}
};
61 changes: 37 additions & 24 deletions lib/std/heap/logging_allocator.zig
Original file line number Diff line number Diff line change
Expand Up @@ -15,39 +15,45 @@ pub fn LoggingAllocator(comptime OutStreamType: type) type {
pub fn init(parent_allocator: *Allocator, out_stream: OutStreamType) Self {
return Self{
.allocator = Allocator{
.reallocFn = realloc,
.shrinkFn = shrink,
.allocFn = alloc,
.resizeFn = resize,
},
.parent_allocator = parent_allocator,
.out_stream = out_stream,
};
}

fn realloc(allocator: *Allocator, old_mem: []u8, old_align: u29, new_size: usize, new_align: u29) ![]u8 {
fn alloc(allocator: *Allocator, len: usize, ptr_align: u29, len_align: u29) error{OutOfMemory}![]u8 {
const self = @fieldParentPtr(Self, "allocator", allocator);
if (old_mem.len == 0) {
self.out_stream.print("allocation of {} ", .{new_size}) catch {};
} else {
self.out_stream.print("resize from {} to {} ", .{ old_mem.len, new_size }) catch {};
}
const result = self.parent_allocator.reallocFn(self.parent_allocator, old_mem, old_align, new_size, new_align);
self.out_stream.print("alloc : {}", .{len}) catch {};
const result = self.parent_allocator.callAllocFn(len, ptr_align, len_align);
if (result) |buff| {
self.out_stream.print("success!\n", .{}) catch {};
self.out_stream.print(" success!\n", .{}) catch {};
} else |err| {
self.out_stream.print("failure!\n", .{}) catch {};
self.out_stream.print(" failure!\n", .{}) catch {};
}
return result;
}

fn shrink(allocator: *Allocator, old_mem: []u8, old_align: u29, new_size: usize, new_align: u29) []u8 {
fn resize(allocator: *Allocator, buf: []u8, new_len: usize, len_align: u29) error{OutOfMemory}!usize {
const self = @fieldParentPtr(Self, "allocator", allocator);
const result = self.parent_allocator.shrinkFn(self.parent_allocator, old_mem, old_align, new_size, new_align);
if (new_size == 0) {
self.out_stream.print("free of {} bytes success!\n", .{old_mem.len}) catch {};
if (new_len == 0) {
self.out_stream.print("free : {}\n", .{buf.len}) catch {};
} else if (new_len <= buf.len) {
self.out_stream.print("shrink: {} to {}\n", .{buf.len, new_len}) catch {};
} else {
self.out_stream.print("shrink from {} bytes to {} bytes success!\n", .{ old_mem.len, new_size }) catch {};
self.out_stream.print("expand: {} to {}", .{ buf.len, new_len }) catch {};
}
if (self.parent_allocator.callResizeFn(buf, new_len, len_align)) |resized_len| {
if (new_len > buf.len) {
self.out_stream.print(" success!\n", .{}) catch {};
}
return resized_len;
} else |e| {
std.debug.assert(new_len > buf.len);
self.out_stream.print(" failure!\n", .{}) catch {};
return e;
}
return result;
}
};
}
Expand All @@ -60,17 +66,24 @@ pub fn loggingAllocator(
}

test "LoggingAllocator" {
var buf: [255]u8 = undefined;
var fbs = std.io.fixedBufferStream(&buf);
var log_buf: [255]u8 = undefined;
var fbs = std.io.fixedBufferStream(&log_buf);

const allocator = &loggingAllocator(std.testing.allocator, fbs.outStream()).allocator;
var allocator_buf: [10]u8 = undefined;
var fixedBufferAllocator = std.mem.validationWrap(std.heap.FixedBufferAllocator.init(&allocator_buf));
const allocator = &loggingAllocator(&fixedBufferAllocator.allocator, fbs.outStream()).allocator;

const ptr = try allocator.alloc(u8, 10);
allocator.free(ptr);
var a = try allocator.alloc(u8, 10);
a.len = allocator.shrinkBytes(a, 5, 0);
std.debug.assert(a.len == 5);
std.testing.expectError(error.OutOfMemory, allocator.callResizeFn(a, 20, 0));
allocator.free(a);

std.testing.expectEqualSlices(u8,
\\allocation of 10 success!
\\free of 10 bytes success!
\\alloc : 10 success!
\\shrink: 10 to 5
\\expand: 5 to 20 failure!
\\free : 5
\\
, fbs.getWritten());
}
Loading

0 comments on commit 0cfe8e5

Please sign in to comment.