| ... | @@ -602,6 +602,7 @@ test "span" { | ... | @@ -602,6 +602,7 @@ test "span" { |
| 602 | try testing.expectEqual(@as(?[:0]u16, null), span(@as(?[*:0]u16, null))); | 602 | try testing.expectEqual(@as(?[:0]u16, null), span(@as(?[*:0]u16, null))); |
| 603 | } | 603 | } |
| 604 | | 604 | |
| | 605 | /// Deprecated: use std.mem.span() or std.mem.sliceTo() |
| 605 | /// Same as `span`, except when there is both a sentinel and an array | 606 | /// Same as `span`, except when there is both a sentinel and an array |
| 606 | /// length or slice length, scans the memory for the sentinel value | 607 | /// length or slice length, scans the memory for the sentinel value |
| 607 | /// rather than using the length. | 608 | /// rather than using the length. |
| ... | @@ -630,6 +631,192 @@ test "spanZ" { | ... | @@ -630,6 +631,192 @@ test "spanZ" { |
| 630 | try testing.expectEqual(@as(?[:0]u16, null), spanZ(@as(?[*:0]u16, null))); | 631 | try testing.expectEqual(@as(?[:0]u16, null), spanZ(@as(?[*:0]u16, null))); |
| 631 | } | 632 | } |
| 632 | | 633 | |
| | 634 | /// Helper for the return type of sliceTo() |
| | 635 | fn SliceTo(comptime T: type, comptime end: meta.Elem(T)) type { |
| | 636 | switch (@typeInfo(T)) { |
| | 637 | .Optional => |optional_info| { |
| | 638 | return ?SliceTo(optional_info.child, end); |
| | 639 | }, |
| | 640 | .Pointer => |ptr_info| { |
| | 641 | var new_ptr_info = ptr_info; |
| | 642 | new_ptr_info.size = .Slice; |
| | 643 | switch (ptr_info.size) { |
| | 644 | .One => switch (@typeInfo(ptr_info.child)) { |
| | 645 | .Array => |array_info| { |
| | 646 | new_ptr_info.child = array_info.child; |
| | 647 | // The return type must only be sentinel terminated if we are guaranteed |
| | 648 | // to find the value searched for, which is only the case if it matches |
| | 649 | // the sentinel of the type passed. |
| | 650 | if (array_info.sentinel) |sentinel| { |
| | 651 | if (end == sentinel) { |
| | 652 | new_ptr_info.sentinel = end; |
| | 653 | } else { |
| | 654 | new_ptr_info.sentinel = null; |
| | 655 | } |
| | 656 | } |
| | 657 | }, |
| | 658 | else => {}, |
| | 659 | }, |
| | 660 | .Many, .Slice => { |
| | 661 | // The return type must only be sentinel terminated if we are guaranteed |
| | 662 | // to find the value searched for, which is only the case if it matches |
| | 663 | // the sentinel of the type passed. |
| | 664 | if (ptr_info.sentinel) |sentinel| { |
| | 665 | if (end == sentinel) { |
| | 666 | new_ptr_info.sentinel = end; |
| | 667 | } else { |
| | 668 | new_ptr_info.sentinel = null; |
| | 669 | } |
| | 670 | } |
| | 671 | }, |
| | 672 | .C => { |
| | 673 | new_ptr_info.sentinel = end; |
| | 674 | // C pointers are always allowzero, but we don't want the return type to be. |
| | 675 | assert(new_ptr_info.is_allowzero); |
| | 676 | new_ptr_info.is_allowzero = false; |
| | 677 | }, |
| | 678 | } |
| | 679 | return @Type(std.builtin.TypeInfo{ .Pointer = new_ptr_info }); |
| | 680 | }, |
| | 681 | else => {}, |
| | 682 | } |
| | 683 | @compileError("invalid type given to std.mem.sliceTo: " ++ @typeName(T)); |
| | 684 | } |
| | 685 | |
| | 686 | /// Takes a pointer to an array, an array, a sentinel-terminated pointer, or a slice and |
| | 687 | /// iterates searching for the first occurrence of `end`, returning the scanned slice. |
| | 688 | /// If `end` is not found, the full length of the array/slice/sentinel terminated pointer is returned. |
| | 689 | /// If the pointer type is sentinel terminated and `end` matches that terminator, the |
| | 690 | /// resulting slice is also sentinel terminated. |
| | 691 | /// Pointer properties such as mutability and alignment are preserved. |
| | 692 | /// C pointers are assumed to be non-null. |
| | 693 | pub fn sliceTo(ptr: anytype, comptime end: meta.Elem(@TypeOf(ptr))) SliceTo(@TypeOf(ptr), end) { |
| | 694 | if (@typeInfo(@TypeOf(ptr)) == .Optional) { |
| | 695 | const non_null = ptr orelse return null; |
| | 696 | return sliceTo(non_null, end); |
| | 697 | } |
| | 698 | const Result = SliceTo(@TypeOf(ptr), end); |
| | 699 | const length = lenSliceTo(ptr, end); |
| | 700 | if (@typeInfo(Result).Pointer.sentinel) |s| { |
| | 701 | return ptr[0..length :s]; |
| | 702 | } else { |
| | 703 | return ptr[0..length]; |
| | 704 | } |
| | 705 | } |
| | 706 | |
| | 707 | test "sliceTo" { |
| | 708 | try testing.expectEqualSlices(u8, "aoeu", sliceTo("aoeu", 0)); |
| | 709 | |
| | 710 | { |
| | 711 | var array: [5]u16 = [_]u16{ 1, 2, 3, 4, 5 }; |
| | 712 | try testing.expectEqualSlices(u16, &array, sliceTo(&array, 0)); |
| | 713 | try testing.expectEqualSlices(u16, array[0..3], sliceTo(array[0..3], 0)); |
| | 714 | try testing.expectEqualSlices(u16, array[0..2], sliceTo(&array, 3)); |
| | 715 | try testing.expectEqualSlices(u16, array[0..2], sliceTo(array[0..3], 3)); |
| | 716 | |
| | 717 | const sentinel_ptr = @ptrCast([*:5]u16, &array); |
| | 718 | try testing.expectEqualSlices(u16, array[0..2], sliceTo(sentinel_ptr, 3)); |
| | 719 | try testing.expectEqualSlices(u16, array[0..4], sliceTo(sentinel_ptr, 99)); |
| | 720 | |
| | 721 | const optional_sentinel_ptr = @ptrCast(?[*:5]u16, &array); |
| | 722 | try testing.expectEqualSlices(u16, array[0..2], sliceTo(optional_sentinel_ptr, 3).?); |
| | 723 | try testing.expectEqualSlices(u16, array[0..4], sliceTo(optional_sentinel_ptr, 99).?); |
| | 724 | |
| | 725 | const c_ptr = @as([*c]u16, &array); |
| | 726 | try testing.expectEqualSlices(u16, array[0..2], sliceTo(c_ptr, 3)); |
| | 727 | |
| | 728 | const slice: []u16 = &array; |
| | 729 | try testing.expectEqualSlices(u16, array[0..2], sliceTo(slice, 3)); |
| | 730 | try testing.expectEqualSlices(u16, &array, sliceTo(slice, 99)); |
| | 731 | |
| | 732 | const sentinel_slice: [:5]u16 = array[0..4 :5]; |
| | 733 | try testing.expectEqualSlices(u16, array[0..2], sliceTo(sentinel_slice, 3)); |
| | 734 | try testing.expectEqualSlices(u16, array[0..4], sliceTo(sentinel_slice, 99)); |
| | 735 | } |
| | 736 | { |
| | 737 | var sentinel_array: [5:0]u16 = [_:0]u16{ 1, 2, 3, 4, 5 }; |
| | 738 | try testing.expectEqualSlices(u16, sentinel_array[0..2], sliceTo(&sentinel_array, 3)); |
| | 739 | try testing.expectEqualSlices(u16, &sentinel_array, sliceTo(&sentinel_array, 0)); |
| | 740 | try testing.expectEqualSlices(u16, &sentinel_array, sliceTo(&sentinel_array, 99)); |
| | 741 | } |
| | 742 | |
| | 743 | try testing.expectEqual(@as(?[]u8, null), sliceTo(@as(?[]u8, null), 0)); |
| | 744 | } |
| | 745 | |
| | 746 | /// Private helper for sliceTo(). If you want the length, use sliceTo(foo, x).len |
| | 747 | fn lenSliceTo(ptr: anytype, comptime end: meta.Elem(@TypeOf(ptr))) usize { |
| | 748 | switch (@typeInfo(@TypeOf(ptr))) { |
| | 749 | .Pointer => |ptr_info| switch (ptr_info.size) { |
| | 750 | .One => switch (@typeInfo(ptr_info.child)) { |
| | 751 | .Array => |array_info| { |
| | 752 | if (array_info.sentinel) |sentinel| { |
| | 753 | if (sentinel == end) { |
| | 754 | return indexOfSentinel(array_info.child, end, ptr); |
| | 755 | } |
| | 756 | } |
| | 757 | return indexOfScalar(array_info.child, ptr, end) orelse array_info.len; |
| | 758 | }, |
| | 759 | else => {}, |
| | 760 | }, |
| | 761 | .Many => if (ptr_info.sentinel) |sentinel| { |
| | 762 | // We may be looking for something other than the sentinel, |
| | 763 | // but iterating past the sentinel would be a bug so we need |
| | 764 | // to check for both. |
| | 765 | var i: usize = 0; |
| | 766 | while (ptr[i] != end and ptr[i] != sentinel) i += 1; |
| | 767 | return i; |
| | 768 | }, |
| | 769 | .C => { |
| | 770 | assert(ptr != null); |
| | 771 | return indexOfSentinel(ptr_info.child, end, ptr); |
| | 772 | }, |
| | 773 | .Slice => { |
| | 774 | if (ptr_info.sentinel) |sentinel| { |
| | 775 | if (sentinel == end) { |
| | 776 | return indexOfSentinel(ptr_info.child, sentinel, ptr); |
| | 777 | } |
| | 778 | } |
| | 779 | return indexOfScalar(ptr_info.child, ptr, end) orelse ptr.len; |
| | 780 | }, |
| | 781 | }, |
| | 782 | else => {}, |
| | 783 | } |
| | 784 | @compileError("invalid type given to std.mem.sliceTo: " ++ @typeName(@TypeOf(ptr))); |
| | 785 | } |
| | 786 | |
| | 787 | test "lenSliceTo" { |
| | 788 | try testing.expect(lenSliceTo("aoeu", 0) == 4); |
| | 789 | |
| | 790 | { |
| | 791 | var array: [5]u16 = [_]u16{ 1, 2, 3, 4, 5 }; |
| | 792 | try testing.expectEqual(@as(usize, 5), lenSliceTo(&array, 0)); |
| | 793 | try testing.expectEqual(@as(usize, 3), lenSliceTo(array[0..3], 0)); |
| | 794 | try testing.expectEqual(@as(usize, 2), lenSliceTo(&array, 3)); |
| | 795 | try testing.expectEqual(@as(usize, 2), lenSliceTo(array[0..3], 3)); |
| | 796 | |
| | 797 | const sentinel_ptr = @ptrCast([*:5]u16, &array); |
| | 798 | try testing.expectEqual(@as(usize, 2), lenSliceTo(sentinel_ptr, 3)); |
| | 799 | try testing.expectEqual(@as(usize, 4), lenSliceTo(sentinel_ptr, 99)); |
| | 800 | |
| | 801 | const c_ptr = @as([*c]u16, &array); |
| | 802 | try testing.expectEqual(@as(usize, 2), lenSliceTo(c_ptr, 3)); |
| | 803 | |
| | 804 | const slice: []u16 = &array; |
| | 805 | try testing.expectEqual(@as(usize, 2), lenSliceTo(slice, 3)); |
| | 806 | try testing.expectEqual(@as(usize, 5), lenSliceTo(slice, 99)); |
| | 807 | |
| | 808 | const sentinel_slice: [:5]u16 = array[0..4 :5]; |
| | 809 | try testing.expectEqual(@as(usize, 2), lenSliceTo(sentinel_slice, 3)); |
| | 810 | try testing.expectEqual(@as(usize, 4), lenSliceTo(sentinel_slice, 99)); |
| | 811 | } |
| | 812 | { |
| | 813 | var sentinel_array: [5:0]u16 = [_:0]u16{ 1, 2, 3, 4, 5 }; |
| | 814 | try testing.expectEqual(@as(usize, 2), lenSliceTo(&sentinel_array, 3)); |
| | 815 | try testing.expectEqual(@as(usize, 5), lenSliceTo(&sentinel_array, 0)); |
| | 816 | try testing.expectEqual(@as(usize, 5), lenSliceTo(&sentinel_array, 99)); |
| | 817 | } |
| | 818 | } |
| | 819 | |
| 633 | /// Takes a pointer to an array, an array, a vector, a sentinel-terminated pointer, | 820 | /// Takes a pointer to an array, an array, a vector, a sentinel-terminated pointer, |
| 634 | /// a slice or a tuple, and returns the length. | 821 | /// a slice or a tuple, and returns the length. |
| 635 | /// In the case of a sentinel-terminated array, it uses the array length. | 822 | /// In the case of a sentinel-terminated array, it uses the array length. |
| ... | @@ -688,6 +875,7 @@ test "len" { | ... | @@ -688,6 +875,7 @@ test "len" { |
| 688 | } | 875 | } |
| 689 | } | 876 | } |
| 690 | | 877 | |
| | 878 | /// Deprecated: use std.mem.len() or std.mem.sliceTo().len |
| 691 | /// Takes a pointer to an array, an array, a sentinel-terminated pointer, | 879 | /// Takes a pointer to an array, an array, a sentinel-terminated pointer, |
| 692 | /// or a slice, and returns the length. | 880 | /// or a slice, and returns the length. |
| 693 | /// In the case of a sentinel-terminated array, it scans the array | 881 | /// In the case of a sentinel-terminated array, it scans the array |