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