Skip to content

Commit 0f587db

Browse files
committed
std: add mem.absorbSentinel()
This will allow replacing (currently buggy) mem.sliceAsBytes() usage in the mem.Allocator implementation with, for example: const bytes: []u8 = @constcast(@ptrCast(mem.absorbSentinel(allocation))); References: ziglang#22706
1 parent 6e8493d commit 0f587db

File tree

1 file changed

+53
-0
lines changed

1 file changed

+53
-0
lines changed

lib/std/mem.zig

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4413,6 +4413,59 @@ test "sliceAsBytes preserves pointer attributes" {
44134413
try testing.expectEqual(in.alignment, out.alignment);
44144414
}
44154415

4416+
fn AbsorbSentinelReturnType(comptime Slice: type) type {
4417+
const info = @typeInfo(Slice).pointer;
4418+
assert(info.size == .slice);
4419+
return @Type(.{
4420+
.pointer = .{
4421+
.size = info.size,
4422+
.is_const = info.is_const,
4423+
.is_volatile = info.is_volatile,
4424+
.is_allowzero = info.is_allowzero,
4425+
.alignment = info.alignment,
4426+
.address_space = info.address_space,
4427+
.child = info.child,
4428+
.sentinel_ptr = null,
4429+
},
4430+
});
4431+
}
4432+
4433+
/// If the provided slice is not sentinel terminated, do nothing and return that slice.
4434+
/// If it is sentinel-terminated, return a non-sentinel-terminated slice with the
4435+
/// length increased by one to include the absorbed sentinel element.
4436+
pub fn absorbSentinel(slice: anytype) AbsorbSentinelReturnType(@TypeOf(slice)) {
4437+
const info = @typeInfo(@TypeOf(slice)).pointer;
4438+
assert(info.size == .slice);
4439+
if (info.sentinel_ptr == null) {
4440+
return slice;
4441+
} else {
4442+
return slice.ptr[0 .. slice.len + 1];
4443+
}
4444+
}
4445+
4446+
test absorbSentinel {
4447+
{
4448+
var buffer: [3:0]u8 = .{ 1, 2, 3 };
4449+
const foo: [:0]const u8 = &buffer;
4450+
const bar: []const u8 = &buffer;
4451+
try testing.expectEqual([]const u8, @TypeOf(absorbSentinel(foo)));
4452+
try testing.expectEqual([]const u8, @TypeOf(absorbSentinel(bar)));
4453+
try testing.expectEqualSlices(u8, &.{ 1, 2, 3, 0 }, absorbSentinel(foo));
4454+
try testing.expectEqualSlices(u8, &.{ 1, 2, 3 }, absorbSentinel(bar));
4455+
}
4456+
{
4457+
var buffer: [3:0]u8 = .{ 1, 2, 3 };
4458+
const foo: [:0]u8 = &buffer;
4459+
const bar: []u8 = &buffer;
4460+
try testing.expectEqual([]u8, @TypeOf(absorbSentinel(foo)));
4461+
try testing.expectEqual([]u8, @TypeOf(absorbSentinel(bar)));
4462+
var expected_foo = [_]u8{ 1, 2, 3, 0 };
4463+
try testing.expectEqualSlices(u8, &expected_foo, absorbSentinel(foo));
4464+
var expected_bar = [_]u8{ 1, 2, 3 };
4465+
try testing.expectEqualSlices(u8, &expected_bar, absorbSentinel(bar));
4466+
}
4467+
}
4468+
44164469
/// Round an address down to the next (or current) aligned address.
44174470
/// Unlike `alignForward`, `alignment` can be any positive number, not just a power of 2.
44184471
pub fn alignForwardAnyAlign(comptime T: type, addr: T, alignment: T) T {

0 commit comments

Comments
 (0)