| 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 | 220 | } |
| 221 | 221 | |
| 222 | 222 | const new_memory = try self.allocator.reallocAtLeast(self.allocatedSlice(), better_capacity); |
| 223 | assert(new_memory.len >= better_capacity); | |
| 224 | 223 | self.items.ptr = new_memory.ptr; |
| 225 | 224 | self.capacity = new_memory.len; |
| 226 | 225 | } |
| ... | ... | @@ -443,7 +442,6 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ |
| 443 | 442 | } |
| 444 | 443 | |
| 445 | 444 | const new_memory = try allocator.reallocAtLeast(self.allocatedSlice(), better_capacity); |
| 446 | assert(new_memory.len >= better_capacity); | |
| 447 | 445 | self.items.ptr = new_memory.ptr; |
| 448 | 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 | 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 | 29 | var c_allocator_state = Allocator{ |
| 30 | 30 | .allocFn = cAlloc, |
| 31 | 31 | .resizeFn = cResize, |
| ... | ... | @@ -38,7 +38,7 @@ fn cAlloc(self: *Allocator, len: usize, ptr_align: u29, len_align: u29) Allocato |
| 38 | 38 | return ptr[0..len]; |
| 39 | 39 | } |
| 40 | 40 | const full_len = init: { |
| 41 | if (comptime supports_malloc_size) { | |
| 41 | if (supports_malloc_size) { | |
| 42 | 42 | const s = malloc_size(ptr); |
| 43 | 43 | assert(s >= len); |
| 44 | 44 | break :init s; |
| ... | ... | @@ -56,24 +56,23 @@ fn cResize(self: *Allocator, buf: []u8, new_len: usize, len_align: u29) Allocato |
| 56 | 56 | if (new_len <= buf.len) { |
| 57 | 57 | return mem.alignAllocLen(buf.len, new_len, len_align); |
| 58 | 58 | } |
| 59 | if (comptime supports_malloc_size) { | |
| 59 | if (supports_malloc_size) { | |
| 60 | 60 | const full_len = malloc_size(buf.ptr); |
| 61 | 61 | if (new_len <= full_len) { |
| 62 | 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 | 65 | return error.OutOfMemory; |
| 67 | 66 | } |
| 68 | 67 | |
| 69 | 68 | /// This allocator makes a syscall directly for every allocation and free. |
| 70 | 69 | /// Thread-safe and lock-free. |
| 71 | 70 | pub const page_allocator = if (std.Target.current.isWasm()) |
| 72 | mem.getAllocatorPtr(&wasm_page_allocator_state) | |
| 71 | &wasm_page_allocator_state | |
| 73 | 72 | else if (std.Target.current.os.tag == .freestanding) |
| 74 | 73 | root.os.heap.page_allocator |
| 75 | 74 | else |
| 76 | mem.getAllocatorPtr(&page_allocator_state); | |
| 75 | &page_allocator_state; | |
| 77 | 76 | |
| 78 | 77 | var page_allocator_state = Allocator{ |
| 79 | 78 | .allocFn = PageAllocator.alloc, |
| ... | ... | @@ -507,9 +506,9 @@ pub const FixedBufferAllocator = struct { |
| 507 | 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 | |
| 511 | // 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. | |
| 509 | /// NOTE: this will not work in all cases, if the last allocation had an adjusted_index | |
| 510 | /// then we won't be able to determine what the last allocation was. This is because | |
| 511 | /// the alignForward operation done in alloc is not reverisible. | |
| 513 | 512 | pub fn isLastAllocation(self: *FixedBufferAllocator, buf: []u8) bool { |
| 514 | 513 | return buf.ptr + buf.len == self.buffer.ptr + self.end_index; |
| 515 | 514 | } |
| ... | ... | @@ -525,7 +524,7 @@ pub const FixedBufferAllocator = struct { |
| 525 | 524 | const result = self.buffer[adjusted_index..new_end_index]; |
| 526 | 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 | 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 | 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 | 547 | if (add + self.end_index > self.buffer.len) { |
| 549 | //add = self.buffer.len - self.end_index; | |
| 550 | 548 | return error.OutOfMemory; |
| 551 | 549 | } |
| 552 | 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 | 554 | pub fn reset(self: *FixedBufferAllocator) void { |
| ... | ... | @@ -735,7 +733,7 @@ test "ArenaAllocator" { |
| 735 | 733 | |
| 736 | 734 | var test_fixed_buffer_allocator_memory: [800000 * @sizeOf(u64)]u8 = undefined; |
| 737 | 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 | 738 | try testAllocator(&fixed_buffer_allocator.allocator); |
| 741 | 739 | try testAllocatorAligned(&fixed_buffer_allocator.allocator, 16); |
| ... | ... | @@ -802,8 +800,8 @@ test "ThreadSafeFixedBufferAllocator" { |
| 802 | 800 | } |
| 803 | 801 | |
| 804 | 802 | fn testAllocator(base_allocator: *mem.Allocator) !void { |
| 805 | var sanityAllocator = mem.sanityWrap(base_allocator); | |
| 806 | const allocator = &sanityAllocator.allocator; | |
| 803 | var validationAllocator = mem.validationWrap(base_allocator); | |
| 804 | const allocator = &validationAllocator.allocator; | |
| 807 | 805 | |
| 808 | 806 | var slice = try allocator.alloc(*i32, 100); |
| 809 | 807 | testing.expect(slice.len == 100); |
| ... | ... | @@ -833,8 +831,8 @@ fn testAllocator(base_allocator: *mem.Allocator) !void { |
| 833 | 831 | } |
| 834 | 832 | |
| 835 | 833 | fn testAllocatorAligned(base_allocator: *mem.Allocator, comptime alignment: u29) !void { |
| 836 | var sanityAllocator = mem.sanityWrap(base_allocator); | |
| 837 | const allocator = &sanityAllocator.allocator; | |
| 834 | var validationAllocator = mem.validationWrap(base_allocator); | |
| 835 | const allocator = &validationAllocator.allocator; | |
| 838 | 836 | |
| 839 | 837 | // initial |
| 840 | 838 | var slice = try allocator.alignedAlloc(u8, alignment, 10); |
| ... | ... | @@ -860,8 +858,8 @@ fn testAllocatorAligned(base_allocator: *mem.Allocator, comptime alignment: u29) |
| 860 | 858 | } |
| 861 | 859 | |
| 862 | 860 | fn testAllocatorLargeAlignment(base_allocator: *mem.Allocator) mem.Allocator.Error!void { |
| 863 | var sanityAllocator = mem.sanityWrap(base_allocator); | |
| 864 | const allocator = &sanityAllocator.allocator; | |
| 861 | var validationAllocator = mem.validationWrap(base_allocator); | |
| 862 | const allocator = &validationAllocator.allocator; | |
| 865 | 863 | |
| 866 | 864 | //Maybe a platform's page_size is actually the same as or |
| 867 | 865 | // very near usize? |
| ... | ... | @@ -892,8 +890,8 @@ fn testAllocatorLargeAlignment(base_allocator: *mem.Allocator) mem.Allocator.Err |
| 892 | 890 | } |
| 893 | 891 | |
| 894 | 892 | fn testAllocatorAlignedShrink(base_allocator: *mem.Allocator) mem.Allocator.Error!void { |
| 895 | var sanityAllocator = mem.sanityWrap(base_allocator); | |
| 896 | const allocator = &sanityAllocator.allocator; | |
| 893 | var validationAllocator = mem.validationWrap(base_allocator); | |
| 894 | const allocator = &validationAllocator.allocator; | |
| 897 | 895 | |
| 898 | 896 | var debug_buffer: [1000]u8 = undefined; |
| 899 | 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 | 77 | } |
| 78 | 78 | const result = cur_buf[adjusted_index..new_end_index]; |
| 79 | 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 | 70 | var fbs = std.io.fixedBufferStream(&log_buf); |
| 71 | 71 | |
| 72 | 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 | 74 | const allocator = &loggingAllocator(&fixedBufferAllocator.allocator, fbs.outStream()).allocator; |
| 75 | 75 | |
| 76 | 76 | var a = try allocator.alloc(u8, 10); |
lib/std/mem.zig+28-34| ... | ... | @@ -141,6 +141,9 @@ pub const Allocator = struct { |
| 141 | 141 | const new_mem = try self.callAllocFn(new_len, new_alignment, len_align); |
| 142 | 142 | @memcpy(new_mem.ptr, old_mem.ptr, std.math.min(new_len, old_mem.len)); |
| 143 | 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 | 147 | //@memset(old_mem.ptr, undefined, old_mem.len); |
| 145 | 148 | _ = self.shrinkBytes(old_mem, 0, 0); |
| 146 | 149 | return new_mem; |
| ... | ... | @@ -214,6 +217,7 @@ pub const Allocator = struct { |
| 214 | 217 | return self.allocWithOptions(Elem, n, null, sentinel); |
| 215 | 218 | } |
| 216 | 219 | |
| 220 | /// Deprecated: use `allocAdvanced` | |
| 217 | 221 | pub fn alignedAlloc( |
| 218 | 222 | self: *Allocator, |
| 219 | 223 | comptime T: type, |
| ... | ... | @@ -221,11 +225,11 @@ pub const Allocator = struct { |
| 221 | 225 | comptime alignment: ?u29, |
| 222 | 226 | n: usize, |
| 223 | 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}; | |
| 228 | pub fn alignedAlloc2( | |
| 231 | const Exact = enum {exact,at_least}; | |
| 232 | pub fn allocAdvanced( | |
| 229 | 233 | self: *Allocator, |
| 230 | 234 | comptime T: type, |
| 231 | 235 | /// null means naturally aligned |
| ... | ... | @@ -234,7 +238,7 @@ pub const Allocator = struct { |
| 234 | 238 | exact: Exact, |
| 235 | 239 | ) Error![]align(alignment orelse @alignOf(T)) T { |
| 236 | 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 | 242 | break :blk a; |
| 239 | 243 | } else @alignOf(T); |
| 240 | 244 | |
| ... | ... | @@ -248,7 +252,10 @@ pub const Allocator = struct { |
| 248 | 252 | // functions that heap-allocate their own frame with @Frame(func). |
| 249 | 253 | const sizeOfT = if (alignment == null) @intCast(u29, @divExact(byte_count, n)) else @sizeOf(T); |
| 250 | 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 | 259 | @memset(byte_slice.ptr, undefined, byte_slice.len); |
| 253 | 260 | if (alignment == null) { |
| 254 | 261 | // This if block is a workaround (see comment above) |
| ... | ... | @@ -273,7 +280,7 @@ pub const Allocator = struct { |
| 273 | 280 | break :t Error![]align(Slice.alignment) Slice.child; |
| 274 | 281 | } { |
| 275 | 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 | 286 | pub fn reallocAtLeast(self: *Allocator, old_mem: var, new_n: usize) t: { |
| ... | ... | @@ -281,25 +288,23 @@ pub const Allocator = struct { |
| 281 | 288 | break :t Error![]align(Slice.alignment) Slice.child; |
| 282 | 289 | } { |
| 283 | 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 | |
| 288 | /// a new alignment, which can be larger, smaller, or the same as the old | |
| 289 | /// allocation. | |
| 294 | // Deprecated: use `reallocAdvanced` | |
| 290 | 295 | pub fn alignedRealloc( |
| 291 | 296 | self: *Allocator, |
| 292 | 297 | old_mem: var, |
| 293 | 298 | comptime new_alignment: u29, |
| 294 | 299 | new_n: usize, |
| 295 | 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 | 304 | /// This is the same as `realloc`, except caller may additionally request |
| 300 | 305 | /// a new alignment, which can be larger, smaller, or the same as the old |
| 301 | 306 | /// allocation. |
| 302 | pub fn alignedRealloc2( | |
| 307 | pub fn reallocAdvanced( | |
| 303 | 308 | self: *Allocator, |
| 304 | 309 | old_mem: var, |
| 305 | 310 | comptime new_alignment: u29, |
| ... | ... | @@ -309,7 +314,7 @@ pub const Allocator = struct { |
| 309 | 314 | const Slice = @typeInfo(@TypeOf(old_mem)).Pointer; |
| 310 | 315 | const T = Slice.child; |
| 311 | 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 | 319 | if (new_n == 0) { |
| 315 | 320 | self.free(old_mem); |
| ... | ... | @@ -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 | |
| 396 | /// either be a `*Allocator`, in which case it is returned as-is, otherwise, the address of | |
| 397 | /// the `allocator` field is returned. | |
| 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 { | |
| 400 | /// Detects and asserts if the std.mem.Allocator interface is violated by the caller | |
| 401 | /// or the allocator. | |
| 402 | pub fn ValidationAllocator(comptime T: type) type { return struct { | |
| 413 | 403 | const Self = @This(); |
| 414 | 404 | allocator: Allocator, |
| 415 | 405 | underlying_allocator: T, |
| ... | ... | @@ -424,7 +414,8 @@ pub fn SanityAllocator(comptime T: type) type { return struct { |
| 424 | 414 | } |
| 425 | 415 | fn getUnderlyingAllocatorPtr(self: *@This()) *Allocator { |
| 426 | 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 | 420 | pub fn alloc(allocator: *Allocator, n: usize, ptr_align: u29, len_align: u29) Allocator.Error![]u8 { |
| 430 | 421 | assert(n > 0); |
| ... | ... | @@ -436,6 +427,7 @@ pub fn SanityAllocator(comptime T: type) type { return struct { |
| 436 | 427 | |
| 437 | 428 | const self = @fieldParentPtr(@This(), "allocator", allocator); |
| 438 | 429 | const result = try self.getUnderlyingAllocatorPtr().callAllocFn(n, ptr_align, len_align); |
| 430 | assert(mem.isAligned(@ptrToInt(result.ptr), ptr_align)); | |
| 439 | 431 | if (len_align == 0) { |
| 440 | 432 | assert(result.len == n); |
| 441 | 433 | } else { |
| ... | ... | @@ -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)) { | |
| 471 | return SanityAllocator(@TypeOf(allocator)).init(allocator); | |
| 462 | pub fn validationWrap(allocator: var) ValidationAllocator(@TypeOf(allocator)) { | |
| 463 | return ValidationAllocator(@TypeOf(allocator)).init(allocator); | |
| 472 | 464 | } |
| 473 | 465 | |
| 474 | 466 | /// An allocator helper function. Adjusts an allocation length satisfy `len_align`. |
| ... | ... | @@ -2377,6 +2369,8 @@ test "alignForward" { |
| 2377 | 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 | 2374 | pub fn alignBackwardAnyAlign(i: usize, alignment: usize) usize { |
| 2381 | 2375 | if (@popCount(usize, alignment) == 1) |
| 2382 | 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 | 11 | pub const failing_allocator = &failing_allocator_instance.allocator; |
| 12 | 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 | 15 | var allocator_mem: [2 * 1024 * 1024]u8 = undefined; |
| 16 | 16 | |
| 17 | 17 | /// This function is intended to be used only in tests. It prints diagnostics to stderr |