authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2018-02-12 02:27:02-05:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2018-02-12 02:44:31-05:00
log4a4ea92cf38372dc63184957e2936fa7989743fb
tree94866dbdde8065d23016ed23f2dc09af18ed85da
parent445b03384a5ffcace11927aa9dd5f21604527f5c

remove std.heap.IncrementingAllocator

Use std.heap.FixedBufferAllocator combined with std.heap.DirectAllocator instead. std.mem.FixedBufferAllocator is moved to std.heap.FixedBufferAllocator

7 files changed, 60 insertions(+), 140 deletions(-)

std/debug/index.zig+1-1
...@@ -1078,5 +1078,5 @@ fn readILeb128(in_stream: var) !i64 {...@@ -1078,5 +1078,5 @@ fn readILeb128(in_stream: var) !i64 {
1078}1078}
10791079
1080pub const global_allocator = &global_fixed_allocator.allocator;1080pub const global_allocator = &global_fixed_allocator.allocator;
1081var global_fixed_allocator = mem.FixedBufferAllocator.init(global_allocator_mem[0..]);1081var global_fixed_allocator = std.heap.FixedBufferAllocator.init(global_allocator_mem[0..]);
1082var global_allocator_mem: [100 * 1024]u8 = undefined;1082var global_allocator_mem: [100 * 1024]u8 = undefined;
std/heap.zig+52-87
...@@ -39,74 +39,6 @@ fn cFree(self: &Allocator, old_mem: []u8) void {...@@ -39,74 +39,6 @@ fn cFree(self: &Allocator, old_mem: []u8) void {
39 c.free(old_ptr);39 c.free(old_ptr);
40}40}
4141
42/// Use this allocator when you want to allocate completely up front and guarantee that individual
43/// allocations will never make syscalls.
44pub const IncrementingAllocator = struct {
45 allocator: Allocator,
46 bytes: []u8,
47 end_index: usize,
48 direct_allocator: DirectAllocator,
49
50 pub fn init(capacity: usize) !IncrementingAllocator {
51 var direct_allocator = DirectAllocator.init();
52 const bytes = try direct_allocator.allocator.alloc(u8, capacity);
53 errdefer direct_allocator.allocator.free(bytes);
54
55 return IncrementingAllocator {
56 .allocator = Allocator {
57 .allocFn = alloc,
58 .reallocFn = realloc,
59 .freeFn = free,
60 },
61 .bytes = bytes,
62 .direct_allocator = direct_allocator,
63 .end_index = 0,
64 };
65 }
66
67 pub fn deinit(self: &IncrementingAllocator) void {
68 self.direct_allocator.allocator.free(self.bytes);
69 self.direct_allocator.deinit();
70 }
71
72 fn reset(self: &IncrementingAllocator) void {
73 self.end_index = 0;
74 }
75
76 fn bytesLeft(self: &const IncrementingAllocator) usize {
77 return self.bytes.len - self.end_index;
78 }
79
80 fn alloc(allocator: &Allocator, n: usize, alignment: u29) ![]u8 {
81 const self = @fieldParentPtr(IncrementingAllocator, "allocator", allocator);
82 const addr = @ptrToInt(&self.bytes[self.end_index]);
83 const rem = @rem(addr, alignment);
84 const march_forward_bytes = if (rem == 0) 0 else (alignment - rem);
85 const adjusted_index = self.end_index + march_forward_bytes;
86 const new_end_index = adjusted_index + n;
87 if (new_end_index > self.bytes.len) {
88 return error.OutOfMemory;
89 }
90 const result = self.bytes[adjusted_index .. new_end_index];
91 self.end_index = new_end_index;
92 return result;
93 }
94
95 fn realloc(allocator: &Allocator, old_mem: []u8, new_size: usize, alignment: u29) ![]u8 {
96 if (new_size <= old_mem.len) {
97 return old_mem[0..new_size];
98 } else {
99 const result = try alloc(allocator, new_size, alignment);
100 mem.copy(u8, result, old_mem);
101 return result;
102 }
103 }
104
105 fn free(allocator: &Allocator, bytes: []u8) void {
106 // Do nothing. That's the point of an incrementing allocator.
107 }
108};
109
110/// This allocator makes a syscall directly for every allocation and free.42/// This allocator makes a syscall directly for every allocation and free.
111pub const DirectAllocator = struct {43pub const DirectAllocator = struct {
112 allocator: Allocator,44 allocator: Allocator,
...@@ -327,34 +259,60 @@ pub const ArenaAllocator = struct {...@@ -327,34 +259,60 @@ pub const ArenaAllocator = struct {
327 fn free(allocator: &Allocator, bytes: []u8) void { }259 fn free(allocator: &Allocator, bytes: []u8) void { }
328};260};
329261
262pub const FixedBufferAllocator = struct {
263 allocator: Allocator,
264 end_index: usize,
265 buffer: []u8,
330266
331267 pub fn init(buffer: []u8) FixedBufferAllocator {
332test "c_allocator" {268 return FixedBufferAllocator {
333 if (builtin.link_libc) {269 .allocator = Allocator {
334 var slice = c_allocator.alloc(u8, 50) catch return;270 .allocFn = alloc,
335 defer c_allocator.free(slice);271 .reallocFn = realloc,
336 slice = c_allocator.realloc(u8, slice, 100) catch return;272 .freeFn = free,
273 },
274 .buffer = buffer,
275 .end_index = 0,
276 };
337 }277 }
338}
339278
340test "IncrementingAllocator" {279 fn alloc(allocator: &Allocator, n: usize, alignment: u29) ![]u8 {
341 const total_bytes = 10 * 1024 * 1024;280 const self = @fieldParentPtr(FixedBufferAllocator, "allocator", allocator);
342 var inc_allocator = try IncrementingAllocator.init(total_bytes);281 const addr = @ptrToInt(&self.buffer[self.end_index]);
343 defer inc_allocator.deinit();282 const rem = @rem(addr, alignment);
283 const march_forward_bytes = if (rem == 0) 0 else (alignment - rem);
284 const adjusted_index = self.end_index + march_forward_bytes;
285 const new_end_index = adjusted_index + n;
286 if (new_end_index > self.buffer.len) {
287 return error.OutOfMemory;
288 }
289 const result = self.buffer[adjusted_index .. new_end_index];
290 self.end_index = new_end_index;
344291
345 const allocator = &inc_allocator.allocator;292 return result;
346 const slice = try allocator.alloc(&i32, 100);293 }
347294
348 for (slice) |*item, i| {295 fn realloc(allocator: &Allocator, old_mem: []u8, new_size: usize, alignment: u29) ![]u8 {
349 *item = try allocator.create(i32);296 if (new_size <= old_mem.len) {
350 **item = i32(i);297 return old_mem[0..new_size];
298 } else {
299 const result = try alloc(allocator, new_size, alignment);
300 mem.copy(u8, result, old_mem);
301 return result;
302 }
351 }303 }
352304
353 assert(inc_allocator.bytesLeft() == total_bytes - @sizeOf(i32) * 100 - @sizeOf(usize) * 100);305 fn free(allocator: &Allocator, bytes: []u8) void { }
306};
307
354308
355 inc_allocator.reset();
356309
357 assert(inc_allocator.bytesLeft() == total_bytes);310test "c_allocator" {
311 if (builtin.link_libc) {
312 var slice = c_allocator.alloc(u8, 50) catch return;
313 defer c_allocator.free(slice);
314 slice = c_allocator.realloc(u8, slice, 100) catch return;
315 }
358}316}
359317
360test "DirectAllocator" {318test "DirectAllocator" {
...@@ -375,6 +333,13 @@ test "ArenaAllocator" {...@@ -375,6 +333,13 @@ test "ArenaAllocator" {
375 try testAllocator(&arena_allocator.allocator);333 try testAllocator(&arena_allocator.allocator);
376}334}
377335
336var test_fixed_buffer_allocator_memory: [30000 * @sizeOf(usize)]u8 = undefined;
337test "FixedBufferAllocator" {
338 var fixed_buffer_allocator = FixedBufferAllocator.init(test_fixed_buffer_allocator_memory[0..]);
339
340 try testAllocator(&fixed_buffer_allocator.allocator);
341}
342
378fn testAllocator(allocator: &mem.Allocator) !void {343fn testAllocator(allocator: &mem.Allocator) !void {
379 var slice = try allocator.alloc(&i32, 100);344 var slice = try allocator.alloc(&i32, 100);
380345
std/mem.zig-45
...@@ -111,51 +111,6 @@ pub const Allocator = struct {...@@ -111,51 +111,6 @@ pub const Allocator = struct {
111 }111 }
112};112};
113113
114pub const FixedBufferAllocator = struct {
115 allocator: Allocator,
116 end_index: usize,
117 buffer: []u8,
118
119 pub fn init(buffer: []u8) FixedBufferAllocator {
120 return FixedBufferAllocator {
121 .allocator = Allocator {
122 .allocFn = alloc,
123 .reallocFn = realloc,
124 .freeFn = free,
125 },
126 .buffer = buffer,
127 .end_index = 0,
128 };
129 }
130
131 fn alloc(allocator: &Allocator, n: usize, alignment: u29) ![]u8 {
132 const self = @fieldParentPtr(FixedBufferAllocator, "allocator", allocator);
133 const addr = @ptrToInt(&self.buffer[self.end_index]);
134 const rem = @rem(addr, alignment);
135 const march_forward_bytes = if (rem == 0) 0 else (alignment - rem);
136 const adjusted_index = self.end_index + march_forward_bytes;
137 const new_end_index = adjusted_index + n;
138 if (new_end_index > self.buffer.len) {
139 return error.OutOfMemory;
140 }
141 const result = self.buffer[adjusted_index .. new_end_index];
142 self.end_index = new_end_index;
143 return result;
144 }
145
146 fn realloc(allocator: &Allocator, old_mem: []u8, new_size: usize, alignment: u29) ![]u8 {
147 if (new_size <= old_mem.len) {
148 return old_mem[0..new_size];
149 } else {
150 const result = try alloc(allocator, new_size, alignment);
151 copy(u8, result, old_mem);
152 return result;
153 }
154 }
155
156 fn free(allocator: &Allocator, bytes: []u8) void { }
157};
158
159/// Copy all of source into dest at position 0.114/// Copy all of source into dest at position 0.
160/// dest.len must be >= source.len.115/// dest.len must be >= source.len.
161pub fn copy(comptime T: type, dest: []T, source: []const T) void {116pub fn copy(comptime T: type, dest: []T, source: []const T) void {
std/os/child_process.zig+2-2
...@@ -363,7 +363,7 @@ pub const ChildProcess = struct {...@@ -363,7 +363,7 @@ pub const ChildProcess = struct {
363 const dev_null_fd = if (any_ignore) blk: {363 const dev_null_fd = if (any_ignore) blk: {
364 const dev_null_path = "/dev/null";364 const dev_null_path = "/dev/null";
365 var fixed_buffer_mem: [dev_null_path.len + 1]u8 = undefined;365 var fixed_buffer_mem: [dev_null_path.len + 1]u8 = undefined;
366 var fixed_allocator = mem.FixedBufferAllocator.init(fixed_buffer_mem[0..]);366 var fixed_allocator = std.heap.FixedBufferAllocator.init(fixed_buffer_mem[0..]);
367 break :blk try os.posixOpen(&fixed_allocator.allocator, "/dev/null", posix.O_RDWR, 0);367 break :blk try os.posixOpen(&fixed_allocator.allocator, "/dev/null", posix.O_RDWR, 0);
368 } else blk: {368 } else blk: {
369 break :blk undefined;369 break :blk undefined;
...@@ -472,7 +472,7 @@ pub const ChildProcess = struct {...@@ -472,7 +472,7 @@ pub const ChildProcess = struct {
472 const nul_handle = if (any_ignore) blk: {472 const nul_handle = if (any_ignore) blk: {
473 const nul_file_path = "NUL";473 const nul_file_path = "NUL";
474 var fixed_buffer_mem: [nul_file_path.len + 1]u8 = undefined;474 var fixed_buffer_mem: [nul_file_path.len + 1]u8 = undefined;
475 var fixed_allocator = mem.FixedBufferAllocator.init(fixed_buffer_mem[0..]);475 var fixed_allocator = std.heap.FixedBufferAllocator.init(fixed_buffer_mem[0..]);
476 break :blk try os.windowsOpen(&fixed_allocator.allocator, "NUL", windows.GENERIC_READ, windows.FILE_SHARE_READ,476 break :blk try os.windowsOpen(&fixed_allocator.allocator, "NUL", windows.GENERIC_READ, windows.FILE_SHARE_READ,
477 windows.OPEN_EXISTING, windows.FILE_ATTRIBUTE_NORMAL);477 windows.OPEN_EXISTING, windows.FILE_ATTRIBUTE_NORMAL);
478 } else blk: {478 } else blk: {
std/os/index.zig+2-2
...@@ -1702,12 +1702,12 @@ pub fn openSelfExe() !os.File {...@@ -1702,12 +1702,12 @@ pub fn openSelfExe() !os.File {
1702 Os.linux => {1702 Os.linux => {
1703 const proc_file_path = "/proc/self/exe";1703 const proc_file_path = "/proc/self/exe";
1704 var fixed_buffer_mem: [proc_file_path.len + 1]u8 = undefined;1704 var fixed_buffer_mem: [proc_file_path.len + 1]u8 = undefined;
1705 var fixed_allocator = mem.FixedBufferAllocator.init(fixed_buffer_mem[0..]);1705 var fixed_allocator = std.heap.FixedBufferAllocator.init(fixed_buffer_mem[0..]);
1706 return os.File.openRead(&fixed_allocator.allocator, proc_file_path);1706 return os.File.openRead(&fixed_allocator.allocator, proc_file_path);
1707 },1707 },
1708 Os.macosx, Os.ios => {1708 Os.macosx, Os.ios => {
1709 var fixed_buffer_mem: [darwin.PATH_MAX * 2]u8 = undefined;1709 var fixed_buffer_mem: [darwin.PATH_MAX * 2]u8 = undefined;
1710 var fixed_allocator = mem.FixedBufferAllocator.init(fixed_buffer_mem[0..]);1710 var fixed_allocator = std.heap.FixedBufferAllocator.init(fixed_buffer_mem[0..]);
1711 const self_exe_path = try selfExePath(&fixed_allocator.allocator);1711 const self_exe_path = try selfExePath(&fixed_allocator.allocator);
1712 return os.File.openRead(&fixed_allocator.allocator, self_exe_path);1712 return os.File.openRead(&fixed_allocator.allocator, self_exe_path);
1713 },1713 },
std/sort.zig+1-1
...@@ -1094,7 +1094,7 @@ var fixed_buffer_mem: [100 * 1024]u8 = undefined;...@@ -1094,7 +1094,7 @@ var fixed_buffer_mem: [100 * 1024]u8 = undefined;
10941094
1095fn fuzzTest(rng: &std.rand.Rand) void {1095fn fuzzTest(rng: &std.rand.Rand) void {
1096 const array_size = rng.range(usize, 0, 1000);1096 const array_size = rng.range(usize, 0, 1000);
1097 var fixed_allocator = mem.FixedBufferAllocator.init(fixed_buffer_mem[0..]);1097 var fixed_allocator = std.heap.FixedBufferAllocator.init(fixed_buffer_mem[0..]);
1098 var array = fixed_allocator.allocator.alloc(IdAndValue, array_size) catch unreachable;1098 var array = fixed_allocator.allocator.alloc(IdAndValue, array_size) catch unreachable;
1099 // populate with random data1099 // populate with random data
1100 for (array) |*item, index| {1100 for (array) |*item, index| {
std/zig/parser.zig+2-2
...@@ -1060,7 +1060,7 @@ fn testParse(source: []const u8, allocator: &mem.Allocator) ![]u8 {...@@ -1060,7 +1060,7 @@ fn testParse(source: []const u8, allocator: &mem.Allocator) ![]u8 {
1060fn testCanonical(source: []const u8) !void {1060fn testCanonical(source: []const u8) !void {
1061 const needed_alloc_count = x: {1061 const needed_alloc_count = x: {
1062 // Try it once with unlimited memory, make sure it works1062 // Try it once with unlimited memory, make sure it works
1063 var fixed_allocator = mem.FixedBufferAllocator.init(fixed_buffer_mem[0..]);1063 var fixed_allocator = std.heap.FixedBufferAllocator.init(fixed_buffer_mem[0..]);
1064 var failing_allocator = std.debug.FailingAllocator.init(&fixed_allocator.allocator, @maxValue(usize));1064 var failing_allocator = std.debug.FailingAllocator.init(&fixed_allocator.allocator, @maxValue(usize));
1065 const result_source = try testParse(source, &failing_allocator.allocator);1065 const result_source = try testParse(source, &failing_allocator.allocator);
1066 if (!mem.eql(u8, result_source, source)) {1066 if (!mem.eql(u8, result_source, source)) {
...@@ -1077,7 +1077,7 @@ fn testCanonical(source: []const u8) !void {...@@ -1077,7 +1077,7 @@ fn testCanonical(source: []const u8) !void {
10771077
1078 var fail_index: usize = 0;1078 var fail_index: usize = 0;
1079 while (fail_index < needed_alloc_count) : (fail_index += 1) {1079 while (fail_index < needed_alloc_count) : (fail_index += 1) {
1080 var fixed_allocator = mem.FixedBufferAllocator.init(fixed_buffer_mem[0..]);1080 var fixed_allocator = std.heap.FixedBufferAllocator.init(fixed_buffer_mem[0..]);
1081 var failing_allocator = std.debug.FailingAllocator.init(&fixed_allocator.allocator, fail_index);1081 var failing_allocator = std.debug.FailingAllocator.init(&fixed_allocator.allocator, fail_index);
1082 if (testParse(source, &failing_allocator.allocator)) |_| {1082 if (testParse(source, &failing_allocator.allocator)) |_| {
1083 return error.NondeterministicMemoryUsage;1083 return error.NondeterministicMemoryUsage;