Commit 8ea0a00f40

Andrew Kelley <andrew@ziglang.org>
2020-03-17 23:54:09
improve std lib code for the new semantics
1 parent 8d0ac6d
Changed files (3)
lib
src-self-hosted
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" {
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 {
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,
     };
 }