improve std lib code for the new semantics

This commit is contained in:
Andrew Kelley 2020-03-17 18:54:09 -04:00
parent 8d0ac6dc4d
commit 8ea0a00f40
No known key found for this signature in database
GPG Key ID: 7C5F548F728501A9
3 changed files with 39 additions and 36 deletions

View File

@ -1829,21 +1829,19 @@ fn SliceAsBytesReturnType(comptime sliceType: type) type {
}
pub fn sliceAsBytes(slice: var) SliceAsBytesReturnType(@TypeOf(slice)) {
const actualSlice = if (comptime trait.isPtrTo(.Array)(@TypeOf(slice))) slice[0..] else slice;
const actualSliceTypeInfo = @typeInfo(@TypeOf(actualSlice)).Pointer;
const Slice = @TypeOf(slice);
// let's not give an undefined pointer to @ptrCast
// it may be equal to zero and fail a null check
if (actualSlice.len == 0 and actualSliceTypeInfo.sentinel == null) {
if (slice.len == 0 and comptime meta.sentinel(Slice) == null) {
return &[0]u8{};
}
const sliceType = @TypeOf(actualSlice);
const alignment = comptime meta.alignment(sliceType);
const alignment = comptime meta.alignment(Slice);
const castTarget = if (comptime trait.isConstPtr(sliceType)) [*]align(alignment) const u8 else [*]align(alignment) u8;
const cast_target = if (comptime trait.isConstPtr(Slice)) [*]align(alignment) const u8 else [*]align(alignment) u8;
return @ptrCast(castTarget, actualSlice.ptr)[0 .. actualSlice.len * @sizeOf(comptime meta.Child(sliceType))];
return @ptrCast(cast_target, slice)[0 .. slice.len * @sizeOf(meta.Child(Slice))];
}
test "sliceAsBytes" {

View File

@ -115,30 +115,37 @@ test "std.meta.Child" {
testing.expect(Child(?u8) == u8);
}
/// Given a type with a sentinel e.g. `[:0]u8`, returns the sentinel
pub fn Sentinel(comptime T: type) Child(T) {
// comptime asserts that ptr has a sentinel
/// Given a type which can have a sentinel e.g. `[:0]u8`, returns the sentinel value,
/// or `null` if there is not one.
/// Types which cannot possibly have a sentinel will be a compile error.
pub fn sentinel(comptime T: type) ?Child(T) {
switch (@typeInfo(T)) {
.Array => |arrayInfo| {
return comptime arrayInfo.sentinel.?;
},
.Pointer => |ptrInfo| {
switch (ptrInfo.size) {
.Many, .Slice => {
return comptime ptrInfo.sentinel.?;
.Array => |info| return info.sentinel,
.Pointer => |info| {
switch (info.size) {
.Many, .Slice => return info.sentinel,
.One => switch (info.child) {
.Array => |array_info| return array_info.sentinel,
else => {},
},
else => {},
}
},
else => {},
}
@compileError("not a sentinel type, found '" ++ @typeName(T) ++ "'");
@compileError("type '" ++ @typeName(T) ++ "' cannot possibly have a sentinel");
}
test "std.meta.Sentinel" {
testing.expectEqual(@as(u8, 0), Sentinel([:0]u8));
testing.expectEqual(@as(u8, 0), Sentinel([*:0]u8));
testing.expectEqual(@as(u8, 0), Sentinel([5:0]u8));
test "std.meta.sentinel" {
testing.expectEqual(@as(u8, 0), sentinel([:0]u8).?);
testing.expectEqual(@as(u8, 0), sentinel([*:0]u8).?);
testing.expectEqual(@as(u8, 0), sentinel([5:0]u8).?);
testing.expectEqual(@as(u8, 0), sentinel(*const [5:0]u8).?);
testing.expect(sentinel([]u8) == null);
testing.expect(sentinel([*]u8) == null);
testing.expect(sentinel([5]u8) == null);
testing.expect(sentinel(*const [5]u8) == null);
}
pub fn containerLayout(comptime T: type) TypeInfo.ContainerLayout {

View File

@ -1744,20 +1744,18 @@ fn writeEscapedString(buf: []u8, s: []const u8) void {
// Returns either a string literal or a slice of `buf`.
fn escapeChar(c: u8, char_buf: *[4]u8) []const u8 {
return switch (c) {
'\"' => "\\\""[0..],
'\'' => "\\'"[0..],
'\\' => "\\\\"[0..],
'\n' => "\\n"[0..],
'\r' => "\\r"[0..],
'\t' => "\\t"[0..],
else => {
// Handle the remaining escapes Zig doesn't support by turning them
// into their respective hex representation
if (std.ascii.isCntrl(c))
return std.fmt.bufPrint(char_buf[0..], "\\x{x:0<2}", .{c}) catch unreachable
else
return std.fmt.bufPrint(char_buf[0..], "{c}", .{c}) catch unreachable;
},
'\"' => "\\\"",
'\'' => "\\'",
'\\' => "\\\\",
'\n' => "\\n",
'\r' => "\\r",
'\t' => "\\t",
// Handle the remaining escapes Zig doesn't support by turning them
// into their respective hex representation
else => if (std.ascii.isCntrl(c))
std.fmt.bufPrint(char_buf, "\\x{x:0<2}", .{c}) catch unreachable
else
std.fmt.bufPrint(char_buf, "{c}", .{c}) catch unreachable,
};
}