authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-03-19 19:30:09-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-03-19 19:30:09-04:00
log28a6c136e9dc9bcf3e04ab0aa38edc21918c78b9
tree8bf6e99d93360d0b9ed41bd6e134fb906d0564bb
parentdc04e97098010f590d109e6e70d4afe79cd8f01b
signaturelock-open Commit is signed but in an unrecognized format.

revert std.mem.span to prefer len over sentinel; add spanZ


1 files changed, 84 insertions(+), 15 deletions(-)

lib/std/mem.zig+84-15
...@@ -496,14 +496,14 @@ pub fn eql(comptime T: type, a: []const T, b: []const T) bool {...@@ -496,14 +496,14 @@ pub fn eql(comptime T: type, a: []const T, b: []const T) bool {
496 return true;496 return true;
497}497}
498498
499/// Deprecated. Use `span`.499/// Deprecated. Use `spanZ`.
500pub fn toSliceConst(comptime T: type, ptr: [*:0]const T) [:0]const T {500pub fn toSliceConst(comptime T: type, ptr: [*:0]const T) [:0]const T {
501 return ptr[0..len(ptr) :0];501 return ptr[0..lenZ(ptr) :0];
502}502}
503503
504/// Deprecated. Use `span`.504/// Deprecated. Use `spanZ`.
505pub fn toSlice(comptime T: type, ptr: [*:0]T) [:0]T {505pub fn toSlice(comptime T: type, ptr: [*:0]T) [:0]T {
506 return ptr[0..len(ptr) :0];506 return ptr[0..lenZ(ptr) :0];
507}507}
508508
509/// Takes a pointer to an array, a sentinel-terminated pointer, or a slice, and509/// Takes a pointer to an array, a sentinel-terminated pointer, or a slice, and
...@@ -548,6 +548,9 @@ test "Span" {...@@ -548,6 +548,9 @@ test "Span" {
548/// returns a slice. If there is a sentinel on the input type, there will be a548/// returns a slice. If there is a sentinel on the input type, there will be a
549/// sentinel on the output type. The constness of the output type matches549/// sentinel on the output type. The constness of the output type matches
550/// the constness of the input type.550/// the constness of the input type.
551///
552/// When there is both a sentinel and an array length or slice length, the
553/// length value is used instead of the sentinel.
551pub fn span(ptr: var) Span(@TypeOf(ptr)) {554pub fn span(ptr: var) Span(@TypeOf(ptr)) {
552 const Result = Span(@TypeOf(ptr));555 const Result = Span(@TypeOf(ptr));
553 const l = len(ptr);556 const l = len(ptr);
...@@ -565,11 +568,74 @@ test "span" {...@@ -565,11 +568,74 @@ test "span" {
565 testing.expect(eql(u16, span(&array), &[_]u16{ 1, 2, 3, 4, 5 }));568 testing.expect(eql(u16, span(&array), &[_]u16{ 1, 2, 3, 4, 5 }));
566}569}
567570
571/// Same as `span`, except when there is both a sentinel and an array
572/// length or slice length, scans the memory for the sentinel value
573/// rather than using the length.
574pub fn spanZ(ptr: var) Span(@TypeOf(ptr)) {
575 const Result = Span(@TypeOf(ptr));
576 const l = lenZ(ptr);
577 if (@typeInfo(Result).Pointer.sentinel) |s| {
578 return ptr[0..l :s];
579 } else {
580 return ptr[0..l];
581 }
582}
583
584test "spanZ" {
585 var array: [5]u16 = [_]u16{ 1, 2, 3, 4, 5 };
586 const ptr = @as([*:3]u16, array[0..2 :3]);
587 testing.expect(eql(u16, spanZ(ptr), &[_]u16{ 1, 2 }));
588 testing.expect(eql(u16, spanZ(&array), &[_]u16{ 1, 2, 3, 4, 5 }));
589}
590
591/// Takes a pointer to an array, an array, a sentinel-terminated pointer,
592/// or a slice, and returns the length.
593/// In the case of a sentinel-terminated array, it uses the array length.
594/// For C pointers it assumes it is a pointer-to-many with a 0 sentinel.
595pub fn len(ptr: var) usize {
596 return switch (@typeInfo(@TypeOf(ptr))) {
597 .Array => |info| info.len,
598 .Pointer => |info| switch (info.size) {
599 .One => switch (@typeInfo(info.child)) {
600 .Array => ptr.len,
601 else => @compileError("invalid type given to std.mem.len"),
602 },
603 .Many => if (info.sentinel) |sentinel|
604 indexOfSentinel(info.child, sentinel, ptr)
605 else
606 @compileError("length of pointer with no sentinel"),
607 .C => indexOfSentinel(info.child, 0, ptr),
608 .Slice => ptr.len,
609 },
610 else => @compileError("invalid type given to std.mem.len"),
611 };
612}
613
614test "len" {
615 testing.expect(len("aoeu") == 4);
616
617 {
618 var array: [5]u16 = [_]u16{ 1, 2, 3, 4, 5 };
619 testing.expect(len(&array) == 5);
620 testing.expect(len(array[0..3]) == 3);
621 array[2] = 0;
622 const ptr = @as([*:0]u16, array[0..2 :0]);
623 testing.expect(len(ptr) == 2);
624 }
625 {
626 var array: [5:0]u16 = [_:0]u16{ 1, 2, 3, 4, 5 };
627 testing.expect(len(&array) == 5);
628 array[2] = 0;
629 testing.expect(len(&array) == 5);
630 }
631}
632
568/// Takes a pointer to an array, an array, a sentinel-terminated pointer,633/// Takes a pointer to an array, an array, a sentinel-terminated pointer,
569/// or a slice, and returns the length.634/// or a slice, and returns the length.
570/// In the case of a sentinel-terminated array, it scans the array635/// In the case of a sentinel-terminated array, it scans the array
571/// for a sentinel and uses that for the length, rather than using the array length.636/// for a sentinel and uses that for the length, rather than using the array length.
572pub fn len(ptr: var) usize {637/// For C pointers it assumes it is a pointer-to-many with a 0 sentinel.
638pub fn lenZ(ptr: var) usize {
573 return switch (@typeInfo(@TypeOf(ptr))) {639 return switch (@typeInfo(@TypeOf(ptr))) {
574 .Array => |info| if (info.sentinel) |sentinel|640 .Array => |info| if (info.sentinel) |sentinel|
575 indexOfSentinel(info.child, sentinel, &ptr)641 indexOfSentinel(info.child, sentinel, &ptr)
...@@ -581,35 +647,38 @@ pub fn len(ptr: var) usize {...@@ -581,35 +647,38 @@ pub fn len(ptr: var) usize {
581 indexOfSentinel(x.child, sentinel, ptr)647 indexOfSentinel(x.child, sentinel, ptr)
582 else648 else
583 ptr.len,649 ptr.len,
584 else => @compileError("invalid type given to std.mem.length"),650 else => @compileError("invalid type given to std.mem.lenZ"),
585 },651 },
586 .Many => if (info.sentinel) |sentinel|652 .Many => if (info.sentinel) |sentinel|
587 indexOfSentinel(info.child, sentinel, ptr)653 indexOfSentinel(info.child, sentinel, ptr)
588 else654 else
589 @compileError("length of pointer with no sentinel"),655 @compileError("length of pointer with no sentinel"),
590 .C => indexOfSentinel(info.child, 0, ptr),656 .C => indexOfSentinel(info.child, 0, ptr),
591 .Slice => ptr.len,657 .Slice => if (info.sentinel) |sentinel|
658 indexOfSentinel(info.child, sentinel, ptr.ptr)
659 else
660 ptr.len,
592 },661 },
593 else => @compileError("invalid type given to std.mem.length"),662 else => @compileError("invalid type given to std.mem.lenZ"),
594 };663 };
595}664}
596665
597test "len" {666test "lenZ" {
598 testing.expect(len("aoeu") == 4);667 testing.expect(lenZ("aoeu") == 4);
599668
600 {669 {
601 var array: [5]u16 = [_]u16{ 1, 2, 3, 4, 5 };670 var array: [5]u16 = [_]u16{ 1, 2, 3, 4, 5 };
602 testing.expect(len(&array) == 5);671 testing.expect(lenZ(&array) == 5);
603 testing.expect(len(array[0..3]) == 3);672 testing.expect(lenZ(array[0..3]) == 3);
604 array[2] = 0;673 array[2] = 0;
605 const ptr = @as([*:0]u16, array[0..2 :0]);674 const ptr = @as([*:0]u16, array[0..2 :0]);
606 testing.expect(len(ptr) == 2);675 testing.expect(lenZ(ptr) == 2);
607 }676 }
608 {677 {
609 var array: [5:0]u16 = [_:0]u16{ 1, 2, 3, 4, 5 };678 var array: [5:0]u16 = [_:0]u16{ 1, 2, 3, 4, 5 };
610 testing.expect(len(&array) == 5);679 testing.expect(lenZ(&array) == 5);
611 array[2] = 0;680 array[2] = 0;
612 testing.expect(len(&array) == 2);681 testing.expect(lenZ(&array) == 2);
613 }682 }
614}683}
615684