| author | |
| committer | |
| log | 43d84420f3bca06be86397049c3b940358131f75 |
| tree | 5423fcf89e712c4ec22af18586c48bf833abd336 |
| parent | 557caecaaa78a1a434b72c38195b40a82fe42c74 |
| parent | 4848c3a1ad2bfd956419351afb60928e290f2be1 |
Reviewed-on: https://codeberg.org/ziglang/zig/pulls/31611
Reviewed-by: Andrew Kelley <andrew@ziglang.org>2 files changed, 52 insertions(+), 5 deletions(-)
lib/std/mem.zig+48| ... | ... | @@ -4709,6 +4709,54 @@ test "sliceAsBytes preserves pointer attributes" { |
| 4709 | 4709 | try testing.expectEqual(in.alignment, out.alignment); |
| 4710 | 4710 | } |
| 4711 | 4711 | |
| 4712 | fn AbsorbSentinelReturnType(comptime Slice: type) type { | |
| 4713 | const info = @typeInfo(Slice).pointer; | |
| 4714 | assert(info.size == .slice); | |
| 4715 | return @Pointer(.slice, .{ | |
| 4716 | .@"const" = info.is_const, | |
| 4717 | .@"volatile" = info.is_volatile, | |
| 4718 | .@"allowzero" = info.is_allowzero, | |
| 4719 | .@"addrspace" = info.address_space, | |
| 4720 | .@"align" = info.alignment, | |
| 4721 | }, info.child, null); | |
| 4722 | } | |
| 4723 | ||
| 4724 | /// If the provided slice is not sentinel terminated, do nothing and return that slice. | |
| 4725 | /// If it is sentinel-terminated, return a non-sentinel-terminated slice with the | |
| 4726 | /// length increased by one to include the absorbed sentinel element. | |
| 4727 | pub fn absorbSentinel(slice: anytype) AbsorbSentinelReturnType(@TypeOf(slice)) { | |
| 4728 | const info = @typeInfo(@TypeOf(slice)).pointer; | |
| 4729 | comptime assert(info.size == .slice); | |
| 4730 | if (info.sentinel_ptr == null) { | |
| 4731 | return slice; | |
| 4732 | } else { | |
| 4733 | return slice.ptr[0 .. slice.len + 1]; | |
| 4734 | } | |
| 4735 | } | |
| 4736 | ||
| 4737 | test absorbSentinel { | |
| 4738 | { | |
| 4739 | var buffer: [3:0]u8 = .{ 1, 2, 3 }; | |
| 4740 | const foo: [:0]const u8 = &buffer; | |
| 4741 | const bar: []const u8 = &buffer; | |
| 4742 | try testing.expectEqual([]const u8, @TypeOf(absorbSentinel(foo))); | |
| 4743 | try testing.expectEqual([]const u8, @TypeOf(absorbSentinel(bar))); | |
| 4744 | try testing.expectEqualSlices(u8, &.{ 1, 2, 3, 0 }, absorbSentinel(foo)); | |
| 4745 | try testing.expectEqualSlices(u8, &.{ 1, 2, 3 }, absorbSentinel(bar)); | |
| 4746 | } | |
| 4747 | { | |
| 4748 | var buffer: [3:0]u8 = .{ 1, 2, 3 }; | |
| 4749 | const foo: [:0]u8 = &buffer; | |
| 4750 | const bar: []u8 = &buffer; | |
| 4751 | try testing.expectEqual([]u8, @TypeOf(absorbSentinel(foo))); | |
| 4752 | try testing.expectEqual([]u8, @TypeOf(absorbSentinel(bar))); | |
| 4753 | var expected_foo = [_]u8{ 1, 2, 3, 0 }; | |
| 4754 | try testing.expectEqualSlices(u8, &expected_foo, absorbSentinel(foo)); | |
| 4755 | var expected_bar = [_]u8{ 1, 2, 3 }; | |
| 4756 | try testing.expectEqualSlices(u8, &expected_bar, absorbSentinel(bar)); | |
| 4757 | } | |
| 4758 | } | |
| 4759 | ||
| 4712 | 4760 | /// Round an address down to the next (or current) aligned address. |
| 4713 | 4761 | /// Unlike `alignForward`, `alignment` can be any positive number, not just a power of 2. |
| 4714 | 4762 | pub fn alignForwardAnyAlign(comptime T: type, addr: T, alignment: T) T { |
lib/std/mem/Allocator.zig+4-5| ... | ... | @@ -322,7 +322,7 @@ pub fn resize(self: Allocator, allocation: anytype, new_len: usize) bool { |
| 322 | 322 | if (allocation.len == 0) { |
| 323 | 323 | return false; |
| 324 | 324 | } |
| 325 | const old_memory = mem.sliceAsBytes(allocation); | |
| 325 | const old_memory: []u8 = @ptrCast(@constCast(mem.absorbSentinel(allocation))); | |
| 326 | 326 | // I would like to use saturating multiplication here, but LLVM cannot lower it |
| 327 | 327 | // on WebAssembly: https://github.com/ziglang/zig/issues/9660 |
| 328 | 328 | //const new_len_bytes = new_len *| @sizeOf(T); |
| ... | ... | @@ -368,7 +368,7 @@ pub fn remap(self: Allocator, allocation: anytype, new_len: usize) ?@TypeOf(allo |
| 368 | 368 | new_memory.len = new_len; |
| 369 | 369 | return new_memory; |
| 370 | 370 | } |
| 371 | const old_memory = mem.sliceAsBytes(allocation); | |
| 371 | const old_memory: []u8 = @ptrCast(@constCast(mem.absorbSentinel(allocation))); | |
| 372 | 372 | // I would like to use saturating multiplication here, but LLVM cannot lower it |
| 373 | 373 | // on WebAssembly: https://github.com/ziglang/zig/issues/9660 |
| 374 | 374 | //const new_len_bytes = new_len *| @sizeOf(T); |
| ... | ... | @@ -420,7 +420,7 @@ pub fn reallocAdvanced( |
| 420 | 420 | return ptr; |
| 421 | 421 | } |
| 422 | 422 | |
| 423 | const old_byte_slice = mem.sliceAsBytes(old_mem); | |
| 423 | const old_byte_slice: []u8 = @ptrCast(@constCast(mem.absorbSentinel(old_mem))); | |
| 424 | 424 | const byte_count = math.mul(usize, @sizeOf(T), new_n) catch return error.OutOfMemory; |
| 425 | 425 | // Note: can't set shrunk memory to undefined as memory shouldn't be modified on realloc failure |
| 426 | 426 | if (self.rawRemap(old_byte_slice, .fromByteUnits(slice_info.alignment orelse @alignOf(T)), byte_count, return_address)) |p| { |
| ... | ... | @@ -443,8 +443,7 @@ pub fn reallocAdvanced( |
| 443 | 443 | pub fn free(self: Allocator, memory: anytype) void { |
| 444 | 444 | const slice_info = @typeInfo(@TypeOf(memory)).pointer; |
| 445 | 445 | comptime assert(slice_info.size == .slice); |
| 446 | const mem_with_sent = memory[0 .. memory.len + @intFromBool(slice_info.sentinel() != null)]; | |
| 447 | const bytes: []u8 = @ptrCast(@constCast(mem_with_sent)); | |
| 446 | const bytes: []u8 = @ptrCast(@constCast(mem.absorbSentinel(memory))); | |
| 448 | 447 | if (bytes.len == 0) return; |
| 449 | 448 | @memset(bytes, undefined); |
| 450 | 449 | self.rawFree(bytes, .fromByteUnits(slice_info.alignment orelse @alignOf(slice_info.child)), @returnAddress()); |