@@ -595,3 +595,226 @@ 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
+ match $info {
717
+ info => {
718
+ multislice!( @check $view, info, ( $( $mut_info) * ) ) ;
719
+ multislice!( @check $view, info, ( $( $immut_info) * ) ) ;
720
+ ( $( $sliced) * unsafe { $view. aliasing_view_mut( ) } . slice_move( info) )
721
+ }
722
+ }
723
+ } ;
724
+ // Parse last slice (read-only), no trailing comma.
725
+ (
726
+ @parse $view: expr,
727
+ ( $( $sliced: tt) * ) ,
728
+ ( $( $mut_info: tt) * ) ,
729
+ ( $( $immut_info: tt) * ) ,
730
+ ( $info: expr)
731
+ ) => {
732
+ match $info {
733
+ info => {
734
+ multislice!( @check $view, info, ( $( $mut_info) * ) ) ;
735
+ ( $( $sliced) * unsafe { $view. aliasing_view( ) } . slice_move( info) )
736
+ }
737
+ }
738
+ } ;
739
+ // Parse last slice (mutable), with trailing comma.
740
+ (
741
+ @parse $view: expr,
742
+ ( $( $sliced: tt) * ) ,
743
+ ( $( $mut_info: tt) * ) ,
744
+ ( $( $immut_info: tt) * ) ,
745
+ ( mut $info: expr, )
746
+ ) => {
747
+ match $info {
748
+ info => {
749
+ multislice!( @check $view, info, ( $( $mut_info) * ) ) ;
750
+ multislice!( @check $view, info, ( $( $immut_info) * ) ) ;
751
+ ( $( $sliced) * unsafe { $view. aliasing_view_mut( ) } . slice_move( info) )
752
+ }
753
+ }
754
+ } ;
755
+ // Parse last slice (read-only), with trailing comma.
756
+ (
757
+ @parse $view: expr,
758
+ ( $( $sliced: tt) * ) ,
759
+ ( $( $mut_info: tt) * ) ,
760
+ ( $( $immut_info: tt) * ) ,
761
+ ( $info: expr, )
762
+ ) => {
763
+ match $info {
764
+ info => {
765
+ multislice!( @check $view, info, ( $( $mut_info) * ) ) ;
766
+ ( $( $sliced) * unsafe { $view. aliasing_view( ) } . slice_move( info) )
767
+ }
768
+ }
769
+ } ;
770
+ // Parse a mutable slice.
771
+ (
772
+ @parse $view: expr,
773
+ ( $( $sliced: tt) * ) ,
774
+ ( $( $mut_info: tt) * ) ,
775
+ ( $( $immut_info: tt) * ) ,
776
+ ( mut $info: expr, $( $t: tt) * )
777
+ ) => {
778
+ match $info {
779
+ info => {
780
+ multislice!( @check $view, info, ( $( $mut_info) * ) ) ;
781
+ multislice!( @check $view, info, ( $( $immut_info) * ) ) ;
782
+ multislice!(
783
+ @parse $view,
784
+ ( $( $sliced) * unsafe { $view. aliasing_view_mut( ) } . slice_move( info) , ) ,
785
+ ( $( $mut_info) * info, ) ,
786
+ ( $( $immut_info) * ) ,
787
+ ( $( $t) * )
788
+ )
789
+ }
790
+ }
791
+ } ;
792
+ // Parse a read-only slice.
793
+ (
794
+ @parse $view: expr,
795
+ ( $( $sliced: tt) * ) ,
796
+ ( $( $mut_info: tt) * ) ,
797
+ ( $( $immut_info: tt) * ) ,
798
+ ( $info: expr, $( $t: tt) * )
799
+ ) => {
800
+ match $info {
801
+ info => {
802
+ multislice!( @check $view, info, ( $( $mut_info) * ) ) ;
803
+ multislice!(
804
+ @parse $view,
805
+ ( $( $sliced) * unsafe { $view. aliasing_view( ) } . slice_move( info) , ) ,
806
+ ( $( $mut_info) * ) ,
807
+ ( $( $immut_info) * info, ) ,
808
+ ( $( $t) * )
809
+ )
810
+ }
811
+ }
812
+ } ;
813
+ // Entry point.
814
+ ( $arr: expr, ( $( $t: tt) * ) ) => {
815
+ {
816
+ let view = $crate:: ArrayBase :: view_mut( & mut $arr) ;
817
+ multislice!( @parse view, ( ) , ( ) , ( ) , ( $( $t) * ) )
818
+ }
819
+ } ;
820
+ ) ;
0 commit comments