| author | |
| committer | |
| log | a728436992415d1bce44b0c63938f6443a4e9a11 |
| tree | a650f594eaed11ee0ea45f84824136318c21d678 |
| parent | dc9648f868ed8ad08f040753767c03976bbcf3b7 |
6 files changed, 51 insertions(+), 61 deletions(-)
lib/std/array_list.zig-2| ... | @@ -220,7 +220,6 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type { | ... | @@ -220,7 +220,6 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type { |
| 220 | } | 220 | } |
| 221 | 221 | ||
| 222 | const new_memory = try self.allocator.reallocAtLeast(self.allocatedSlice(), better_capacity); | 222 | const new_memory = try self.allocator.reallocAtLeast(self.allocatedSlice(), better_capacity); |
| 223 | assert(new_memory.len >= better_capacity); | ||
| 224 | self.items.ptr = new_memory.ptr; | 223 | self.items.ptr = new_memory.ptr; |
| 225 | self.capacity = new_memory.len; | 224 | self.capacity = new_memory.len; |
| 226 | } | 225 | } |
| ... | @@ -443,7 +442,6 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ | ... | @@ -443,7 +442,6 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ |
| 443 | } | 442 | } |
| 444 | 443 | ||
| 445 | const new_memory = try allocator.reallocAtLeast(self.allocatedSlice(), better_capacity); | 444 | const new_memory = try allocator.reallocAtLeast(self.allocatedSlice(), better_capacity); |
| 446 | assert(new_memory.len >= better_capacity); | ||
| 447 | self.items.ptr = new_memory.ptr; | 445 | self.items.ptr = new_memory.ptr; |
| 448 | self.capacity = new_memory.len; | 446 | self.capacity = new_memory.len; |
| 449 | } | 447 | } |
lib/std/heap.zig+20-22| ... | @@ -25,7 +25,7 @@ usingnamespace if (comptime @hasDecl(c, "malloc_size")) struct { | ... | @@ -25,7 +25,7 @@ usingnamespace if (comptime @hasDecl(c, "malloc_size")) struct { |
| 25 | pub const supports_malloc_size = false; | 25 | pub const supports_malloc_size = false; |
| 26 | }; | 26 | }; |
| 27 | 27 | ||
| 28 | pub const c_allocator = mem.getAllocatorPtr(&c_allocator_state); | 28 | pub const c_allocator = &c_allocator_state; |
| 29 | var c_allocator_state = Allocator{ | 29 | var c_allocator_state = Allocator{ |
| 30 | .allocFn = cAlloc, | 30 | .allocFn = cAlloc, |
| 31 | .resizeFn = cResize, | 31 | .resizeFn = cResize, |
| ... | @@ -38,7 +38,7 @@ fn cAlloc(self: *Allocator, len: usize, ptr_align: u29, len_align: u29) Allocato | ... | @@ -38,7 +38,7 @@ fn cAlloc(self: *Allocator, len: usize, ptr_align: u29, len_align: u29) Allocato |
| 38 | return ptr[0..len]; | 38 | return ptr[0..len]; |
| 39 | } | 39 | } |
| 40 | const full_len = init: { | 40 | const full_len = init: { |
| 41 | if (comptime supports_malloc_size) { | 41 | if (supports_malloc_size) { |
| 42 | const s = malloc_size(ptr); | 42 | const s = malloc_size(ptr); |
| 43 | assert(s >= len); | 43 | assert(s >= len); |
| 44 | break :init s; | 44 | break :init s; |
| ... | @@ -56,24 +56,23 @@ fn cResize(self: *Allocator, buf: []u8, new_len: usize, len_align: u29) Allocato | ... | @@ -56,24 +56,23 @@ fn cResize(self: *Allocator, buf: []u8, new_len: usize, len_align: u29) Allocato |
| 56 | if (new_len <= buf.len) { | 56 | if (new_len <= buf.len) { |
| 57 | return mem.alignAllocLen(buf.len, new_len, len_align); | 57 | return mem.alignAllocLen(buf.len, new_len, len_align); |
| 58 | } | 58 | } |
| 59 | if (comptime supports_malloc_size) { | 59 | if (supports_malloc_size) { |
| 60 | const full_len = malloc_size(buf.ptr); | 60 | const full_len = malloc_size(buf.ptr); |
| 61 | if (new_len <= full_len) { | 61 | if (new_len <= full_len) { |
| 62 | return mem.alignAllocLen(full_len, new_len, len_align); | 62 | return mem.alignAllocLen(full_len, new_len, len_align); |
| 63 | } | 63 | } |
| 64 | } | 64 | } |
| 65 | // TODO: could we still use realloc? are there any cases where we can guarantee that realloc won't move memory? | ||
| 66 | return error.OutOfMemory; | 65 | return error.OutOfMemory; |
| 67 | } | 66 | } |
| 68 | 67 | ||
| 69 | /// This allocator makes a syscall directly for every allocation and free. | 68 | /// This allocator makes a syscall directly for every allocation and free. |
| 70 | /// Thread-safe and lock-free. | 69 | /// Thread-safe and lock-free. |
| 71 | pub const page_allocator = if (std.Target.current.isWasm()) | 70 | pub const page_allocator = if (std.Target.current.isWasm()) |
| 72 | mem.getAllocatorPtr(&wasm_page_allocator_state) | 71 | &wasm_page_allocator_state |
| 73 | else if (std.Target.current.os.tag == .freestanding) | 72 | else if (std.Target.current.os.tag == .freestanding) |
| 74 | root.os.heap.page_allocator | 73 | root.os.heap.page_allocator |
| 75 | else | 74 | else |
| 76 | mem.getAllocatorPtr(&page_allocator_state); | 75 | &page_allocator_state; |
| 77 | 76 | ||
| 78 | var page_allocator_state = Allocator{ | 77 | var page_allocator_state = Allocator{ |
| 79 | .allocFn = PageAllocator.alloc, | 78 | .allocFn = PageAllocator.alloc, |
| ... | @@ -507,9 +506,9 @@ pub const FixedBufferAllocator = struct { | ... | @@ -507,9 +506,9 @@ pub const FixedBufferAllocator = struct { |
| 507 | return sliceContainsSlice(self.buffer, slice); | 506 | return sliceContainsSlice(self.buffer, slice); |
| 508 | } | 507 | } |
| 509 | 508 | ||
| 510 | // NOTE: this will not work in all cases, if the last allocation had an adjusted_index | 509 | /// NOTE: this will not work in all cases, if the last allocation had an adjusted_index |
| 511 | // then we won't be able to determine what the last allocation was. This is because | 510 | /// then we won't be able to determine what the last allocation was. This is because |
| 512 | // the alignForward operation done in alloc is not reverisible. | 511 | /// the alignForward operation done in alloc is not reverisible. |
| 513 | pub fn isLastAllocation(self: *FixedBufferAllocator, buf: []u8) bool { | 512 | pub fn isLastAllocation(self: *FixedBufferAllocator, buf: []u8) bool { |
| 514 | return buf.ptr + buf.len == self.buffer.ptr + self.end_index; | 513 | return buf.ptr + buf.len == self.buffer.ptr + self.end_index; |
| 515 | } | 514 | } |
| ... | @@ -525,7 +524,7 @@ pub const FixedBufferAllocator = struct { | ... | @@ -525,7 +524,7 @@ pub const FixedBufferAllocator = struct { |
| 525 | const result = self.buffer[adjusted_index..new_end_index]; | 524 | const result = self.buffer[adjusted_index..new_end_index]; |
| 526 | self.end_index = new_end_index; | 525 | self.end_index = new_end_index; |
| 527 | 526 | ||
| 528 | return result[0..mem.alignAllocLen(result.len, n, len_align)]; | 527 | return result; |
| 529 | } | 528 | } |
| 530 | 529 | ||
| 531 | fn resize(allocator: *Allocator, buf: []u8, new_size: usize, len_align: u29) Allocator.Error!usize { | 530 | fn resize(allocator: *Allocator, buf: []u8, new_size: usize, len_align: u29) Allocator.Error!usize { |
| ... | @@ -544,13 +543,12 @@ pub const FixedBufferAllocator = struct { | ... | @@ -544,13 +543,12 @@ pub const FixedBufferAllocator = struct { |
| 544 | return if (new_size == 0) 0 else mem.alignAllocLen(buf.len - sub, new_size, len_align); | 543 | return if (new_size == 0) 0 else mem.alignAllocLen(buf.len - sub, new_size, len_align); |
| 545 | } | 544 | } |
| 546 | 545 | ||
| 547 | var add = new_size - buf.len; | 546 | const add = new_size - buf.len; |
| 548 | if (add + self.end_index > self.buffer.len) { | 547 | if (add + self.end_index > self.buffer.len) { |
| 549 | //add = self.buffer.len - self.end_index; | ||
| 550 | return error.OutOfMemory; | 548 | return error.OutOfMemory; |
| 551 | } | 549 | } |
| 552 | self.end_index += add; | 550 | self.end_index += add; |
| 553 | return mem.alignAllocLen(buf.len + add, new_size, len_align); | 551 | return new_size; |
| 554 | } | 552 | } |
| 555 | 553 | ||
| 556 | pub fn reset(self: *FixedBufferAllocator) void { | 554 | pub fn reset(self: *FixedBufferAllocator) void { |
| ... | @@ -735,7 +733,7 @@ test "ArenaAllocator" { | ... | @@ -735,7 +733,7 @@ test "ArenaAllocator" { |
| 735 | 733 | ||
| 736 | var test_fixed_buffer_allocator_memory: [800000 * @sizeOf(u64)]u8 = undefined; | 734 | var test_fixed_buffer_allocator_memory: [800000 * @sizeOf(u64)]u8 = undefined; |
| 737 | test "FixedBufferAllocator" { | 735 | test "FixedBufferAllocator" { |
| 738 | var fixed_buffer_allocator = mem.sanityWrap(FixedBufferAllocator.init(test_fixed_buffer_allocator_memory[0..])); | 736 | var fixed_buffer_allocator = mem.validationWrap(FixedBufferAllocator.init(test_fixed_buffer_allocator_memory[0..])); |
| 739 | 737 | ||
| 740 | try testAllocator(&fixed_buffer_allocator.allocator); | 738 | try testAllocator(&fixed_buffer_allocator.allocator); |
| 741 | try testAllocatorAligned(&fixed_buffer_allocator.allocator, 16); | 739 | try testAllocatorAligned(&fixed_buffer_allocator.allocator, 16); |
| ... | @@ -802,8 +800,8 @@ test "ThreadSafeFixedBufferAllocator" { | ... | @@ -802,8 +800,8 @@ test "ThreadSafeFixedBufferAllocator" { |
| 802 | } | 800 | } |
| 803 | 801 | ||
| 804 | fn testAllocator(base_allocator: *mem.Allocator) !void { | 802 | fn testAllocator(base_allocator: *mem.Allocator) !void { |
| 805 | var sanityAllocator = mem.sanityWrap(base_allocator); | 803 | var validationAllocator = mem.validationWrap(base_allocator); |
| 806 | const allocator = &sanityAllocator.allocator; | 804 | const allocator = &validationAllocator.allocator; |
| 807 | 805 | ||
| 808 | var slice = try allocator.alloc(*i32, 100); | 806 | var slice = try allocator.alloc(*i32, 100); |
| 809 | testing.expect(slice.len == 100); | 807 | testing.expect(slice.len == 100); |
| ... | @@ -833,8 +831,8 @@ fn testAllocator(base_allocator: *mem.Allocator) !void { | ... | @@ -833,8 +831,8 @@ fn testAllocator(base_allocator: *mem.Allocator) !void { |
| 833 | } | 831 | } |
| 834 | 832 | ||
| 835 | fn testAllocatorAligned(base_allocator: *mem.Allocator, comptime alignment: u29) !void { | 833 | fn testAllocatorAligned(base_allocator: *mem.Allocator, comptime alignment: u29) !void { |
| 836 | var sanityAllocator = mem.sanityWrap(base_allocator); | 834 | var validationAllocator = mem.validationWrap(base_allocator); |
| 837 | const allocator = &sanityAllocator.allocator; | 835 | const allocator = &validationAllocator.allocator; |
| 838 | 836 | ||
| 839 | // initial | 837 | // initial |
| 840 | var slice = try allocator.alignedAlloc(u8, alignment, 10); | 838 | var slice = try allocator.alignedAlloc(u8, alignment, 10); |
| ... | @@ -860,8 +858,8 @@ fn testAllocatorAligned(base_allocator: *mem.Allocator, comptime alignment: u29) | ... | @@ -860,8 +858,8 @@ fn testAllocatorAligned(base_allocator: *mem.Allocator, comptime alignment: u29) |
| 860 | } | 858 | } |
| 861 | 859 | ||
| 862 | fn testAllocatorLargeAlignment(base_allocator: *mem.Allocator) mem.Allocator.Error!void { | 860 | fn testAllocatorLargeAlignment(base_allocator: *mem.Allocator) mem.Allocator.Error!void { |
| 863 | var sanityAllocator = mem.sanityWrap(base_allocator); | 861 | var validationAllocator = mem.validationWrap(base_allocator); |
| 864 | const allocator = &sanityAllocator.allocator; | 862 | const allocator = &validationAllocator.allocator; |
| 865 | 863 | ||
| 866 | //Maybe a platform's page_size is actually the same as or | 864 | //Maybe a platform's page_size is actually the same as or |
| 867 | // very near usize? | 865 | // very near usize? |
| ... | @@ -892,8 +890,8 @@ fn testAllocatorLargeAlignment(base_allocator: *mem.Allocator) mem.Allocator.Err | ... | @@ -892,8 +890,8 @@ fn testAllocatorLargeAlignment(base_allocator: *mem.Allocator) mem.Allocator.Err |
| 892 | } | 890 | } |
| 893 | 891 | ||
| 894 | fn testAllocatorAlignedShrink(base_allocator: *mem.Allocator) mem.Allocator.Error!void { | 892 | fn testAllocatorAlignedShrink(base_allocator: *mem.Allocator) mem.Allocator.Error!void { |
| 895 | var sanityAllocator = mem.sanityWrap(base_allocator); | 893 | var validationAllocator = mem.validationWrap(base_allocator); |
| 896 | const allocator = &sanityAllocator.allocator; | 894 | const allocator = &validationAllocator.allocator; |
| 897 | 895 | ||
| 898 | var debug_buffer: [1000]u8 = undefined; | 896 | var debug_buffer: [1000]u8 = undefined; |
| 899 | const debug_allocator = &FixedBufferAllocator.init(&debug_buffer).allocator; | 897 | const debug_allocator = &FixedBufferAllocator.init(&debug_buffer).allocator; |
lib/std/heap/arena_allocator.zig+1-1| ... | @@ -77,7 +77,7 @@ pub const ArenaAllocator = struct { | ... | @@ -77,7 +77,7 @@ pub const ArenaAllocator = struct { |
| 77 | } | 77 | } |
| 78 | const result = cur_buf[adjusted_index..new_end_index]; | 78 | const result = cur_buf[adjusted_index..new_end_index]; |
| 79 | self.state.end_index = new_end_index; | 79 | self.state.end_index = new_end_index; |
| 80 | return result[0..mem.alignAllocLen(result.len, n, len_align)]; | 80 | return result; |
| 81 | } | 81 | } |
| 82 | } | 82 | } |
| 83 | }; | 83 | }; |
lib/std/heap/logging_allocator.zig+1-1| ... | @@ -70,7 +70,7 @@ test "LoggingAllocator" { | ... | @@ -70,7 +70,7 @@ test "LoggingAllocator" { |
| 70 | var fbs = std.io.fixedBufferStream(&log_buf); | 70 | var fbs = std.io.fixedBufferStream(&log_buf); |
| 71 | 71 | ||
| 72 | var allocator_buf: [10]u8 = undefined; | 72 | var allocator_buf: [10]u8 = undefined; |
| 73 | var fixedBufferAllocator = std.mem.sanityWrap(std.heap.FixedBufferAllocator.init(&allocator_buf)); | 73 | var fixedBufferAllocator = std.mem.validationWrap(std.heap.FixedBufferAllocator.init(&allocator_buf)); |
| 74 | const allocator = &loggingAllocator(&fixedBufferAllocator.allocator, fbs.outStream()).allocator; | 74 | const allocator = &loggingAllocator(&fixedBufferAllocator.allocator, fbs.outStream()).allocator; |
| 75 | 75 | ||
| 76 | var a = try allocator.alloc(u8, 10); | 76 | var a = try allocator.alloc(u8, 10); |
lib/std/mem.zig+28-34| ... | @@ -141,6 +141,9 @@ pub const Allocator = struct { | ... | @@ -141,6 +141,9 @@ pub const Allocator = struct { |
| 141 | const new_mem = try self.callAllocFn(new_len, new_alignment, len_align); | 141 | const new_mem = try self.callAllocFn(new_len, new_alignment, len_align); |
| 142 | @memcpy(new_mem.ptr, old_mem.ptr, std.math.min(new_len, old_mem.len)); | 142 | @memcpy(new_mem.ptr, old_mem.ptr, std.math.min(new_len, old_mem.len)); |
| 143 | // DISABLED TO AVOID BUGS IN TRANSLATE C | 143 | // DISABLED TO AVOID BUGS IN TRANSLATE C |
| 144 | // use './zig build test-translate-c' to reproduce, some of the symbols in the | ||
| 145 | // generated C code will be a sequence of 0xaa (the undefined value), meaning | ||
| 146 | // it is printing data that has been freed | ||
| 144 | //@memset(old_mem.ptr, undefined, old_mem.len); | 147 | //@memset(old_mem.ptr, undefined, old_mem.len); |
| 145 | _ = self.shrinkBytes(old_mem, 0, 0); | 148 | _ = self.shrinkBytes(old_mem, 0, 0); |
| 146 | return new_mem; | 149 | return new_mem; |
| ... | @@ -214,6 +217,7 @@ pub const Allocator = struct { | ... | @@ -214,6 +217,7 @@ pub const Allocator = struct { |
| 214 | return self.allocWithOptions(Elem, n, null, sentinel); | 217 | return self.allocWithOptions(Elem, n, null, sentinel); |
| 215 | } | 218 | } |
| 216 | 219 | ||
| 220 | /// Deprecated: use `allocAdvanced` | ||
| 217 | pub fn alignedAlloc( | 221 | pub fn alignedAlloc( |
| 218 | self: *Allocator, | 222 | self: *Allocator, |
| 219 | comptime T: type, | 223 | comptime T: type, |
| ... | @@ -221,11 +225,11 @@ pub const Allocator = struct { | ... | @@ -221,11 +225,11 @@ pub const Allocator = struct { |
| 221 | comptime alignment: ?u29, | 225 | comptime alignment: ?u29, |
| 222 | n: usize, | 226 | n: usize, |
| 223 | ) Error![]align(alignment orelse @alignOf(T)) T { | 227 | ) Error![]align(alignment orelse @alignOf(T)) T { |
| 224 | return self.alignedAlloc2(T, alignment, n, .exact); | 228 | return self.allocAdvanced(T, alignment, n, .exact); |
| 225 | } | 229 | } |
| 226 | 230 | ||
| 227 | const Exact = enum {exact,atLeast}; | 231 | const Exact = enum {exact,at_least}; |
| 228 | pub fn alignedAlloc2( | 232 | pub fn allocAdvanced( |
| 229 | self: *Allocator, | 233 | self: *Allocator, |
| 230 | comptime T: type, | 234 | comptime T: type, |
| 231 | /// null means naturally aligned | 235 | /// null means naturally aligned |
| ... | @@ -234,7 +238,7 @@ pub const Allocator = struct { | ... | @@ -234,7 +238,7 @@ pub const Allocator = struct { |
| 234 | exact: Exact, | 238 | exact: Exact, |
| 235 | ) Error![]align(alignment orelse @alignOf(T)) T { | 239 | ) Error![]align(alignment orelse @alignOf(T)) T { |
| 236 | const a = if (alignment) |a| blk: { | 240 | const a = if (alignment) |a| blk: { |
| 237 | if (a == @alignOf(T)) return alignedAlloc2(self, T, null, n, exact); | 241 | if (a == @alignOf(T)) return allocAdvanced(self, T, null, n, exact); |
| 238 | break :blk a; | 242 | break :blk a; |
| 239 | } else @alignOf(T); | 243 | } else @alignOf(T); |
| 240 | 244 | ||
| ... | @@ -248,7 +252,10 @@ pub const Allocator = struct { | ... | @@ -248,7 +252,10 @@ pub const Allocator = struct { |
| 248 | // functions that heap-allocate their own frame with @Frame(func). | 252 | // functions that heap-allocate their own frame with @Frame(func). |
| 249 | const sizeOfT = if (alignment == null) @intCast(u29, @divExact(byte_count, n)) else @sizeOf(T); | 253 | const sizeOfT = if (alignment == null) @intCast(u29, @divExact(byte_count, n)) else @sizeOf(T); |
| 250 | const byte_slice = try self.callAllocFn(byte_count, a, if (exact == .exact) @as(u29, 0) else sizeOfT); | 254 | const byte_slice = try self.callAllocFn(byte_count, a, if (exact == .exact) @as(u29, 0) else sizeOfT); |
| 251 | assert(if (exact == .exact) byte_slice.len == byte_count else byte_slice.len >= byte_count); | 255 | switch (exact) { |
| 256 | .exact => assert(byte_slice.len == byte_count), | ||
| 257 | .at_least => assert(byte_slice.len >= byte_count), | ||
| 258 | } | ||
| 252 | @memset(byte_slice.ptr, undefined, byte_slice.len); | 259 | @memset(byte_slice.ptr, undefined, byte_slice.len); |
| 253 | if (alignment == null) { | 260 | if (alignment == null) { |
| 254 | // This if block is a workaround (see comment above) | 261 | // This if block is a workaround (see comment above) |
| ... | @@ -273,7 +280,7 @@ pub const Allocator = struct { | ... | @@ -273,7 +280,7 @@ pub const Allocator = struct { |
| 273 | break :t Error![]align(Slice.alignment) Slice.child; | 280 | break :t Error![]align(Slice.alignment) Slice.child; |
| 274 | } { | 281 | } { |
| 275 | const old_alignment = @typeInfo(@TypeOf(old_mem)).Pointer.alignment; | 282 | const old_alignment = @typeInfo(@TypeOf(old_mem)).Pointer.alignment; |
| 276 | return self.alignedRealloc2(old_mem, old_alignment, new_n, .exact); | 283 | return self.reallocAdvanced(old_mem, old_alignment, new_n, .exact); |
| 277 | } | 284 | } |
| 278 | 285 | ||
| 279 | pub fn reallocAtLeast(self: *Allocator, old_mem: var, new_n: usize) t: { | 286 | pub fn reallocAtLeast(self: *Allocator, old_mem: var, new_n: usize) t: { |
| ... | @@ -281,25 +288,23 @@ pub const Allocator = struct { | ... | @@ -281,25 +288,23 @@ pub const Allocator = struct { |
| 281 | break :t Error![]align(Slice.alignment) Slice.child; | 288 | break :t Error![]align(Slice.alignment) Slice.child; |
| 282 | } { | 289 | } { |
| 283 | const old_alignment = @typeInfo(@TypeOf(old_mem)).Pointer.alignment; | 290 | const old_alignment = @typeInfo(@TypeOf(old_mem)).Pointer.alignment; |
| 284 | return self.alignedRealloc2(old_mem, old_alignment, new_n, .atLeast); | 291 | return self.reallocAdvanced(old_mem, old_alignment, new_n, .at_least); |
| 285 | } | 292 | } |
| 286 | 293 | ||
| 287 | /// This is the same as `realloc`, except caller may additionally request | 294 | // Deprecated: use `reallocAdvanced` |
| 288 | /// a new alignment, which can be larger, smaller, or the same as the old | ||
| 289 | /// allocation. | ||
| 290 | pub fn alignedRealloc( | 295 | pub fn alignedRealloc( |
| 291 | self: *Allocator, | 296 | self: *Allocator, |
| 292 | old_mem: var, | 297 | old_mem: var, |
| 293 | comptime new_alignment: u29, | 298 | comptime new_alignment: u29, |
| 294 | new_n: usize, | 299 | new_n: usize, |
| 295 | ) Error![]align(new_alignment) @typeInfo(@TypeOf(old_mem)).Pointer.child { | 300 | ) Error![]align(new_alignment) @typeInfo(@TypeOf(old_mem)).Pointer.child { |
| 296 | return self.alignedRealloc2(old_mem, new_alignment, new_n, .exact); | 301 | return self.reallocAdvanced(old_mem, new_alignment, new_n, .exact); |
| 297 | } | 302 | } |
| 298 | 303 | ||
| 299 | /// This is the same as `realloc`, except caller may additionally request | 304 | /// This is the same as `realloc`, except caller may additionally request |
| 300 | /// a new alignment, which can be larger, smaller, or the same as the old | 305 | /// a new alignment, which can be larger, smaller, or the same as the old |
| 301 | /// allocation. | 306 | /// allocation. |
| 302 | pub fn alignedRealloc2( | 307 | pub fn reallocAdvanced( |
| 303 | self: *Allocator, | 308 | self: *Allocator, |
| 304 | old_mem: var, | 309 | old_mem: var, |
| 305 | comptime new_alignment: u29, | 310 | comptime new_alignment: u29, |
| ... | @@ -309,7 +314,7 @@ pub const Allocator = struct { | ... | @@ -309,7 +314,7 @@ pub const Allocator = struct { |
| 309 | const Slice = @typeInfo(@TypeOf(old_mem)).Pointer; | 314 | const Slice = @typeInfo(@TypeOf(old_mem)).Pointer; |
| 310 | const T = Slice.child; | 315 | const T = Slice.child; |
| 311 | if (old_mem.len == 0) { | 316 | if (old_mem.len == 0) { |
| 312 | return self.alignedAlloc2(T, new_alignment, new_n, exact); | 317 | return self.allocAdvanced(T, new_alignment, new_n, exact); |
| 313 | } | 318 | } |
| 314 | if (new_n == 0) { | 319 | if (new_n == 0) { |
| 315 | self.free(old_mem); | 320 | self.free(old_mem); |
| ... | @@ -392,24 +397,9 @@ pub const Allocator = struct { | ... | @@ -392,24 +397,9 @@ pub const Allocator = struct { |
| 392 | } | 397 | } |
| 393 | }; | 398 | }; |
| 394 | 399 | ||
| 395 | /// Given a pointer to an allocator, return the *Allocator for it. `allocatorStatePtr` can | 400 | /// Detects and asserts if the std.mem.Allocator interface is violated by the caller |
| 396 | /// either be a `*Allocator`, in which case it is returned as-is, otherwise, the address of | 401 | /// or the allocator. |
| 397 | /// the `allocator` field is returned. | 402 | pub fn ValidationAllocator(comptime T: type) type { return struct { |
| 398 | pub fn getAllocatorPtr(allocatorStatePtr: var) *Allocator { | ||
| 399 | // allocator must be a pointer or else this function will return a copy of the allocator which | ||
| 400 | // is not what this is for | ||
| 401 | const T = @TypeOf(allocatorStatePtr); | ||
| 402 | switch (@typeInfo(T)) { | ||
| 403 | .Pointer => {}, | ||
| 404 | else => @compileError("getAllocatorPtr expects a pointer to an allocator but got: " ++ @typeName(T)), | ||
| 405 | } | ||
| 406 | if (T == *Allocator) | ||
| 407 | return allocatorStatePtr; | ||
| 408 | return &allocatorStatePtr.allocator; | ||
| 409 | } | ||
| 410 | |||
| 411 | /// Detects and asserts if the std.mem.Allocator interface is violated | ||
| 412 | pub fn SanityAllocator(comptime T: type) type { return struct { | ||
| 413 | const Self = @This(); | 403 | const Self = @This(); |
| 414 | allocator: Allocator, | 404 | allocator: Allocator, |
| 415 | underlying_allocator: T, | 405 | underlying_allocator: T, |
| ... | @@ -424,7 +414,8 @@ pub fn SanityAllocator(comptime T: type) type { return struct { | ... | @@ -424,7 +414,8 @@ pub fn SanityAllocator(comptime T: type) type { return struct { |
| 424 | } | 414 | } |
| 425 | fn getUnderlyingAllocatorPtr(self: *@This()) *Allocator { | 415 | fn getUnderlyingAllocatorPtr(self: *@This()) *Allocator { |
| 426 | if (T == *Allocator) return self.underlying_allocator; | 416 | if (T == *Allocator) return self.underlying_allocator; |
| 427 | return getAllocatorPtr(&self.underlying_allocator); | 417 | if (*T == *Allocator) return &self.underlying_allocator; |
| 418 | return &self.underlying_allocator.allocator; | ||
| 428 | } | 419 | } |
| 429 | pub fn alloc(allocator: *Allocator, n: usize, ptr_align: u29, len_align: u29) Allocator.Error![]u8 { | 420 | pub fn alloc(allocator: *Allocator, n: usize, ptr_align: u29, len_align: u29) Allocator.Error![]u8 { |
| 430 | assert(n > 0); | 421 | assert(n > 0); |
| ... | @@ -436,6 +427,7 @@ pub fn SanityAllocator(comptime T: type) type { return struct { | ... | @@ -436,6 +427,7 @@ pub fn SanityAllocator(comptime T: type) type { return struct { |
| 436 | 427 | ||
| 437 | const self = @fieldParentPtr(@This(), "allocator", allocator); | 428 | const self = @fieldParentPtr(@This(), "allocator", allocator); |
| 438 | const result = try self.getUnderlyingAllocatorPtr().callAllocFn(n, ptr_align, len_align); | 429 | const result = try self.getUnderlyingAllocatorPtr().callAllocFn(n, ptr_align, len_align); |
| 430 | assert(mem.isAligned(@ptrToInt(result.ptr), ptr_align)); | ||
| 439 | if (len_align == 0) { | 431 | if (len_align == 0) { |
| 440 | assert(result.len == n); | 432 | assert(result.len == n); |
| 441 | } else { | 433 | } else { |
| ... | @@ -467,8 +459,8 @@ pub fn SanityAllocator(comptime T: type) type { return struct { | ... | @@ -467,8 +459,8 @@ pub fn SanityAllocator(comptime T: type) type { return struct { |
| 467 | }; | 459 | }; |
| 468 | };} | 460 | };} |
| 469 | 461 | ||
| 470 | pub fn sanityWrap(allocator: var) SanityAllocator(@TypeOf(allocator)) { | 462 | pub fn validationWrap(allocator: var) ValidationAllocator(@TypeOf(allocator)) { |
| 471 | return SanityAllocator(@TypeOf(allocator)).init(allocator); | 463 | return ValidationAllocator(@TypeOf(allocator)).init(allocator); |
| 472 | } | 464 | } |
| 473 | 465 | ||
| 474 | /// An allocator helper function. Adjusts an allocation length satisfy `len_align`. | 466 | /// An allocator helper function. Adjusts an allocation length satisfy `len_align`. |
| ... | @@ -2377,6 +2369,8 @@ test "alignForward" { | ... | @@ -2377,6 +2369,8 @@ test "alignForward" { |
| 2377 | testing.expect(alignForward(17, 8) == 24); | 2369 | testing.expect(alignForward(17, 8) == 24); |
| 2378 | } | 2370 | } |
| 2379 | 2371 | ||
| 2372 | /// Round an address up to the previous aligned address | ||
| 2373 | /// Unlike `alignBackward`, `alignment` can be any positive number, not just a power of 2. | ||
| 2380 | pub fn alignBackwardAnyAlign(i: usize, alignment: usize) usize { | 2374 | pub fn alignBackwardAnyAlign(i: usize, alignment: usize) usize { |
| 2381 | if (@popCount(usize, alignment) == 1) | 2375 | if (@popCount(usize, alignment) == 1) |
| 2382 | return alignBackward(i, alignment); | 2376 | return alignBackward(i, alignment); |
lib/std/testing.zig+1-1| ... | @@ -11,7 +11,7 @@ pub var allocator_instance = LeakCountAllocator.init(&base_allocator_instance.al | ... | @@ -11,7 +11,7 @@ pub var allocator_instance = LeakCountAllocator.init(&base_allocator_instance.al |
| 11 | pub const failing_allocator = &failing_allocator_instance.allocator; | 11 | pub const failing_allocator = &failing_allocator_instance.allocator; |
| 12 | pub var failing_allocator_instance = FailingAllocator.init(&base_allocator_instance.allocator, 0); | 12 | pub var failing_allocator_instance = FailingAllocator.init(&base_allocator_instance.allocator, 0); |
| 13 | 13 | ||
| 14 | pub var base_allocator_instance = std.mem.sanityWrap(std.heap.ThreadSafeFixedBufferAllocator.init(allocator_mem[0..])); | 14 | pub var base_allocator_instance = std.mem.validationWrap(std.heap.ThreadSafeFixedBufferAllocator.init(allocator_mem[0..])); |
| 15 | var allocator_mem: [2 * 1024 * 1024]u8 = undefined; | 15 | var allocator_mem: [2 * 1024 * 1024]u8 = undefined; |
| 16 | 16 | ||
| 17 | /// This function is intended to be used only in tests. It prints diagnostics to stderr | 17 | /// This function is intended to be used only in tests. It prints diagnostics to stderr |