| author | |
| committer | |
| log | 3c1432701129bacf95b944f0f86af2d96ae72c69 |
| tree | d05e7ddf19d709975f432e60f5a2321309078517 |
| parent | b99c6d56da3d2db995c268fb07f48548ea6d1148 |
| parent | ef3d761da545a3a72928ed0e0ba3b749a4cb74d8 |
| signature |
closes #397211 files changed, 171 insertions(+), 27 deletions(-)
lib/std/builtin.zig+2| ... | @@ -185,6 +185,7 @@ pub const TypeInfo = union(enum) { | ... | @@ -185,6 +185,7 @@ pub const TypeInfo = union(enum) { |
| 185 | child: type, | 185 | child: type, |
| 186 | is_allowzero: bool, | 186 | is_allowzero: bool, |
| 187 | 187 | ||
| 188 | /// This field is an optional type. | ||
| 188 | /// The type of the sentinel is the element type of the pointer, which is | 189 | /// The type of the sentinel is the element type of the pointer, which is |
| 189 | /// the value of the `child` field in this struct. However there is no way | 190 | /// the value of the `child` field in this struct. However there is no way |
| 190 | /// to refer to that type here, so we use `var`. | 191 | /// to refer to that type here, so we use `var`. |
| ... | @@ -206,6 +207,7 @@ pub const TypeInfo = union(enum) { | ... | @@ -206,6 +207,7 @@ pub const TypeInfo = union(enum) { |
| 206 | len: comptime_int, | 207 | len: comptime_int, |
| 207 | child: type, | 208 | child: type, |
| 208 | 209 | ||
| 210 | /// This field is an optional type. | ||
| 209 | /// The type of the sentinel is the element type of the array, which is | 211 | /// The type of the sentinel is the element type of the array, which is |
| 210 | /// the value of the `child` field in this struct. However there is no way | 212 | /// the value of the `child` field in this struct. However there is no way |
| 211 | /// to refer to that type here, so we use `var`. | 213 | /// to refer to that type here, so we use `var`. |
lib/std/cstr.zig+1-1| ... | @@ -28,7 +28,7 @@ test "cstr fns" { | ... | @@ -28,7 +28,7 @@ test "cstr fns" { |
| 28 | 28 | ||
| 29 | fn testCStrFnsImpl() void { | 29 | fn testCStrFnsImpl() void { |
| 30 | testing.expect(cmp("aoeu", "aoez") == -1); | 30 | testing.expect(cmp("aoeu", "aoez") == -1); |
| 31 | testing.expect(mem.len(u8, "123456789") == 9); | 31 | testing.expect(mem.len("123456789") == 9); |
| 32 | } | 32 | } |
| 33 | 33 | ||
| 34 | /// Returns a mutable, null-terminated slice with the same length as `slice`. | 34 | /// Returns a mutable, null-terminated slice with the same length as `slice`. |
lib/std/fmt.zig+4-2| ... | @@ -441,10 +441,12 @@ pub fn formatType( | ... | @@ -441,10 +441,12 @@ pub fn formatType( |
| 441 | else => return format(context, Errors, output, "{}@{x}", .{ @typeName(T.Child), @ptrToInt(value) }), | 441 | else => return format(context, Errors, output, "{}@{x}", .{ @typeName(T.Child), @ptrToInt(value) }), |
| 442 | }, | 442 | }, |
| 443 | .Many, .C => { | 443 | .Many, .C => { |
| 444 | if (ptr_info.sentinel) |sentinel| { | ||
| 445 | return formatType(mem.span(value), fmt, options, context, Errors, output, max_depth); | ||
| 446 | } | ||
| 444 | if (ptr_info.child == u8) { | 447 | if (ptr_info.child == u8) { |
| 445 | if (fmt.len > 0 and fmt[0] == 's') { | 448 | if (fmt.len > 0 and fmt[0] == 's') { |
| 446 | const len = mem.len(u8, value); | 449 | return formatText(mem.span(value), fmt, options, context, Errors, output); |
| 447 | return formatText(value[0..len], fmt, options, context, Errors, output); | ||
| 448 | } | 450 | } |
| 449 | } | 451 | } |
| 450 | return format(context, Errors, output, "{}@{x}", .{ @typeName(T.Child), @ptrToInt(value) }); | 452 | return format(context, Errors, output, "{}@{x}", .{ @typeName(T.Child), @ptrToInt(value) }); |
lib/std/mem.zig+126-12| ... | @@ -333,8 +333,20 @@ pub fn zeroes(comptime T: type) T { | ... | @@ -333,8 +333,20 @@ pub fn zeroes(comptime T: type) T { |
| 333 | } | 333 | } |
| 334 | return array; | 334 | return array; |
| 335 | }, | 335 | }, |
| 336 | .Vector, .ErrorUnion, .ErrorSet, .Union, .Fn, .BoundFn, .Type, .NoReturn, .Undefined, .Opaque, .Frame, .AnyFrame, => { | 336 | .Vector, |
| 337 | @compileError("Can't set a "++ @typeName(T) ++" to zero."); | 337 | .ErrorUnion, |
| 338 | .ErrorSet, | ||
| 339 | .Union, | ||
| 340 | .Fn, | ||
| 341 | .BoundFn, | ||
| 342 | .Type, | ||
| 343 | .NoReturn, | ||
| 344 | .Undefined, | ||
| 345 | .Opaque, | ||
| 346 | .Frame, | ||
| 347 | .AnyFrame, | ||
| 348 | => { | ||
| 349 | @compileError("Can't set a " ++ @typeName(T) ++ " to zero."); | ||
| 338 | }, | 350 | }, |
| 339 | } | 351 | } |
| 340 | } | 352 | } |
| ... | @@ -470,18 +482,115 @@ pub fn eql(comptime T: type, a: []const T, b: []const T) bool { | ... | @@ -470,18 +482,115 @@ pub fn eql(comptime T: type, a: []const T, b: []const T) bool { |
| 470 | return true; | 482 | return true; |
| 471 | } | 483 | } |
| 472 | 484 | ||
| 473 | pub fn len(comptime T: type, ptr: [*:0]const T) usize { | 485 | /// Deprecated. Use `span`. |
| 474 | var count: usize = 0; | ||
| 475 | while (ptr[count] != 0) : (count += 1) {} | ||
| 476 | return count; | ||
| 477 | } | ||
| 478 | |||
| 479 | pub fn toSliceConst(comptime T: type, ptr: [*:0]const T) [:0]const T { | 486 | pub fn toSliceConst(comptime T: type, ptr: [*:0]const T) [:0]const T { |
| 480 | return ptr[0..len(T, ptr) :0]; | 487 | return ptr[0..len(ptr) :0]; |
| 481 | } | 488 | } |
| 482 | 489 | ||
| 490 | /// Deprecated. Use `span`. | ||
| 483 | pub fn toSlice(comptime T: type, ptr: [*:0]T) [:0]T { | 491 | pub fn toSlice(comptime T: type, ptr: [*:0]T) [:0]T { |
| 484 | return ptr[0..len(T, ptr) :0]; | 492 | return ptr[0..len(ptr) :0]; |
| 493 | } | ||
| 494 | |||
| 495 | /// Takes a pointer to an array, a sentinel-terminated pointer, or a slice, and | ||
| 496 | /// returns a slice. If there is a sentinel on the input type, there will be a | ||
| 497 | /// sentinel on the output type. The constness of the output type matches | ||
| 498 | /// the constness of the input type. `[*c]` pointers are assumed to be 0-terminated, | ||
| 499 | /// and assumed to not allow null. | ||
| 500 | pub fn Span(comptime T: type) type { | ||
| 501 | var ptr_info = @typeInfo(T).Pointer; | ||
| 502 | switch (ptr_info.size) { | ||
| 503 | .One => switch (@typeInfo(ptr_info.child)) { | ||
| 504 | .Array => |info| { | ||
| 505 | ptr_info.child = info.child; | ||
| 506 | ptr_info.sentinel = info.sentinel; | ||
| 507 | }, | ||
| 508 | else => @compileError("invalid type given to std.mem.Span"), | ||
| 509 | }, | ||
| 510 | .C => { | ||
| 511 | ptr_info.sentinel = 0; | ||
| 512 | ptr_info.is_allowzero = false; | ||
| 513 | }, | ||
| 514 | .Many, .Slice => {}, | ||
| 515 | } | ||
| 516 | ptr_info.size = .Slice; | ||
| 517 | return @Type(std.builtin.TypeInfo{ .Pointer = ptr_info }); | ||
| 518 | } | ||
| 519 | |||
| 520 | test "Span" { | ||
| 521 | testing.expect(Span(*[5]u16) == []u16); | ||
| 522 | testing.expect(Span(*const [5]u16) == []const u16); | ||
| 523 | testing.expect(Span([]u16) == []u16); | ||
| 524 | testing.expect(Span([]const u8) == []const u8); | ||
| 525 | testing.expect(Span([:1]u16) == [:1]u16); | ||
| 526 | testing.expect(Span([:1]const u8) == [:1]const u8); | ||
| 527 | testing.expect(Span([*:1]u16) == [:1]u16); | ||
| 528 | testing.expect(Span([*:1]const u8) == [:1]const u8); | ||
| 529 | testing.expect(Span([*c]u16) == [:0]u16); | ||
| 530 | testing.expect(Span([*c]const u8) == [:0]const u8); | ||
| 531 | } | ||
| 532 | |||
| 533 | /// Takes a pointer to an array, a sentinel-terminated pointer, or a slice, and | ||
| 534 | /// returns a slice. If there is a sentinel on the input type, there will be a | ||
| 535 | /// sentinel on the output type. The constness of the output type matches | ||
| 536 | /// the constness of the input type. | ||
| 537 | pub fn span(ptr: var) Span(@TypeOf(ptr)) { | ||
| 538 | const Result = Span(@TypeOf(ptr)); | ||
| 539 | const l = len(ptr); | ||
| 540 | if (@typeInfo(Result).Pointer.sentinel) |s| { | ||
| 541 | return ptr[0..l :s]; | ||
| 542 | } else { | ||
| 543 | return ptr[0..l]; | ||
| 544 | } | ||
| 545 | } | ||
| 546 | |||
| 547 | test "span" { | ||
| 548 | var array: [5]u16 = [_]u16{ 1, 2, 3, 4, 5 }; | ||
| 549 | const ptr = array[0..2 :3].ptr; | ||
| 550 | testing.expect(eql(u16, span(ptr), &[_]u16{ 1, 2 })); | ||
| 551 | testing.expect(eql(u16, span(&array), &[_]u16{ 1, 2, 3, 4, 5 })); | ||
| 552 | } | ||
| 553 | |||
| 554 | /// Takes a pointer to an array, an array, a sentinel-terminated pointer, | ||
| 555 | /// or a slice, and returns the length. | ||
| 556 | pub fn len(ptr: var) usize { | ||
| 557 | return switch (@typeInfo(@TypeOf(ptr))) { | ||
| 558 | .Array => |info| info.len, | ||
| 559 | .Pointer => |info| switch (info.size) { | ||
| 560 | .One => switch (@typeInfo(info.child)) { | ||
| 561 | .Array => |x| x.len, | ||
| 562 | else => @compileError("invalid type given to std.mem.length"), | ||
| 563 | }, | ||
| 564 | .Many => if (info.sentinel) |sentinel| | ||
| 565 | indexOfSentinel(info.child, sentinel, ptr) | ||
| 566 | else | ||
| 567 | @compileError("length of pointer with no sentinel"), | ||
| 568 | .C => indexOfSentinel(info.child, 0, ptr), | ||
| 569 | .Slice => ptr.len, | ||
| 570 | }, | ||
| 571 | else => @compileError("invalid type given to std.mem.length"), | ||
| 572 | }; | ||
| 573 | } | ||
| 574 | |||
| 575 | test "len" { | ||
| 576 | testing.expect(len("aoeu") == 4); | ||
| 577 | |||
| 578 | { | ||
| 579 | var array: [5]u16 = [_]u16{ 1, 2, 3, 4, 5 }; | ||
| 580 | testing.expect(len(&array) == 5); | ||
| 581 | testing.expect(len(array[0..3]) == 3); | ||
| 582 | array[2] = 0; | ||
| 583 | const ptr = array[0..2 :0].ptr; | ||
| 584 | testing.expect(len(ptr) == 2); | ||
| 585 | } | ||
| 586 | } | ||
| 587 | |||
| 588 | pub fn indexOfSentinel(comptime Elem: type, comptime sentinel: Elem, ptr: [*:sentinel]const Elem) usize { | ||
| 589 | var i: usize = 0; | ||
| 590 | while (ptr[i] != sentinel) { | ||
| 591 | i += 1; | ||
| 592 | } | ||
| 593 | return i; | ||
| 485 | } | 594 | } |
| 486 | 595 | ||
| 487 | /// Returns true if all elements in a slice are equal to the scalar value provided | 596 | /// Returns true if all elements in a slice are equal to the scalar value provided |
| ... | @@ -1753,8 +1862,13 @@ fn SubArrayPtrReturnType(comptime T: type, comptime length: usize) type { | ... | @@ -1753,8 +1862,13 @@ fn SubArrayPtrReturnType(comptime T: type, comptime length: usize) type { |
| 1753 | return *[length]meta.Child(meta.Child(T)); | 1862 | return *[length]meta.Child(meta.Child(T)); |
| 1754 | } | 1863 | } |
| 1755 | 1864 | ||
| 1756 | ///Given a pointer to an array, returns a pointer to a portion of that array, preserving constness. | 1865 | /// Given a pointer to an array, returns a pointer to a portion of that array, preserving constness. |
| 1757 | pub fn subArrayPtr(ptr: var, comptime start: usize, comptime length: usize) SubArrayPtrReturnType(@TypeOf(ptr), length) { | 1866 | /// TODO this will be obsoleted by https://github.com/ziglang/zig/issues/863 |
| 1867 | pub fn subArrayPtr( | ||
| 1868 | ptr: var, | ||
| 1869 | comptime start: usize, | ||
| 1870 | comptime length: usize, | ||
| 1871 | ) SubArrayPtrReturnType(@TypeOf(ptr), length) { | ||
| 1758 | assert(start + length <= ptr.*.len); | 1872 | assert(start + length <= ptr.*.len); |
| 1759 | 1873 | ||
| 1760 | const ReturnType = SubArrayPtrReturnType(@TypeOf(ptr), length); | 1874 | const ReturnType = SubArrayPtrReturnType(@TypeOf(ptr), length); |
lib/std/meta.zig+26| ... | @@ -115,6 +115,32 @@ test "std.meta.Child" { | ... | @@ -115,6 +115,32 @@ test "std.meta.Child" { |
| 115 | testing.expect(Child(?u8) == u8); | 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 | ||
| 121 | 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.?; | ||
| 129 | }, | ||
| 130 | else => {}, | ||
| 131 | } | ||
| 132 | }, | ||
| 133 | else => {}, | ||
| 134 | } | ||
| 135 | @compileError("not a sentinel type, found '" ++ @typeName(T) ++ "'"); | ||
| 136 | } | ||
| 137 | |||
| 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)); | ||
| 142 | } | ||
| 143 | |||
| 118 | pub fn containerLayout(comptime T: type) TypeInfo.ContainerLayout { | 144 | pub fn containerLayout(comptime T: type) TypeInfo.ContainerLayout { |
| 119 | return switch (@typeInfo(T)) { | 145 | return switch (@typeInfo(T)) { |
| 120 | .Struct => |info| info.layout, | 146 | .Struct => |info| info.layout, |
lib/std/net.zig+1-1| ... | @@ -352,7 +352,7 @@ pub const Address = extern union { | ... | @@ -352,7 +352,7 @@ pub const Address = extern union { |
| 352 | unreachable; | 352 | unreachable; |
| 353 | } | 353 | } |
| 354 | 354 | ||
| 355 | const path_len = std.mem.len(u8, @ptrCast([*:0]const u8, &self.un.path)); | 355 | const path_len = std.mem.len(@ptrCast([*:0]const u8, &self.un.path)); |
| 356 | return @intCast(os.socklen_t, @sizeOf(os.sockaddr_un) - self.un.path.len + path_len); | 356 | return @intCast(os.socklen_t, @sizeOf(os.sockaddr_un) - self.un.path.len + path_len); |
| 357 | }, | 357 | }, |
| 358 | else => unreachable, | 358 | else => unreachable, |
lib/std/os.zig+1-1| ... | @@ -1095,7 +1095,7 @@ pub fn createNullDelimitedEnvMap(allocator: *mem.Allocator, env_map: *const std. | ... | @@ -1095,7 +1095,7 @@ pub fn createNullDelimitedEnvMap(allocator: *mem.Allocator, env_map: *const std. |
| 1095 | 1095 | ||
| 1096 | pub fn freeNullDelimitedEnvMap(allocator: *mem.Allocator, envp_buf: []?[*:0]u8) void { | 1096 | pub fn freeNullDelimitedEnvMap(allocator: *mem.Allocator, envp_buf: []?[*:0]u8) void { |
| 1097 | for (envp_buf) |env| { | 1097 | for (envp_buf) |env| { |
| 1098 | const env_buf = if (env) |ptr| ptr[0 .. mem.len(u8, ptr) + 1] else break; | 1098 | const env_buf = if (env) |ptr| ptr[0 .. mem.len(ptr) + 1] else break; |
| 1099 | allocator.free(env_buf); | 1099 | allocator.free(env_buf); |
| 1100 | } | 1100 | } |
| 1101 | allocator.free(envp_buf); | 1101 | allocator.free(envp_buf); |
lib/std/special/c.zig+1-1| ... | @@ -47,7 +47,7 @@ fn strcmp(s1: [*:0]const u8, s2: [*:0]const u8) callconv(.C) c_int { | ... | @@ -47,7 +47,7 @@ fn strcmp(s1: [*:0]const u8, s2: [*:0]const u8) callconv(.C) c_int { |
| 47 | } | 47 | } |
| 48 | 48 | ||
| 49 | fn strlen(s: [*:0]const u8) callconv(.C) usize { | 49 | fn strlen(s: [*:0]const u8) callconv(.C) usize { |
| 50 | return std.mem.len(u8, s); | 50 | return std.mem.len(s); |
| 51 | } | 51 | } |
| 52 | 52 | ||
| 53 | fn strncmp(_l: [*:0]const u8, _r: [*:0]const u8, _n: usize) callconv(.C) c_int { | 53 | fn strncmp(_l: [*:0]const u8, _r: [*:0]const u8, _n: usize) callconv(.C) c_int { |
src-self-hosted/main.zig+7-7| ... | @@ -792,7 +792,7 @@ async fn fmtPath(fmt: *Fmt, file_path_ref: []const u8, check_mode: bool) FmtErro | ... | @@ -792,7 +792,7 @@ async fn fmtPath(fmt: *Fmt, file_path_ref: []const u8, check_mode: bool) FmtErro |
| 792 | } | 792 | } |
| 793 | 793 | ||
| 794 | fn cmdVersion(allocator: *Allocator, args: []const []const u8) !void { | 794 | fn cmdVersion(allocator: *Allocator, args: []const []const u8) !void { |
| 795 | try stdout.print("{}\n", .{std.mem.toSliceConst(u8, c.ZIG_VERSION_STRING)}); | 795 | try stdout.print("{}\n", .{c.ZIG_VERSION_STRING}); |
| 796 | } | 796 | } |
| 797 | 797 | ||
| 798 | fn cmdHelp(allocator: *Allocator, args: []const []const u8) !void { | 798 | fn cmdHelp(allocator: *Allocator, args: []const []const u8) !void { |
| ... | @@ -863,12 +863,12 @@ fn cmdInternalBuildInfo(allocator: *Allocator, args: []const []const u8) !void { | ... | @@ -863,12 +863,12 @@ fn cmdInternalBuildInfo(allocator: *Allocator, args: []const []const u8) !void { |
| 863 | \\ZIG_DIA_GUIDS_LIB {} | 863 | \\ZIG_DIA_GUIDS_LIB {} |
| 864 | \\ | 864 | \\ |
| 865 | , .{ | 865 | , .{ |
| 866 | std.mem.toSliceConst(u8, c.ZIG_CMAKE_BINARY_DIR), | 866 | c.ZIG_CMAKE_BINARY_DIR, |
| 867 | std.mem.toSliceConst(u8, c.ZIG_CXX_COMPILER), | 867 | c.ZIG_CXX_COMPILER, |
| 868 | std.mem.toSliceConst(u8, c.ZIG_LLD_INCLUDE_PATH), | 868 | c.ZIG_LLD_INCLUDE_PATH, |
| 869 | std.mem.toSliceConst(u8, c.ZIG_LLD_LIBRARIES), | 869 | c.ZIG_LLD_LIBRARIES, |
| 870 | std.mem.toSliceConst(u8, c.ZIG_LLVM_CONFIG_EXE), | 870 | c.ZIG_LLVM_CONFIG_EXE, |
| 871 | std.mem.toSliceConst(u8, c.ZIG_DIA_GUIDS_LIB), | 871 | c.ZIG_DIA_GUIDS_LIB, |
| 872 | }); | 872 | }); |
| 873 | } | 873 | } |
| 874 | 874 |
src-self-hosted/translate_c.zig+1-1| ... | @@ -4849,7 +4849,7 @@ fn transPreprocessorEntities(c: *Context, unit: *ZigClangASTUnit) Error!void { | ... | @@ -4849,7 +4849,7 @@ fn transPreprocessorEntities(c: *Context, unit: *ZigClangASTUnit) Error!void { |
| 4849 | } | 4849 | } |
| 4850 | 4850 | ||
| 4851 | const begin_c = ZigClangSourceManager_getCharacterData(c.source_manager, begin_loc); | 4851 | const begin_c = ZigClangSourceManager_getCharacterData(c.source_manager, begin_loc); |
| 4852 | const slice = begin_c[0..mem.len(u8, begin_c)]; | 4852 | const slice = begin_c[0..mem.len(begin_c)]; |
| 4853 | 4853 | ||
| 4854 | tok_list.shrink(0); | 4854 | tok_list.shrink(0); |
| 4855 | var tokenizer = std.c.Tokenizer{ | 4855 | var tokenizer = std.c.Tokenizer{ |
test/stage1/behavior/misc.zig+1-1| ... | @@ -335,7 +335,7 @@ test "string concatenation" { | ... | @@ -335,7 +335,7 @@ test "string concatenation" { |
| 335 | comptime expect(@TypeOf(a) == *const [12:0]u8); | 335 | comptime expect(@TypeOf(a) == *const [12:0]u8); |
| 336 | comptime expect(@TypeOf(b) == *const [12:0]u8); | 336 | comptime expect(@TypeOf(b) == *const [12:0]u8); |
| 337 | 337 | ||
| 338 | const len = mem.len(u8, b); | 338 | const len = mem.len(b); |
| 339 | const len_with_null = len + 1; | 339 | const len_with_null = len + 1; |
| 340 | { | 340 | { |
| 341 | var i: u32 = 0; | 341 | var i: u32 = 0; |