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