@@ -627,3 +627,226 @@ macro_rules! s(
627
627
& * & s![ @parse :: std:: marker:: PhantomData :: <$crate:: Ix0 >, [ ] $( $t) * ]
628
628
} ;
629
629
) ;
630
+
631
+ /// Take multiple slices simultaneously.
632
+ ///
633
+ /// This macro makes it possible to take multiple slices of the same array, as
634
+ /// long as Rust's aliasing rules are followed for *elements* in the slices.
635
+ /// For example, it's possible to take two disjoint, mutable slices of an
636
+ /// array, with one referencing the even-index elements and the other
637
+ /// referencing the odd-index elements. If you tried to achieve this by calling
638
+ /// `.slice_mut()` twice, the borrow checker would complain about mutably
639
+ /// borrowing the array twice (even though it's safe as long as the slices are
640
+ /// disjoint).
641
+ ///
642
+ /// The syntax is `multislice!(` *expression, (pattern [, pattern [, …]])* `)`,
643
+ /// where *expression* evaluates to an `ArrayBase<S, D>` where `S: DataMut`,
644
+ /// and `pattern` is one of the following:
645
+ ///
646
+ /// * `mut expr`: creates an `ArrayViewMut`, where `expr` evaluates to a
647
+ /// `&SliceInfo` instance used to slice the array.
648
+ /// * `expr`: creates an `ArrayView`, where `expr` evaluates to a `&SliceInfo`
649
+ /// instance used to slice the array.
650
+ ///
651
+ /// **Note** that this macro always mutably borrows the array even if there are
652
+ /// no `mut` patterns. If all you want to do is take read-only slices, you
653
+ /// don't need `multislice!()`; just call
654
+ /// [`.slice()`](struct.ArrayBase.html#method.slice) multiple times instead.
655
+ ///
656
+ /// `multislice!()` follows Rust's aliasing rules:
657
+ ///
658
+ /// * An `ArrayViewMut` and `ArrayView` cannot reference the same element.
659
+ /// * Two `ArrayViewMut` cannot reference the same element.
660
+ /// * Two `ArrayView` can reference the same element.
661
+ ///
662
+ /// **Panics** at runtime if any of the aliasing rules is violated.
663
+ ///
664
+ /// See also [*Slicing*](struct.ArrayBase.html#slicing).
665
+ ///
666
+ /// # Examples
667
+ ///
668
+ /// In this example, there are two overlapping read-only slices, and two
669
+ /// disjoint mutable slices. Neither of the mutable slices intersects any of
670
+ /// the other slices.
671
+ ///
672
+ /// ```
673
+ /// #[macro_use]
674
+ /// extern crate ndarray;
675
+ ///
676
+ /// use ndarray::prelude::*;
677
+ ///
678
+ /// # fn main() {
679
+ /// let mut arr = Array1::from_iter(0..12);
680
+ /// let (a, b, c, d) = multislice!(arr, (s![0..5], mut s![6..;2], s![1..6], mut s![7..;2]));
681
+ /// assert_eq!(a, array![0, 1, 2, 3, 4]);
682
+ /// assert_eq!(b, array![6, 8, 10]);
683
+ /// assert_eq!(c, array![1, 2, 3, 4, 5]);
684
+ /// assert_eq!(d, array![7, 9, 11]);
685
+ /// # }
686
+ /// ```
687
+ ///
688
+ /// These examples panic because they don't follow the aliasing rules:
689
+ ///
690
+ /// * `ArrayViewMut` and `ArrayView` cannot reference the same element.
691
+ ///
692
+ /// ```should_panic
693
+ /// # #[macro_use] extern crate ndarray;
694
+ /// # use ndarray::prelude::*;
695
+ /// # fn main() {
696
+ /// let mut arr = Array1::from_iter(0..12);
697
+ /// multislice!(arr, (s![0..5], mut s![1..;2])); // panic!
698
+ /// # }
699
+ /// ```
700
+ ///
701
+ /// * Two `ArrayViewMut` cannot reference the same element.
702
+ ///
703
+ /// ```should_panic
704
+ /// # #[macro_use] extern crate ndarray;
705
+ /// # use ndarray::prelude::*;
706
+ /// # fn main() {
707
+ /// let mut arr = Array1::from_iter(0..12);
708
+ /// multislice!(arr, (mut s![0..5], mut s![1..;2])); // panic!
709
+ /// # }
710
+ /// ```
711
+ #[ macro_export]
712
+ macro_rules! multislice(
713
+ (
714
+ @check $view: expr,
715
+ $info: expr,
716
+ ( )
717
+ ) => { } ;
718
+ // Check that $info doesn't intersect $other.
719
+ (
720
+ @check $view: expr,
721
+ $info: expr,
722
+ ( $other: expr, )
723
+ ) => {
724
+ assert!(
725
+ !$crate:: slices_intersect( & $view. raw_dim( ) , $info, $other) ,
726
+ "Slice {:?} must not intersect slice {:?}" , $info, $other
727
+ )
728
+ } ;
729
+ // Check that $info doesn't intersect any of the other info in the tuple.
730
+ (
731
+ @check $view: expr,
732
+ $info: expr,
733
+ ( $other: expr, $( $more: tt) * )
734
+ ) => {
735
+ {
736
+ multislice!( @check $view, $info, ( $other, ) ) ;
737
+ multislice!( @check $view, $info, ( $( $more) * ) ) ;
738
+ }
739
+ } ;
740
+ // Parse last slice (mutable), no trailing comma.
741
+ (
742
+ @parse $view: expr,
743
+ ( $( $sliced: tt) * ) ,
744
+ ( $( $mut_info: tt) * ) ,
745
+ ( $( $immut_info: tt) * ) ,
746
+ ( mut $info: expr)
747
+ ) => {
748
+ match $info {
749
+ info => {
750
+ multislice!( @check $view, info, ( $( $mut_info) * ) ) ;
751
+ multislice!( @check $view, info, ( $( $immut_info) * ) ) ;
752
+ ( $( $sliced) * unsafe { $view. aliasing_view_mut( ) } . slice_move( info) )
753
+ }
754
+ }
755
+ } ;
756
+ // Parse last slice (read-only), no trailing comma.
757
+ (
758
+ @parse $view: expr,
759
+ ( $( $sliced: tt) * ) ,
760
+ ( $( $mut_info: tt) * ) ,
761
+ ( $( $immut_info: tt) * ) ,
762
+ ( $info: expr)
763
+ ) => {
764
+ match $info {
765
+ info => {
766
+ multislice!( @check $view, info, ( $( $mut_info) * ) ) ;
767
+ ( $( $sliced) * unsafe { $view. aliasing_view( ) } . slice_move( info) )
768
+ }
769
+ }
770
+ } ;
771
+ // Parse last slice (mutable), with trailing comma.
772
+ (
773
+ @parse $view: expr,
774
+ ( $( $sliced: tt) * ) ,
775
+ ( $( $mut_info: tt) * ) ,
776
+ ( $( $immut_info: tt) * ) ,
777
+ ( mut $info: expr, )
778
+ ) => {
779
+ match $info {
780
+ info => {
781
+ multislice!( @check $view, info, ( $( $mut_info) * ) ) ;
782
+ multislice!( @check $view, info, ( $( $immut_info) * ) ) ;
783
+ ( $( $sliced) * unsafe { $view. aliasing_view_mut( ) } . slice_move( info) )
784
+ }
785
+ }
786
+ } ;
787
+ // Parse last slice (read-only), with trailing comma.
788
+ (
789
+ @parse $view: expr,
790
+ ( $( $sliced: tt) * ) ,
791
+ ( $( $mut_info: tt) * ) ,
792
+ ( $( $immut_info: tt) * ) ,
793
+ ( $info: expr, )
794
+ ) => {
795
+ match $info {
796
+ info => {
797
+ multislice!( @check $view, info, ( $( $mut_info) * ) ) ;
798
+ ( $( $sliced) * unsafe { $view. aliasing_view( ) } . slice_move( info) )
799
+ }
800
+ }
801
+ } ;
802
+ // Parse a mutable slice.
803
+ (
804
+ @parse $view: expr,
805
+ ( $( $sliced: tt) * ) ,
806
+ ( $( $mut_info: tt) * ) ,
807
+ ( $( $immut_info: tt) * ) ,
808
+ ( mut $info: expr, $( $t: tt) * )
809
+ ) => {
810
+ match $info {
811
+ info => {
812
+ multislice!( @check $view, info, ( $( $mut_info) * ) ) ;
813
+ multislice!( @check $view, info, ( $( $immut_info) * ) ) ;
814
+ multislice!(
815
+ @parse $view,
816
+ ( $( $sliced) * unsafe { $view. aliasing_view_mut( ) } . slice_move( info) , ) ,
817
+ ( $( $mut_info) * info, ) ,
818
+ ( $( $immut_info) * ) ,
819
+ ( $( $t) * )
820
+ )
821
+ }
822
+ }
823
+ } ;
824
+ // Parse a read-only slice.
825
+ (
826
+ @parse $view: expr,
827
+ ( $( $sliced: tt) * ) ,
828
+ ( $( $mut_info: tt) * ) ,
829
+ ( $( $immut_info: tt) * ) ,
830
+ ( $info: expr, $( $t: tt) * )
831
+ ) => {
832
+ match $info {
833
+ info => {
834
+ multislice!( @check $view, info, ( $( $mut_info) * ) ) ;
835
+ multislice!(
836
+ @parse $view,
837
+ ( $( $sliced) * unsafe { $view. aliasing_view( ) } . slice_move( info) , ) ,
838
+ ( $( $mut_info) * ) ,
839
+ ( $( $immut_info) * info, ) ,
840
+ ( $( $t) * )
841
+ )
842
+ }
843
+ }
844
+ } ;
845
+ // Entry point.
846
+ ( $arr: expr, ( $( $t: tt) * ) ) => {
847
+ {
848
+ let view = $crate:: ArrayBase :: view_mut( & mut $arr) ;
849
+ multislice!( @parse view, ( ) , ( ) , ( ) , ( $( $t) * ) )
850
+ }
851
+ } ;
852
+ ) ;
0 commit comments