| author | |
| committer | |
| log | 8ea0a00f406bb04c08a8fa4471c3a3895f82b24a |
| tree | db67660d2496e6b501ebb67bec9c2d4907e3fa51 |
| parent | 8d0ac6dc4d32daea3561e7de8eeee9ce34d2c5cb |
| signature |
3 files changed, 39 insertions(+), 36 deletions(-)
lib/std/mem.zig+5-7| ... | ... | @@ -1829,21 +1829,19 @@ fn SliceAsBytesReturnType(comptime sliceType: type) type { |
| 1829 | 1829 | } |
| 1830 | 1830 | |
| 1831 | 1831 | pub fn sliceAsBytes(slice: var) SliceAsBytesReturnType(@TypeOf(slice)) { |
| 1832 | const actualSlice = if (comptime trait.isPtrTo(.Array)(@TypeOf(slice))) slice[0..] else slice; | |
| 1833 | const actualSliceTypeInfo = @typeInfo(@TypeOf(actualSlice)).Pointer; | |
| 1832 | const Slice = @TypeOf(slice); | |
| 1834 | 1833 | |
| 1835 | 1834 | // let's not give an undefined pointer to @ptrCast |
| 1836 | 1835 | // it may be equal to zero and fail a null check |
| 1837 | if (actualSlice.len == 0 and actualSliceTypeInfo.sentinel == null) { | |
| 1836 | if (slice.len == 0 and comptime meta.sentinel(Slice) == null) { | |
| 1838 | 1837 | return &[0]u8{}; |
| 1839 | 1838 | } |
| 1840 | 1839 | |
| 1841 | const sliceType = @TypeOf(actualSlice); | |
| 1842 | const alignment = comptime meta.alignment(sliceType); | |
| 1840 | const alignment = comptime meta.alignment(Slice); | |
| 1843 | 1841 | |
| 1844 | const castTarget = if (comptime trait.isConstPtr(sliceType)) [*]align(alignment) const u8 else [*]align(alignment) u8; | |
| 1842 | const cast_target = if (comptime trait.isConstPtr(Slice)) [*]align(alignment) const u8 else [*]align(alignment) u8; | |
| 1845 | 1843 | |
| 1846 | return @ptrCast(castTarget, actualSlice.ptr)[0 .. actualSlice.len * @sizeOf(comptime meta.Child(sliceType))]; | |
| 1844 | return @ptrCast(cast_target, slice)[0 .. slice.len * @sizeOf(meta.Child(Slice))]; | |
| 1847 | 1845 | } |
| 1848 | 1846 | |
| 1849 | 1847 | test "sliceAsBytes" { |
lib/std/meta.zig+22-15| ... | ... | @@ -115,30 +115,37 @@ test "std.meta.Child" { |
| 115 | 115 | testing.expect(Child(?u8) == u8); |
| 116 | 116 | } |
| 117 | 117 | |
| 118 | /// Given a type with a sentinel e.g. `[:0]u8`, returns the sentinel | |
| 119 | pub fn Sentinel(comptime T: type) Child(T) { | |
| 120 | // comptime asserts that ptr has a sentinel | |
| 118 | /// Given a type which can have a sentinel e.g. `[:0]u8`, returns the sentinel value, | |
| 119 | /// or `null` if there is not one. | |
| 120 | /// Types which cannot possibly have a sentinel will be a compile error. | |
| 121 | pub fn sentinel(comptime T: type) ?Child(T) { | |
| 121 | 122 | switch (@typeInfo(T)) { |
| 122 | .Array => |arrayInfo| { | |
| 123 | return comptime arrayInfo.sentinel.?; | |
| 124 | }, | |
| 125 | .Pointer => |ptrInfo| { | |
| 126 | switch (ptrInfo.size) { | |
| 127 | .Many, .Slice => { | |
| 128 | return comptime ptrInfo.sentinel.?; | |
| 123 | .Array => |info| return info.sentinel, | |
| 124 | .Pointer => |info| { | |
| 125 | switch (info.size) { | |
| 126 | .Many, .Slice => return info.sentinel, | |
| 127 | .One => switch (info.child) { | |
| 128 | .Array => |array_info| return array_info.sentinel, | |
| 129 | else => {}, | |
| 129 | 130 | }, |
| 130 | 131 | else => {}, |
| 131 | 132 | } |
| 132 | 133 | }, |
| 133 | 134 | else => {}, |
| 134 | 135 | } |
| 135 | @compileError("not a sentinel type, found '" ++ @typeName(T) ++ "'"); | |
| 136 | @compileError("type '" ++ @typeName(T) ++ "' cannot possibly have a sentinel"); | |
| 136 | 137 | } |
| 137 | 138 | |
| 138 | test "std.meta.Sentinel" { | |
| 139 | testing.expectEqual(@as(u8, 0), Sentinel([:0]u8)); | |
| 140 | testing.expectEqual(@as(u8, 0), Sentinel([*:0]u8)); | |
| 141 | testing.expectEqual(@as(u8, 0), Sentinel([5:0]u8)); | |
| 139 | test "std.meta.sentinel" { | |
| 140 | testing.expectEqual(@as(u8, 0), sentinel([:0]u8).?); | |
| 141 | testing.expectEqual(@as(u8, 0), sentinel([*:0]u8).?); | |
| 142 | testing.expectEqual(@as(u8, 0), sentinel([5:0]u8).?); | |
| 143 | testing.expectEqual(@as(u8, 0), sentinel(*const [5:0]u8).?); | |
| 144 | ||
| 145 | testing.expect(sentinel([]u8) == null); | |
| 146 | testing.expect(sentinel([*]u8) == null); | |
| 147 | testing.expect(sentinel([5]u8) == null); | |
| 148 | testing.expect(sentinel(*const [5]u8) == null); | |
| 142 | 149 | } |
| 143 | 150 | |
| 144 | 151 | pub fn containerLayout(comptime T: type) TypeInfo.ContainerLayout { |
src-self-hosted/translate_c.zig+12-14| ... | ... | @@ -1744,20 +1744,18 @@ fn writeEscapedString(buf: []u8, s: []const u8) void { |
| 1744 | 1744 | // Returns either a string literal or a slice of `buf`. |
| 1745 | 1745 | fn escapeChar(c: u8, char_buf: *[4]u8) []const u8 { |
| 1746 | 1746 | return switch (c) { |
| 1747 | '\"' => "\\\""[0..], | |
| 1748 | '\'' => "\\'"[0..], | |
| 1749 | '\\' => "\\\\"[0..], | |
| 1750 | '\n' => "\\n"[0..], | |
| 1751 | '\r' => "\\r"[0..], | |
| 1752 | '\t' => "\\t"[0..], | |
| 1753 | else => { | |
| 1754 | // Handle the remaining escapes Zig doesn't support by turning them | |
| 1755 | // into their respective hex representation | |
| 1756 | if (std.ascii.isCntrl(c)) | |
| 1757 | return std.fmt.bufPrint(char_buf[0..], "\\x{x:0<2}", .{c}) catch unreachable | |
| 1758 | else | |
| 1759 | return std.fmt.bufPrint(char_buf[0..], "{c}", .{c}) catch unreachable; | |
| 1760 | }, | |
| 1747 | '\"' => "\\\"", | |
| 1748 | '\'' => "\\'", | |
| 1749 | '\\' => "\\\\", | |
| 1750 | '\n' => "\\n", | |
| 1751 | '\r' => "\\r", | |
| 1752 | '\t' => "\\t", | |
| 1753 | // Handle the remaining escapes Zig doesn't support by turning them | |
| 1754 | // into their respective hex representation | |
| 1755 | else => if (std.ascii.isCntrl(c)) | |
| 1756 | std.fmt.bufPrint(char_buf, "\\x{x:0<2}", .{c}) catch unreachable | |
| 1757 | else | |
| 1758 | std.fmt.bufPrint(char_buf, "{c}", .{c}) catch unreachable, | |
| 1761 | 1759 | }; |
| 1762 | 1760 | } |
| 1763 | 1761 |