ndarray/dimension/
dimension_trait.rs

1// Copyright 2014-2016 bluss and ndarray developers.
2//
3// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
4// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
5// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
6// option. This file may not be copied, modified, or distributed
7// except according to those terms.
8
9use std::fmt::Debug;
10use std::ops::{Add, AddAssign, Mul, MulAssign, Sub, SubAssign};
11use std::ops::{Index, IndexMut};
12use alloc::vec::Vec;
13
14use super::axes_of;
15use super::conversion::Convert;
16use super::ops::DimAdd;
17use super::{stride_offset, stride_offset_checked};
18use crate::itertools::{enumerate, zip};
19use crate::{Axis, DimMax};
20use crate::IntoDimension;
21use crate::RemoveAxis;
22use crate::{ArrayView1, ArrayViewMut1};
23use crate::{Dim, Ix, Ix0, Ix1, Ix2, Ix3, Ix4, Ix5, Ix6, IxDyn, IxDynImpl, Ixs};
24
25/// Array shape and index trait.
26///
27/// This trait defines a number of methods and operations that can be used on
28/// dimensions and indices.
29///
30/// **Note:** *This trait can not be implemented outside the crate*
31pub trait Dimension:
32    Clone
33    + Eq
34    + Debug
35    + Send
36    + Sync
37    + Default
38    + IndexMut<usize, Output = usize>
39    + Add<Self, Output = Self>
40    + AddAssign
41    + for<'x> AddAssign<&'x Self>
42    + Sub<Self, Output = Self>
43    + SubAssign
44    + for<'x> SubAssign<&'x Self>
45    + Mul<usize, Output = Self>
46    + Mul<Self, Output = Self>
47    + MulAssign
48    + for<'x> MulAssign<&'x Self>
49    + MulAssign<usize>
50    + DimMax<Ix0, Output=Self>
51    + DimMax<Self, Output=Self>
52    + DimMax<IxDyn, Output=IxDyn>
53    + DimMax<<Self as Dimension>::Smaller, Output=Self>
54    + DimMax<<Self as Dimension>::Larger, Output=<Self as Dimension>::Larger>
55    + DimAdd<Self>
56    + DimAdd<<Self as Dimension>::Smaller>
57    + DimAdd<<Self as Dimension>::Larger>
58    + DimAdd<Ix0, Output = Self>
59    + DimAdd<Ix1, Output = <Self as Dimension>::Larger>
60    + DimAdd<IxDyn, Output = IxDyn>
61{
62    /// For fixed-size dimension representations (e.g. `Ix2`), this should be
63    /// `Some(ndim)`, and for variable-size dimension representations (e.g.
64    /// `IxDyn`), this should be `None`.
65    const NDIM: Option<usize>;
66    /// Pattern matching friendly form of the dimension value.
67    ///
68    /// - For `Ix1`: `usize`,
69    /// - For `Ix2`: `(usize, usize)`
70    /// - and so on..
71    /// - For `IxDyn`: `IxDyn`
72    type Pattern: IntoDimension<Dim = Self> + Clone + Debug + PartialEq + Eq + Default;
73    /// Next smaller dimension (if applicable)
74    type Smaller: Dimension;
75    /// Next larger dimension
76    type Larger: Dimension + RemoveAxis;
77
78    /// Returns the number of dimensions (number of axes).
79    fn ndim(&self) -> usize;
80
81    /// Convert the dimension into a pattern matching friendly value.
82    fn into_pattern(self) -> Self::Pattern;
83
84    /// Compute the size of the dimension (number of elements)
85    fn size(&self) -> usize {
86        self.slice().iter().fold(1, |s, &a| s * a as usize)
87    }
88
89    /// Compute the size while checking for overflow.
90    fn size_checked(&self) -> Option<usize> {
91        self.slice()
92            .iter()
93            .fold(Some(1), |s, &a| s.and_then(|s_| s_.checked_mul(a)))
94    }
95
96    #[doc(hidden)]
97    fn slice(&self) -> &[Ix];
98
99    #[doc(hidden)]
100    fn slice_mut(&mut self) -> &mut [Ix];
101
102    /// Borrow as a read-only array view.
103    fn as_array_view(&self) -> ArrayView1<'_, Ix> {
104        ArrayView1::from(self.slice())
105    }
106
107    /// Borrow as a read-write array view.
108    fn as_array_view_mut(&mut self) -> ArrayViewMut1<'_, Ix> {
109        ArrayViewMut1::from(self.slice_mut())
110    }
111
112    #[doc(hidden)]
113    fn equal(&self, rhs: &Self) -> bool {
114        self.slice() == rhs.slice()
115    }
116
117    /// Returns the strides for a standard layout array with the given shape.
118    ///
119    /// If the array is non-empty, the strides result in contiguous layout; if
120    /// the array is empty, the strides are all zeros.
121    #[doc(hidden)]
122    fn default_strides(&self) -> Self {
123        // Compute default array strides
124        // Shape (a, b, c) => Give strides (b * c, c, 1)
125        let mut strides = Self::zeros(self.ndim());
126        // For empty arrays, use all zero strides.
127        if self.slice().iter().all(|&d| d != 0) {
128            let mut it = strides.slice_mut().iter_mut().rev();
129            // Set first element to 1
130            if let Some(rs) = it.next() {
131                *rs = 1;
132            }
133            let mut cum_prod = 1;
134            for (rs, dim) in it.zip(self.slice().iter().rev()) {
135                cum_prod *= *dim;
136                *rs = cum_prod;
137            }
138        }
139        strides
140    }
141
142    /// Returns the strides for a Fortran layout array with the given shape.
143    ///
144    /// If the array is non-empty, the strides result in contiguous layout; if
145    /// the array is empty, the strides are all zeros.
146    #[doc(hidden)]
147    fn fortran_strides(&self) -> Self {
148        // Compute fortran array strides
149        // Shape (a, b, c) => Give strides (1, a, a * b)
150        let mut strides = Self::zeros(self.ndim());
151        // For empty arrays, use all zero strides.
152        if self.slice().iter().all(|&d| d != 0) {
153            let mut it = strides.slice_mut().iter_mut();
154            // Set first element to 1
155            if let Some(rs) = it.next() {
156                *rs = 1;
157            }
158            let mut cum_prod = 1;
159            for (rs, dim) in it.zip(self.slice()) {
160                cum_prod *= *dim;
161                *rs = cum_prod;
162            }
163        }
164        strides
165    }
166
167    /// Creates a dimension of all zeros with the specified ndim.
168    ///
169    /// This method is useful for generalizing over fixed-size and
170    /// variable-size dimension representations.
171    ///
172    /// **Panics** if `Self` has a fixed size that is not `ndim`.
173    fn zeros(ndim: usize) -> Self;
174
175    #[doc(hidden)]
176    #[inline]
177    fn first_index(&self) -> Option<Self> {
178        for ax in self.slice().iter() {
179            if *ax == 0 {
180                return None;
181            }
182        }
183        Some(Self::zeros(self.ndim()))
184    }
185
186    #[doc(hidden)]
187    /// Iteration -- Use self as size, and return next index after `index`
188    /// or None if there are no more.
189    // FIXME: use &Self for index or even &mut?
190    #[inline]
191    fn next_for(&self, index: Self) -> Option<Self> {
192        let mut index = index;
193        let mut done = false;
194        for (&dim, ix) in zip(self.slice(), index.slice_mut()).rev() {
195            *ix += 1;
196            if *ix == dim {
197                *ix = 0;
198            } else {
199                done = true;
200                break;
201            }
202        }
203        if done {
204            Some(index)
205        } else {
206            None
207        }
208    }
209
210    #[doc(hidden)]
211    /// Iteration -- Use self as size, and create the next index after `index`
212    /// Return false if iteration is done
213    ///
214    /// Next in f-order
215    #[inline]
216    fn next_for_f(&self, index: &mut Self) -> bool {
217        let mut end_iteration = true;
218        for (&dim, ix) in zip(self.slice(), index.slice_mut()) {
219            *ix += 1;
220            if *ix == dim {
221                *ix = 0;
222            } else {
223                end_iteration = false;
224                break;
225            }
226        }
227        !end_iteration
228    }
229
230    /// Returns `true` iff `strides1` and `strides2` are equivalent for the
231    /// shape `self`.
232    ///
233    /// The strides are equivalent if, for each axis with length > 1, the
234    /// strides are equal.
235    ///
236    /// Note: Returns `false` if any of the ndims don't match.
237    #[doc(hidden)]
238    fn strides_equivalent<D>(&self, strides1: &Self, strides2: &D) -> bool
239    where
240        D: Dimension,
241    {
242        let shape_ndim = self.ndim();
243        shape_ndim == strides1.ndim()
244            && shape_ndim == strides2.ndim()
245            && izip!(self.slice(), strides1.slice(), strides2.slice())
246                .all(|(&d, &s1, &s2)| d <= 1 || s1 as isize == s2 as isize)
247    }
248
249    #[doc(hidden)]
250    /// Return stride offset for index.
251    fn stride_offset(index: &Self, strides: &Self) -> isize {
252        let mut offset = 0;
253        for (&i, &s) in izip!(index.slice(), strides.slice()) {
254            offset += stride_offset(i, s);
255        }
256        offset
257    }
258
259    #[doc(hidden)]
260    /// Return stride offset for this dimension and index.
261    fn stride_offset_checked(&self, strides: &Self, index: &Self) -> Option<isize> {
262        stride_offset_checked(self.slice(), strides.slice(), index.slice())
263    }
264
265    #[doc(hidden)]
266    fn last_elem(&self) -> usize {
267        if self.ndim() == 0 {
268            0
269        } else {
270            self.slice()[self.ndim() - 1]
271        }
272    }
273
274    #[doc(hidden)]
275    fn set_last_elem(&mut self, i: usize) {
276        let nd = self.ndim();
277        self.slice_mut()[nd - 1] = i;
278    }
279
280    #[doc(hidden)]
281    fn is_contiguous(dim: &Self, strides: &Self) -> bool {
282        let defaults = dim.default_strides();
283        if strides.equal(&defaults) {
284            return true;
285        }
286        if dim.ndim() == 1 {
287            return strides[0] as isize == -1;
288        }
289        let order = strides._fastest_varying_stride_order();
290        let strides = strides.slice();
291
292        let dim_slice = dim.slice();
293        let mut cstride = 1;
294        for &i in order.slice() {
295            // a dimension of length 1 can have unequal strides
296            if dim_slice[i] != 1 && (strides[i] as isize).abs() as usize != cstride {
297                return false;
298            }
299            cstride *= dim_slice[i];
300        }
301        true
302    }
303
304    /// Return the axis ordering corresponding to the fastest variation
305    /// (in ascending order).
306    ///
307    /// Assumes that no stride value appears twice.
308    #[doc(hidden)]
309    fn _fastest_varying_stride_order(&self) -> Self {
310        let mut indices = self.clone();
311        for (i, elt) in enumerate(indices.slice_mut()) {
312            *elt = i;
313        }
314        let strides = self.slice();
315        indices
316            .slice_mut()
317            .sort_by_key(|&i| (strides[i] as isize).abs());
318        indices
319    }
320
321    /// Compute the minimum stride axis (absolute value), under the constraint
322    /// that the length of the axis is > 1;
323    #[doc(hidden)]
324    fn min_stride_axis(&self, strides: &Self) -> Axis {
325        let n = match self.ndim() {
326            0 => panic!("min_stride_axis: Array must have ndim > 0"),
327            1 => return Axis(0),
328            n => n,
329        };
330        axes_of(self, strides)
331            .rev()
332            .min_by_key(|ax| ax.stride.abs())
333            .map_or(Axis(n - 1), |ax| ax.axis)
334    }
335
336    /// Compute the maximum stride axis (absolute value), under the constraint
337    /// that the length of the axis is > 1;
338    #[doc(hidden)]
339    fn max_stride_axis(&self, strides: &Self) -> Axis {
340        match self.ndim() {
341            0 => panic!("max_stride_axis: Array must have ndim > 0"),
342            1 => return Axis(0),
343            _ => {}
344        }
345        axes_of(self, strides)
346            .filter(|ax| ax.len > 1)
347            .max_by_key(|ax| ax.stride.abs())
348            .map_or(Axis(0), |ax| ax.axis)
349    }
350
351    /// Convert the dimensional into a dynamic dimensional (IxDyn).
352    fn into_dyn(self) -> IxDyn {
353        IxDyn(self.slice())
354    }
355
356    #[doc(hidden)]
357    fn from_dimension<D2: Dimension>(d: &D2) -> Option<Self> {
358        let mut s = Self::default();
359        if s.ndim() == d.ndim() {
360            for i in 0..d.ndim() {
361                s[i] = d[i];
362            }
363            Some(s)
364        } else {
365            None
366        }
367    }
368
369    #[doc(hidden)]
370    fn insert_axis(&self, axis: Axis) -> Self::Larger;
371
372    #[doc(hidden)]
373    fn try_remove_axis(&self, axis: Axis) -> Self::Smaller;
374
375    private_decl! {}
376}
377
378// Dimension impls
379
380macro_rules! impl_insert_axis_array(
381    ($n:expr) => (
382        #[inline]
383        fn insert_axis(&self, axis: Axis) -> Self::Larger {
384            debug_assert!(axis.index() <= $n);
385            let mut out = [1; $n + 1];
386            out[0..axis.index()].copy_from_slice(&self.slice()[0..axis.index()]);
387            out[axis.index()+1..=$n].copy_from_slice(&self.slice()[axis.index()..$n]);
388            Dim(out)
389        }
390    );
391);
392
393impl Dimension for Dim<[Ix; 0]> {
394    const NDIM: Option<usize> = Some(0);
395    type Pattern = ();
396    type Smaller = Self;
397    type Larger = Ix1;
398    // empty product is 1 -> size is 1
399    #[inline]
400    fn ndim(&self) -> usize {
401        0
402    }
403    #[inline]
404    fn slice(&self) -> &[Ix] {
405        &[]
406    }
407    #[inline]
408    fn slice_mut(&mut self) -> &mut [Ix] {
409        &mut []
410    }
411    #[inline]
412    fn _fastest_varying_stride_order(&self) -> Self {
413        Ix0()
414    }
415    #[inline]
416    fn into_pattern(self) -> Self::Pattern {}
417    #[inline]
418    fn zeros(ndim: usize) -> Self {
419        assert_eq!(ndim, 0);
420        Self::default()
421    }
422    #[inline]
423    fn next_for(&self, _index: Self) -> Option<Self> {
424        None
425    }
426    impl_insert_axis_array!(0);
427    #[inline]
428    fn try_remove_axis(&self, _ignore: Axis) -> Self::Smaller {
429        *self
430    }
431
432    private_impl! {}
433}
434
435impl Dimension for Dim<[Ix; 1]> {
436    const NDIM: Option<usize> = Some(1);
437    type Pattern = Ix;
438    type Smaller = Ix0;
439    type Larger = Ix2;
440    #[inline]
441    fn ndim(&self) -> usize {
442        1
443    }
444    #[inline]
445    fn slice(&self) -> &[Ix] {
446        self.ix()
447    }
448    #[inline]
449    fn slice_mut(&mut self) -> &mut [Ix] {
450        self.ixm()
451    }
452    #[inline]
453    fn into_pattern(self) -> Self::Pattern {
454        get!(&self, 0)
455    }
456    #[inline]
457    fn zeros(ndim: usize) -> Self {
458        assert_eq!(ndim, 1);
459        Self::default()
460    }
461    #[inline]
462    fn next_for(&self, mut index: Self) -> Option<Self> {
463        getm!(index, 0) += 1;
464        if get!(&index, 0) < get!(self, 0) {
465            Some(index)
466        } else {
467            None
468        }
469    }
470
471    #[inline]
472    fn equal(&self, rhs: &Self) -> bool {
473        get!(self, 0) == get!(rhs, 0)
474    }
475
476    #[inline]
477    fn size(&self) -> usize {
478        get!(self, 0)
479    }
480    #[inline]
481    fn size_checked(&self) -> Option<usize> {
482        Some(get!(self, 0))
483    }
484
485    #[inline]
486    fn default_strides(&self) -> Self {
487        if get!(self, 0) == 0 {
488            Ix1(0)
489        } else {
490            Ix1(1)
491        }
492    }
493
494    #[inline]
495    fn _fastest_varying_stride_order(&self) -> Self {
496        Ix1(0)
497    }
498
499    #[inline(always)]
500    fn min_stride_axis(&self, _: &Self) -> Axis {
501        Axis(0)
502    }
503
504    #[inline(always)]
505    fn max_stride_axis(&self, _: &Self) -> Axis {
506        Axis(0)
507    }
508
509    #[inline]
510    fn first_index(&self) -> Option<Self> {
511        if get!(self, 0) != 0 {
512            Some(Ix1(0))
513        } else {
514            None
515        }
516    }
517
518    /// Self is an index, return the stride offset
519    #[inline(always)]
520    fn stride_offset(index: &Self, stride: &Self) -> isize {
521        stride_offset(get!(index, 0), get!(stride, 0))
522    }
523
524    /// Return stride offset for this dimension and index.
525    #[inline]
526    fn stride_offset_checked(&self, stride: &Self, index: &Self) -> Option<isize> {
527        if get!(index, 0) < get!(self, 0) {
528            Some(stride_offset(get!(index, 0), get!(stride, 0)))
529        } else {
530            None
531        }
532    }
533    impl_insert_axis_array!(1);
534    #[inline]
535    fn try_remove_axis(&self, axis: Axis) -> Self::Smaller {
536        self.remove_axis(axis)
537    }
538
539    fn from_dimension<D2: Dimension>(d: &D2) -> Option<Self> {
540        if 1 == d.ndim() {
541            Some(Ix1(d[0]))
542        } else {
543            None
544        }
545    }
546    private_impl! {}
547}
548
549impl Dimension for Dim<[Ix; 2]> {
550    const NDIM: Option<usize> = Some(2);
551    type Pattern = (Ix, Ix);
552    type Smaller = Ix1;
553    type Larger = Ix3;
554    #[inline]
555    fn ndim(&self) -> usize {
556        2
557    }
558    #[inline]
559    fn into_pattern(self) -> Self::Pattern {
560        self.ix().convert()
561    }
562    #[inline]
563    fn slice(&self) -> &[Ix] {
564        self.ix()
565    }
566    #[inline]
567    fn slice_mut(&mut self) -> &mut [Ix] {
568        self.ixm()
569    }
570    #[inline]
571    fn zeros(ndim: usize) -> Self {
572        assert_eq!(ndim, 2);
573        Self::default()
574    }
575    #[inline]
576    fn next_for(&self, index: Self) -> Option<Self> {
577        let mut i = get!(&index, 0);
578        let mut j = get!(&index, 1);
579        let imax = get!(self, 0);
580        let jmax = get!(self, 1);
581        j += 1;
582        if j >= jmax {
583            j = 0;
584            i += 1;
585            if i >= imax {
586                return None;
587            }
588        }
589        Some(Ix2(i, j))
590    }
591
592    #[inline]
593    fn equal(&self, rhs: &Self) -> bool {
594        get!(self, 0) == get!(rhs, 0) && get!(self, 1) == get!(rhs, 1)
595    }
596
597    #[inline]
598    fn size(&self) -> usize {
599        get!(self, 0) * get!(self, 1)
600    }
601
602    #[inline]
603    fn size_checked(&self) -> Option<usize> {
604        let m = get!(self, 0);
605        let n = get!(self, 1);
606        (m as usize).checked_mul(n as usize)
607    }
608
609    #[inline]
610    fn last_elem(&self) -> usize {
611        get!(self, 1)
612    }
613
614    #[inline]
615    fn set_last_elem(&mut self, i: usize) {
616        getm!(self, 1) = i;
617    }
618
619    #[inline]
620    fn default_strides(&self) -> Self {
621        let m = get!(self, 0);
622        let n = get!(self, 1);
623        if m == 0 || n == 0 {
624            Ix2(0, 0)
625        } else {
626            Ix2(n, 1)
627        }
628    }
629    #[inline]
630    fn fortran_strides(&self) -> Self {
631        let m = get!(self, 0);
632        let n = get!(self, 1);
633        if m == 0 || n == 0 {
634            Ix2(0, 0)
635        } else {
636            Ix2(1, m)
637        }
638    }
639
640    #[inline]
641    fn _fastest_varying_stride_order(&self) -> Self {
642        if (get!(self, 0) as Ixs).abs() <= (get!(self, 1) as Ixs).abs() {
643            Ix2(0, 1)
644        } else {
645            Ix2(1, 0)
646        }
647    }
648
649    #[inline]
650    fn min_stride_axis(&self, strides: &Self) -> Axis {
651        let s = get!(strides, 0) as Ixs;
652        let t = get!(strides, 1) as Ixs;
653        if s.abs() < t.abs() {
654            Axis(0)
655        } else {
656            Axis(1)
657        }
658    }
659
660    #[inline]
661    fn first_index(&self) -> Option<Self> {
662        let m = get!(self, 0);
663        let n = get!(self, 1);
664        if m != 0 && n != 0 {
665            Some(Ix2(0, 0))
666        } else {
667            None
668        }
669    }
670
671    /// Self is an index, return the stride offset
672    #[inline(always)]
673    fn stride_offset(index: &Self, strides: &Self) -> isize {
674        let i = get!(index, 0);
675        let j = get!(index, 1);
676        let s = get!(strides, 0);
677        let t = get!(strides, 1);
678        stride_offset(i, s) + stride_offset(j, t)
679    }
680
681    /// Return stride offset for this dimension and index.
682    #[inline]
683    fn stride_offset_checked(&self, strides: &Self, index: &Self) -> Option<isize> {
684        let m = get!(self, 0);
685        let n = get!(self, 1);
686        let i = get!(index, 0);
687        let j = get!(index, 1);
688        let s = get!(strides, 0);
689        let t = get!(strides, 1);
690        if i < m && j < n {
691            Some(stride_offset(i, s) + stride_offset(j, t))
692        } else {
693            None
694        }
695    }
696    impl_insert_axis_array!(2);
697    #[inline]
698    fn try_remove_axis(&self, axis: Axis) -> Self::Smaller {
699        self.remove_axis(axis)
700    }
701    private_impl! {}
702}
703
704impl Dimension for Dim<[Ix; 3]> {
705    const NDIM: Option<usize> = Some(3);
706    type Pattern = (Ix, Ix, Ix);
707    type Smaller = Ix2;
708    type Larger = Ix4;
709    #[inline]
710    fn ndim(&self) -> usize {
711        3
712    }
713    #[inline]
714    fn into_pattern(self) -> Self::Pattern {
715        self.ix().convert()
716    }
717    #[inline]
718    fn slice(&self) -> &[Ix] {
719        self.ix()
720    }
721    #[inline]
722    fn slice_mut(&mut self) -> &mut [Ix] {
723        self.ixm()
724    }
725
726    #[inline]
727    fn size(&self) -> usize {
728        let m = get!(self, 0);
729        let n = get!(self, 1);
730        let o = get!(self, 2);
731        m as usize * n as usize * o as usize
732    }
733
734    #[inline]
735    fn zeros(ndim: usize) -> Self {
736        assert_eq!(ndim, 3);
737        Self::default()
738    }
739
740    #[inline]
741    fn next_for(&self, index: Self) -> Option<Self> {
742        let mut i = get!(&index, 0);
743        let mut j = get!(&index, 1);
744        let mut k = get!(&index, 2);
745        let imax = get!(self, 0);
746        let jmax = get!(self, 1);
747        let kmax = get!(self, 2);
748        k += 1;
749        if k == kmax {
750            k = 0;
751            j += 1;
752            if j == jmax {
753                j = 0;
754                i += 1;
755                if i == imax {
756                    return None;
757                }
758            }
759        }
760        Some(Ix3(i, j, k))
761    }
762
763    /// Self is an index, return the stride offset
764    #[inline]
765    fn stride_offset(index: &Self, strides: &Self) -> isize {
766        let i = get!(index, 0);
767        let j = get!(index, 1);
768        let k = get!(index, 2);
769        let s = get!(strides, 0);
770        let t = get!(strides, 1);
771        let u = get!(strides, 2);
772        stride_offset(i, s) + stride_offset(j, t) + stride_offset(k, u)
773    }
774
775    /// Return stride offset for this dimension and index.
776    #[inline]
777    fn stride_offset_checked(&self, strides: &Self, index: &Self) -> Option<isize> {
778        let m = get!(self, 0);
779        let n = get!(self, 1);
780        let l = get!(self, 2);
781        let i = get!(index, 0);
782        let j = get!(index, 1);
783        let k = get!(index, 2);
784        let s = get!(strides, 0);
785        let t = get!(strides, 1);
786        let u = get!(strides, 2);
787        if i < m && j < n && k < l {
788            Some(stride_offset(i, s) + stride_offset(j, t) + stride_offset(k, u))
789        } else {
790            None
791        }
792    }
793
794    #[inline]
795    fn _fastest_varying_stride_order(&self) -> Self {
796        let mut stride = *self;
797        let mut order = Ix3(0, 1, 2);
798        macro_rules! swap {
799            ($stride:expr, $order:expr, $x:expr, $y:expr) => {
800                if ($stride[$x] as isize).abs() > ($stride[$y] as isize).abs() {
801                    $stride.swap($x, $y);
802                    $order.ixm().swap($x, $y);
803                }
804            };
805        }
806        {
807            // stable sorting network for 3 elements
808            let strides = stride.slice_mut();
809            swap![strides, order, 1, 2];
810            swap![strides, order, 0, 1];
811            swap![strides, order, 1, 2];
812        }
813        order
814    }
815    impl_insert_axis_array!(3);
816    #[inline]
817    fn try_remove_axis(&self, axis: Axis) -> Self::Smaller {
818        self.remove_axis(axis)
819    }
820    private_impl! {}
821}
822
823macro_rules! large_dim {
824    ($n:expr, $name:ident, $pattern:ty, $larger:ty, { $($insert_axis:tt)* }) => (
825        impl Dimension for Dim<[Ix; $n]> {
826            const NDIM: Option<usize> = Some($n);
827            type Pattern = $pattern;
828            type Smaller = Dim<[Ix; $n - 1]>;
829            type Larger = $larger;
830            #[inline]
831            fn ndim(&self) -> usize { $n }
832            #[inline]
833            fn into_pattern(self) -> Self::Pattern {
834                self.ix().convert()
835            }
836            #[inline]
837            fn slice(&self) -> &[Ix] { self.ix() }
838            #[inline]
839            fn slice_mut(&mut self) -> &mut [Ix] { self.ixm() }
840            #[inline]
841            fn zeros(ndim: usize) -> Self {
842                assert_eq!(ndim, $n);
843                Self::default()
844            }
845            $($insert_axis)*
846            #[inline]
847            fn try_remove_axis(&self, axis: Axis) -> Self::Smaller {
848                self.remove_axis(axis)
849            }
850            private_impl!{}
851        }
852    )
853}
854
855large_dim!(4, Ix4, (Ix, Ix, Ix, Ix), Ix5, {
856    impl_insert_axis_array!(4);
857});
858large_dim!(5, Ix5, (Ix, Ix, Ix, Ix, Ix), Ix6, {
859    impl_insert_axis_array!(5);
860});
861large_dim!(6, Ix6, (Ix, Ix, Ix, Ix, Ix, Ix), IxDyn, {
862    fn insert_axis(&self, axis: Axis) -> Self::Larger {
863        debug_assert!(axis.index() <= self.ndim());
864        let mut out = Vec::with_capacity(self.ndim() + 1);
865        out.extend_from_slice(&self.slice()[0..axis.index()]);
866        out.push(1);
867        out.extend_from_slice(&self.slice()[axis.index()..self.ndim()]);
868        Dim(out)
869    }
870});
871
872/// IxDyn is a "dynamic" index, pretty hard to use when indexing,
873/// and memory wasteful, but it allows an arbitrary and dynamic number of axes.
874impl Dimension for IxDyn {
875    const NDIM: Option<usize> = None;
876    type Pattern = Self;
877    type Smaller = Self;
878    type Larger = Self;
879    #[inline]
880    fn ndim(&self) -> usize {
881        self.ix().len()
882    }
883    #[inline]
884    fn slice(&self) -> &[Ix] {
885        self.ix()
886    }
887    #[inline]
888    fn slice_mut(&mut self) -> &mut [Ix] {
889        self.ixm()
890    }
891    #[inline]
892    fn into_pattern(self) -> Self::Pattern {
893        self
894    }
895
896    #[inline]
897    fn zeros(ndim: usize) -> Self {
898        IxDyn::zeros(ndim)
899    }
900
901    #[inline]
902    fn insert_axis(&self, axis: Axis) -> Self::Larger {
903        debug_assert!(axis.index() <= self.ndim());
904        Dim::new(self.ix().insert(axis.index()))
905    }
906
907    #[inline]
908    fn try_remove_axis(&self, axis: Axis) -> Self::Smaller {
909        if self.ndim() > 0 {
910            self.remove_axis(axis)
911        } else {
912            self.clone()
913        }
914    }
915
916    fn from_dimension<D2: Dimension>(d: &D2) -> Option<Self> {
917        Some(IxDyn(d.slice()))
918    }
919
920    fn into_dyn(self) -> IxDyn {
921        self
922    }
923
924    private_impl! {}
925}
926
927impl Index<usize> for Dim<IxDynImpl> {
928    type Output = <IxDynImpl as Index<usize>>::Output;
929    fn index(&self, index: usize) -> &Self::Output {
930        &self.ix()[index]
931    }
932}
933
934impl IndexMut<usize> for Dim<IxDynImpl> {
935    fn index_mut(&mut self, index: usize) -> &mut Self::Output {
936        &mut self.ixm()[index]
937    }
938}