From 8ea0a00f406bb04c08a8fa4471c3a3895f82b24a Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Tue, 17 Mar 2020 18:54:09 -0400 Subject: [PATCH] improve std lib code for the new semantics --- lib/std/mem.zig | 12 +++++------ lib/std/meta.zig | 37 ++++++++++++++++++++------------- src-self-hosted/translate_c.zig | 26 +++++++++++------------ 3 files changed, 39 insertions(+), 36 deletions(-) diff --git a/lib/std/mem.zig b/lib/std/mem.zig index eb2539720..dcdf76e19 100644 --- a/lib/std/mem.zig +++ b/lib/std/mem.zig @@ -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" { diff --git a/lib/std/meta.zig b/lib/std/meta.zig index 65809abb5..e8b9f1689 100644 --- a/lib/std/meta.zig +++ b/lib/std/meta.zig @@ -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 { diff --git a/src-self-hosted/translate_c.zig b/src-self-hosted/translate_c.zig index 84416ac98..e6cf8fb14 100644 --- a/src-self-hosted/translate_c.zig +++ b/src-self-hosted/translate_c.zig @@ -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, }; }