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