| ... | ... | @@ -305,6 +305,25 @@ pub fn allocBytesAligned( |
| 305 | 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 | 327 | /// Request to modify the size of an allocation. |
| 309 | 328 | /// |
| 310 | 329 | /// It is guaranteed to not move the pointer, however the allocator |
| ... | ... | @@ -316,6 +335,10 @@ pub fn allocBytesAligned( |
| 316 | 335 | /// `new_len` may be zero, in which case the allocation is freed. |
| 317 | 336 | pub fn resize(self: Allocator, allocation: anytype, new_len: usize) bool { |
| 318 | 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 | 342 | comptime assert(slice_info.size == .slice); |
| 320 | 343 | const T = slice_info.child; |
| 321 | 344 | if (new_len == 0) { |
| ... | ... | @@ -354,8 +377,12 @@ pub fn resize(self: Allocator, allocation: anytype, new_len: usize) bool { |
| 354 | 377 | /// `new_len` may be zero, in which case the allocation is freed. |
| 355 | 378 | /// |
| 356 | 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 | 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 | 386 | comptime assert(slice_info.size == .slice); |
| 360 | 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 | 426 | /// do the realloc more efficiently than the caller |
| 400 | 427 | /// * `resize` which returns `false` when the `Allocator` implementation cannot |
| 401 | 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 | 430 | return self.reallocAdvanced(old_mem, new_n, @returnAddress()); |
| 404 | 431 | } |
| 405 | 432 | |
| ... | ... | @@ -408,8 +435,12 @@ pub fn reallocAdvanced( |
| 408 | 435 | old_mem: anytype, |
| 409 | 436 | new_n: usize, |
| 410 | 437 | return_address: usize, |
| 411 | | ) Error!@TypeOf(old_mem) { |
| 438 | ) Error!SliceType(@TypeOf(old_mem)) { |
| 412 | 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 | 444 | comptime assert(slice_info.size == .slice); |
| 414 | 445 | const T = slice_info.child; |
| 415 | 446 | if (old_mem.len == 0) { |
| ... | ... | @@ -446,9 +477,10 @@ pub fn reallocAdvanced( |
| 446 | 477 | pub fn free(self: Allocator, memory: anytype) void { |
| 447 | 478 | const slice_info = @typeInfo(@TypeOf(memory)).pointer; |
| 448 | 479 | if (slice_info.size != .slice) { |
| 449 | | // slicing with comptime-known start and end results in *[len]T, which may be free'd |
| 450 | | comptime assert(slice_info.size == .one and @typeInfo(slice_info.child) == .array); |
| 480 | const slice: SliceType(@TypeOf(memory)) = memory; // coerce *[len]T to []T |
| 481 | return free(self, slice); |
| 451 | 482 | } |
| 483 | comptime assert(slice_info.size == .slice); |
| 452 | 484 | const bytes: []u8 = @ptrCast(@constCast(mem.absorbSentinel(memory))); |
| 453 | 485 | if (bytes.len == 0) return; |
| 454 | 486 | @memset(bytes, undefined); |
| ... | ... | @@ -591,3 +623,9 @@ test failing { |
| 591 | 623 | try std.testing.expectError(error.OutOfMemory, f.alloc(u8, std.math.maxInt(usize))); |
| 592 | 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 | } |