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        fn insert_axis(&self, axis: Axis) -> Self::Larger {
383            debug_assert!(axis.index() <= $n);
384            let mut out = [1; $n + 1];
385            out[0..axis.index()].copy_from_slice(&self.slice()[0..axis.index()]);
386            out[axis.index()+1..=$n].copy_from_slice(&self.slice()[axis.index()..$n]);
387            Dim(out)
388        }
389    );
390);
391
392impl Dimension for Dim<[Ix; 0]> {
393    const NDIM: Option<usize> = Some(0);
394    type Pattern = ();
395    type Smaller = Self;
396    type Larger = Ix1;
397    // empty product is 1 -> size is 1
398    #[inline]
399    fn ndim(&self) -> usize {
400        0
401    }
402    #[inline]
403    fn slice(&self) -> &[Ix] {
404        &[]
405    }
406    #[inline]
407    fn slice_mut(&mut self) -> &mut [Ix] {
408        &mut []
409    }
410    #[inline]
411    fn _fastest_varying_stride_order(&self) -> Self {
412        Ix0()
413    }
414    #[inline]
415    fn into_pattern(self) -> Self::Pattern {}
416    #[inline]
417    fn zeros(ndim: usize) -> Self {
418        assert_eq!(ndim, 0);
419        Self::default()
420    }
421    #[inline]
422    fn next_for(&self, _index: Self) -> Option<Self> {
423        None
424    }
425    #[inline]
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    #[inline]
534    impl_insert_axis_array!(1);
535    #[inline]
536    fn try_remove_axis(&self, axis: Axis) -> Self::Smaller {
537        self.remove_axis(axis)
538    }
539
540    fn from_dimension<D2: Dimension>(d: &D2) -> Option<Self> {
541        if 1 == d.ndim() {
542            Some(Ix1(d[0]))
543        } else {
544            None
545        }
546    }
547    private_impl! {}
548}
549
550impl Dimension for Dim<[Ix; 2]> {
551    const NDIM: Option<usize> = Some(2);
552    type Pattern = (Ix, Ix);
553    type Smaller = Ix1;
554    type Larger = Ix3;
555    #[inline]
556    fn ndim(&self) -> usize {
557        2
558    }
559    #[inline]
560    fn into_pattern(self) -> Self::Pattern {
561        self.ix().convert()
562    }
563    #[inline]
564    fn slice(&self) -> &[Ix] {
565        self.ix()
566    }
567    #[inline]
568    fn slice_mut(&mut self) -> &mut [Ix] {
569        self.ixm()
570    }
571    #[inline]
572    fn zeros(ndim: usize) -> Self {
573        assert_eq!(ndim, 2);
574        Self::default()
575    }
576    #[inline]
577    fn next_for(&self, index: Self) -> Option<Self> {
578        let mut i = get!(&index, 0);
579        let mut j = get!(&index, 1);
580        let imax = get!(self, 0);
581        let jmax = get!(self, 1);
582        j += 1;
583        if j >= jmax {
584            j = 0;
585            i += 1;
586            if i >= imax {
587                return None;
588            }
589        }
590        Some(Ix2(i, j))
591    }
592
593    #[inline]
594    fn equal(&self, rhs: &Self) -> bool {
595        get!(self, 0) == get!(rhs, 0) && get!(self, 1) == get!(rhs, 1)
596    }
597
598    #[inline]
599    fn size(&self) -> usize {
600        get!(self, 0) * get!(self, 1)
601    }
602
603    #[inline]
604    fn size_checked(&self) -> Option<usize> {
605        let m = get!(self, 0);
606        let n = get!(self, 1);
607        (m as usize).checked_mul(n as usize)
608    }
609
610    #[inline]
611    fn last_elem(&self) -> usize {
612        get!(self, 1)
613    }
614
615    #[inline]
616    fn set_last_elem(&mut self, i: usize) {
617        getm!(self, 1) = i;
618    }
619
620    #[inline]
621    fn default_strides(&self) -> Self {
622        let m = get!(self, 0);
623        let n = get!(self, 1);
624        if m == 0 || n == 0 {
625            Ix2(0, 0)
626        } else {
627            Ix2(n, 1)
628        }
629    }
630    #[inline]
631    fn fortran_strides(&self) -> Self {
632        let m = get!(self, 0);
633        let n = get!(self, 1);
634        if m == 0 || n == 0 {
635            Ix2(0, 0)
636        } else {
637            Ix2(1, m)
638        }
639    }
640
641    #[inline]
642    fn _fastest_varying_stride_order(&self) -> Self {
643        if (get!(self, 0) as Ixs).abs() <= (get!(self, 1) as Ixs).abs() {
644            Ix2(0, 1)
645        } else {
646            Ix2(1, 0)
647        }
648    }
649
650    #[inline]
651    fn min_stride_axis(&self, strides: &Self) -> Axis {
652        let s = get!(strides, 0) as Ixs;
653        let t = get!(strides, 1) as Ixs;
654        if s.abs() < t.abs() {
655            Axis(0)
656        } else {
657            Axis(1)
658        }
659    }
660
661    #[inline]
662    fn first_index(&self) -> Option<Self> {
663        let m = get!(self, 0);
664        let n = get!(self, 1);
665        if m != 0 && n != 0 {
666            Some(Ix2(0, 0))
667        } else {
668            None
669        }
670    }
671
672    /// Self is an index, return the stride offset
673    #[inline(always)]
674    fn stride_offset(index: &Self, strides: &Self) -> isize {
675        let i = get!(index, 0);
676        let j = get!(index, 1);
677        let s = get!(strides, 0);
678        let t = get!(strides, 1);
679        stride_offset(i, s) + stride_offset(j, t)
680    }
681
682    /// Return stride offset for this dimension and index.
683    #[inline]
684    fn stride_offset_checked(&self, strides: &Self, index: &Self) -> Option<isize> {
685        let m = get!(self, 0);
686        let n = get!(self, 1);
687        let i = get!(index, 0);
688        let j = get!(index, 1);
689        let s = get!(strides, 0);
690        let t = get!(strides, 1);
691        if i < m && j < n {
692            Some(stride_offset(i, s) + stride_offset(j, t))
693        } else {
694            None
695        }
696    }
697    #[inline]
698    impl_insert_axis_array!(2);
699    #[inline]
700    fn try_remove_axis(&self, axis: Axis) -> Self::Smaller {
701        self.remove_axis(axis)
702    }
703    private_impl! {}
704}
705
706impl Dimension for Dim<[Ix; 3]> {
707    const NDIM: Option<usize> = Some(3);
708    type Pattern = (Ix, Ix, Ix);
709    type Smaller = Ix2;
710    type Larger = Ix4;
711    #[inline]
712    fn ndim(&self) -> usize {
713        3
714    }
715    #[inline]
716    fn into_pattern(self) -> Self::Pattern {
717        self.ix().convert()
718    }
719    #[inline]
720    fn slice(&self) -> &[Ix] {
721        self.ix()
722    }
723    #[inline]
724    fn slice_mut(&mut self) -> &mut [Ix] {
725        self.ixm()
726    }
727
728    #[inline]
729    fn size(&self) -> usize {
730        let m = get!(self, 0);
731        let n = get!(self, 1);
732        let o = get!(self, 2);
733        m as usize * n as usize * o as usize
734    }
735
736    #[inline]
737    fn zeros(ndim: usize) -> Self {
738        assert_eq!(ndim, 3);
739        Self::default()
740    }
741
742    #[inline]
743    fn next_for(&self, index: Self) -> Option<Self> {
744        let mut i = get!(&index, 0);
745        let mut j = get!(&index, 1);
746        let mut k = get!(&index, 2);
747        let imax = get!(self, 0);
748        let jmax = get!(self, 1);
749        let kmax = get!(self, 2);
750        k += 1;
751        if k == kmax {
752            k = 0;
753            j += 1;
754            if j == jmax {
755                j = 0;
756                i += 1;
757                if i == imax {
758                    return None;
759                }
760            }
761        }
762        Some(Ix3(i, j, k))
763    }
764
765    /// Self is an index, return the stride offset
766    #[inline]
767    fn stride_offset(index: &Self, strides: &Self) -> isize {
768        let i = get!(index, 0);
769        let j = get!(index, 1);
770        let k = get!(index, 2);
771        let s = get!(strides, 0);
772        let t = get!(strides, 1);
773        let u = get!(strides, 2);
774        stride_offset(i, s) + stride_offset(j, t) + stride_offset(k, u)
775    }
776
777    /// Return stride offset for this dimension and index.
778    #[inline]
779    fn stride_offset_checked(&self, strides: &Self, index: &Self) -> Option<isize> {
780        let m = get!(self, 0);
781        let n = get!(self, 1);
782        let l = get!(self, 2);
783        let i = get!(index, 0);
784        let j = get!(index, 1);
785        let k = get!(index, 2);
786        let s = get!(strides, 0);
787        let t = get!(strides, 1);
788        let u = get!(strides, 2);
789        if i < m && j < n && k < l {
790            Some(stride_offset(i, s) + stride_offset(j, t) + stride_offset(k, u))
791        } else {
792            None
793        }
794    }
795
796    #[inline]
797    fn _fastest_varying_stride_order(&self) -> Self {
798        let mut stride = *self;
799        let mut order = Ix3(0, 1, 2);
800        macro_rules! swap {
801            ($stride:expr, $order:expr, $x:expr, $y:expr) => {
802                if ($stride[$x] as isize).abs() > ($stride[$y] as isize).abs() {
803                    $stride.swap($x, $y);
804                    $order.ixm().swap($x, $y);
805                }
806            };
807        }
808        {
809            // stable sorting network for 3 elements
810            let strides = stride.slice_mut();
811            swap![strides, order, 1, 2];
812            swap![strides, order, 0, 1];
813            swap![strides, order, 1, 2];
814        }
815        order
816    }
817    #[inline]
818    impl_insert_axis_array!(3);
819    #[inline]
820    fn try_remove_axis(&self, axis: Axis) -> Self::Smaller {
821        self.remove_axis(axis)
822    }
823    private_impl! {}
824}
825
826macro_rules! large_dim {
827    ($n:expr, $name:ident, $pattern:ty, $larger:ty, { $($insert_axis:tt)* }) => (
828        impl Dimension for Dim<[Ix; $n]> {
829            const NDIM: Option<usize> = Some($n);
830            type Pattern = $pattern;
831            type Smaller = Dim<[Ix; $n - 1]>;
832            type Larger = $larger;
833            #[inline]
834            fn ndim(&self) -> usize { $n }
835            #[inline]
836            fn into_pattern(self) -> Self::Pattern {
837                self.ix().convert()
838            }
839            #[inline]
840            fn slice(&self) -> &[Ix] { self.ix() }
841            #[inline]
842            fn slice_mut(&mut self) -> &mut [Ix] { self.ixm() }
843            #[inline]
844            fn zeros(ndim: usize) -> Self {
845                assert_eq!(ndim, $n);
846                Self::default()
847            }
848            #[inline]
849            $($insert_axis)*
850            #[inline]
851            fn try_remove_axis(&self, axis: Axis) -> Self::Smaller {
852                self.remove_axis(axis)
853            }
854            private_impl!{}
855        }
856    )
857}
858
859large_dim!(4, Ix4, (Ix, Ix, Ix, Ix), Ix5, {
860    impl_insert_axis_array!(4);
861});
862large_dim!(5, Ix5, (Ix, Ix, Ix, Ix, Ix), Ix6, {
863    impl_insert_axis_array!(5);
864});
865large_dim!(6, Ix6, (Ix, Ix, Ix, Ix, Ix, Ix), IxDyn, {
866    fn insert_axis(&self, axis: Axis) -> Self::Larger {
867        debug_assert!(axis.index() <= self.ndim());
868        let mut out = Vec::with_capacity(self.ndim() + 1);
869        out.extend_from_slice(&self.slice()[0..axis.index()]);
870        out.push(1);
871        out.extend_from_slice(&self.slice()[axis.index()..self.ndim()]);
872        Dim(out)
873    }
874});
875
876/// IxDyn is a "dynamic" index, pretty hard to use when indexing,
877/// and memory wasteful, but it allows an arbitrary and dynamic number of axes.
878impl Dimension for IxDyn {
879    const NDIM: Option<usize> = None;
880    type Pattern = Self;
881    type Smaller = Self;
882    type Larger = Self;
883    #[inline]
884    fn ndim(&self) -> usize {
885        self.ix().len()
886    }
887    #[inline]
888    fn slice(&self) -> &[Ix] {
889        self.ix()
890    }
891    #[inline]
892    fn slice_mut(&mut self) -> &mut [Ix] {
893        self.ixm()
894    }
895    #[inline]
896    fn into_pattern(self) -> Self::Pattern {
897        self
898    }
899
900    #[inline]
901    fn zeros(ndim: usize) -> Self {
902        IxDyn::zeros(ndim)
903    }
904
905    #[inline]
906    fn insert_axis(&self, axis: Axis) -> Self::Larger {
907        debug_assert!(axis.index() <= self.ndim());
908        Dim::new(self.ix().insert(axis.index()))
909    }
910
911    #[inline]
912    fn try_remove_axis(&self, axis: Axis) -> Self::Smaller {
913        if self.ndim() > 0 {
914            self.remove_axis(axis)
915        } else {
916            self.clone()
917        }
918    }
919
920    fn from_dimension<D2: Dimension>(d: &D2) -> Option<Self> {
921        Some(IxDyn(d.slice()))
922    }
923
924    fn into_dyn(self) -> IxDyn {
925        self
926    }
927
928    private_impl! {}
929}
930
931impl Index<usize> for Dim<IxDynImpl> {
932    type Output = <IxDynImpl as Index<usize>>::Output;
933    fn index(&self, index: usize) -> &Self::Output {
934        &self.ix()[index]
935    }
936}
937
938impl IndexMut<usize> for Dim<IxDynImpl> {
939    fn index_mut(&mut self, index: usize) -> &mut Self::Output {
940        &mut self.ixm()[index]
941    }
942}