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