| ... | @@ -305,6 +305,25 @@ pub fn allocBytesAligned( | ... | @@ -305,6 +305,25 @@ pub fn allocBytesAligned( |
| 305 | return @alignCast(byte_ptr); | 305 | return @alignCast(byte_ptr); |
| 306 | } | 306 | } |
| 307 | | 307 | |
| | 308 | fn SliceType(comptime Pointer: type) type { |
| | 309 | const info = @typeInfo(Pointer).pointer; |
| | 310 | switch (info.size) { |
| | 311 | .slice => return Pointer, |
| | 312 | .one => { |
| | 313 | const child_info = @typeInfo(info.child); |
| | 314 | comptime assert(child_info == .array); |
| | 315 | const sentinel_ptr: ?*const child_info.array.child = @ptrCast(@alignCast(child_info.array.sentinel_ptr)); |
| | 316 | return @Pointer( |
| | 317 | .slice, |
| | 318 | info.attrs, |
| | 319 | child_info.array.child, |
| | 320 | if (sentinel_ptr) |ptr| ptr.* else null, |
| | 321 | ); |
| | 322 | }, |
| | 323 | else => unreachable, |
| | 324 | } |
| | 325 | } |
| | 326 | |
| 308 | /// Request to modify the size of an allocation. | 327 | /// Request to modify the size of an allocation. |
| 309 | /// | 328 | /// |
| 310 | /// It is guaranteed to not move the pointer, however the allocator | 329 | /// It is guaranteed to not move the pointer, however the allocator |
| ... | @@ -316,6 +335,10 @@ pub fn allocBytesAligned( | ... | @@ -316,6 +335,10 @@ pub fn allocBytesAligned( |
| 316 | /// `new_len` may be zero, in which case the allocation is freed. | 335 | /// `new_len` may be zero, in which case the allocation is freed. |
| 317 | pub fn resize(self: Allocator, allocation: anytype, new_len: usize) bool { | 336 | pub fn resize(self: Allocator, allocation: anytype, new_len: usize) bool { |
| 318 | const slice_info = @typeInfo(@TypeOf(allocation)).pointer; | 337 | const slice_info = @typeInfo(@TypeOf(allocation)).pointer; |
| | 338 | if (slice_info.size != .slice) { |
| | 339 | const slice: SliceType(@TypeOf(allocation)) = allocation; // coerce *[len]T to []T |
| | 340 | return resize(self, slice, new_len); |
| | 341 | } |
| 319 | comptime assert(slice_info.size == .slice); | 342 | comptime assert(slice_info.size == .slice); |
| 320 | const T = slice_info.child; | 343 | const T = slice_info.child; |
| 321 | if (new_len == 0) { | 344 | if (new_len == 0) { |
| ... | @@ -354,8 +377,12 @@ pub fn resize(self: Allocator, allocation: anytype, new_len: usize) bool { | ... | @@ -354,8 +377,12 @@ pub fn resize(self: Allocator, allocation: anytype, new_len: usize) bool { |
| 354 | /// `new_len` may be zero, in which case the allocation is freed. | 377 | /// `new_len` may be zero, in which case the allocation is freed. |
| 355 | /// | 378 | /// |
| 356 | /// If the allocation's elements' type is zero bytes sized, `allocation.len` is set to `new_len`. | 379 | /// If the allocation's elements' type is zero bytes sized, `allocation.len` is set to `new_len`. |
| 357 | pub fn remap(self: Allocator, allocation: anytype, new_len: usize) ?@TypeOf(allocation) { | 380 | pub fn remap(self: Allocator, allocation: anytype, new_len: usize) ?SliceType(@TypeOf(allocation)) { |
| 358 | const slice_info = @typeInfo(@TypeOf(allocation)).pointer; | 381 | const slice_info = @typeInfo(@TypeOf(allocation)).pointer; |
| | 382 | if (slice_info.size != .slice) { |
| | 383 | const slice: SliceType(@TypeOf(allocation)) = allocation; // coerce *[len]T to []T |
| | 384 | return remap(self, slice, new_len); |
| | 385 | } |
| 359 | comptime assert(slice_info.size == .slice); | 386 | comptime assert(slice_info.size == .slice); |
| 360 | const T = slice_info.child; | 387 | const T = slice_info.child; |
| 361 | | 388 | |
| ... | @@ -399,7 +426,7 @@ pub fn remap(self: Allocator, allocation: anytype, new_len: usize) ?@TypeOf(allo | ... | @@ -399,7 +426,7 @@ pub fn remap(self: Allocator, allocation: anytype, new_len: usize) ?@TypeOf(allo |
| 399 | /// do the realloc more efficiently than the caller | 426 | /// do the realloc more efficiently than the caller |
| 400 | /// * `resize` which returns `false` when the `Allocator` implementation cannot | 427 | /// * `resize` which returns `false` when the `Allocator` implementation cannot |
| 401 | /// change the size without relocating the allocation. | 428 | /// change the size without relocating the allocation. |
| 402 | pub fn realloc(self: Allocator, old_mem: anytype, new_n: usize) Error!@TypeOf(old_mem) { | 429 | pub fn realloc(self: Allocator, old_mem: anytype, new_n: usize) Error!SliceType(@TypeOf(old_mem)) { |
| 403 | return self.reallocAdvanced(old_mem, new_n, @returnAddress()); | 430 | return self.reallocAdvanced(old_mem, new_n, @returnAddress()); |
| 404 | } | 431 | } |
| 405 | | 432 | |
| ... | @@ -408,8 +435,12 @@ pub fn reallocAdvanced( | ... | @@ -408,8 +435,12 @@ pub fn reallocAdvanced( |
| 408 | old_mem: anytype, | 435 | old_mem: anytype, |
| 409 | new_n: usize, | 436 | new_n: usize, |
| 410 | return_address: usize, | 437 | return_address: usize, |
| 411 | ) Error!@TypeOf(old_mem) { | 438 | ) Error!SliceType(@TypeOf(old_mem)) { |
| 412 | const slice_info = @typeInfo(@TypeOf(old_mem)).pointer; | 439 | const slice_info = @typeInfo(@TypeOf(old_mem)).pointer; |
| | 440 | if (slice_info.size != .slice) { |
| | 441 | const slice: SliceType(@TypeOf(old_mem)) = old_mem; // coerce *[len]T to []T |
| | 442 | return reallocAdvanced(self, slice, new_n, return_address); |
| | 443 | } |
| 413 | comptime assert(slice_info.size == .slice); | 444 | comptime assert(slice_info.size == .slice); |
| 414 | const T = slice_info.child; | 445 | const T = slice_info.child; |
| 415 | if (old_mem.len == 0) { | 446 | if (old_mem.len == 0) { |
| ... | @@ -446,9 +477,10 @@ pub fn reallocAdvanced( | ... | @@ -446,9 +477,10 @@ pub fn reallocAdvanced( |
| 446 | pub fn free(self: Allocator, memory: anytype) void { | 477 | pub fn free(self: Allocator, memory: anytype) void { |
| 447 | const slice_info = @typeInfo(@TypeOf(memory)).pointer; | 478 | const slice_info = @typeInfo(@TypeOf(memory)).pointer; |
| 448 | if (slice_info.size != .slice) { | 479 | if (slice_info.size != .slice) { |
| 449 | // slicing with comptime-known start and end results in *[len]T, which may be free'd | 480 | const slice: SliceType(@TypeOf(memory)) = memory; // coerce *[len]T to []T |
| 450 | comptime assert(slice_info.size == .one and @typeInfo(slice_info.child) == .array); | 481 | return free(self, slice); |
| 451 | } | 482 | } |
| | 483 | comptime assert(slice_info.size == .slice); |
| 452 | const bytes: []u8 = @ptrCast(@constCast(mem.absorbSentinel(memory))); | 484 | const bytes: []u8 = @ptrCast(@constCast(mem.absorbSentinel(memory))); |
| 453 | if (bytes.len == 0) return; | 485 | if (bytes.len == 0) return; |
| 454 | @memset(bytes, undefined); | 486 | @memset(bytes, undefined); |
| ... | @@ -591,3 +623,9 @@ test failing { | ... | @@ -591,3 +623,9 @@ test failing { |
| 591 | try std.testing.expectError(error.OutOfMemory, f.alloc(u8, std.math.maxInt(usize))); | 623 | try std.testing.expectError(error.OutOfMemory, f.alloc(u8, std.math.maxInt(usize))); |
| 592 | try std.testing.expectError(error.OutOfMemory, f.allocSentinel(u8, std.math.maxInt(usize) - 1, 0)); | 624 | try std.testing.expectError(error.OutOfMemory, f.allocSentinel(u8, std.math.maxInt(usize) - 1, 0)); |
| 593 | } | 625 | } |
| | 626 | |
| | 627 | test "free single-pointer to array" { |
| | 628 | const allocator = std.testing.allocator; |
| | 629 | const bytes = allocator.alloc(u32, 128) catch return error.SkipZigTest; |
| | 630 | allocator.free(bytes.ptr[0..128]); |
| | 631 | } |