@@ -602,6 +602,7 @@ test "span" {
602
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
606
/// Same as `span`, except when there is both a sentinel and an array
606
607
/// length or slice length, scans the memory for the sentinel value
607
608
/// rather than using the length.
@@ -630,6 +631,192 @@ test "spanZ" {
630
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
820
/// Takes a pointer to an array, an array, a vector, a sentinel-terminated pointer,
634
821
/// a slice or a tuple, and returns the length.
635
822
/// In the case of a sentinel-terminated array, it uses the array length.
@@ -688,6 +875,7 @@ test "len" {
688
875
}
689
876
}
690
877
878
+ /// Deprecated: use std.mem.len() or std.mem.sliceTo().len
691
879
/// Takes a pointer to an array, an array, a sentinel-terminated pointer,
692
880
/// or a slice, and returns the length.
693
881
/// In the case of a sentinel-terminated array, it scans the array
0 commit comments