ndarray/
arraytraits.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::hash;
10use std::iter::FromIterator;
11use std::iter::IntoIterator;
12use std::mem;
13use std::ops::{Index, IndexMut};
14use alloc::vec::Vec;
15
16use crate::imp_prelude::*;
17use crate::iter::{Iter, IterMut};
18use crate::NdIndex;
19
20use crate::numeric_util;
21use crate::{FoldWhile, Zip};
22
23#[cold]
24#[inline(never)]
25pub(crate) fn array_out_of_bounds() -> ! {
26    panic!("ndarray: index out of bounds");
27}
28
29#[inline(always)]
30pub fn debug_bounds_check<S, D, I>(_a: &ArrayBase<S, D>, _index: &I)
31where
32    D: Dimension,
33    I: NdIndex<D>,
34    S: Data,
35{
36    debug_bounds_check!(_a, *_index);
37}
38
39/// Access the element at **index**.
40///
41/// **Panics** if index is out of bounds.
42impl<S, D, I> Index<I> for ArrayBase<S, D>
43where
44    D: Dimension,
45    I: NdIndex<D>,
46    S: Data,
47{
48    type Output = S::Elem;
49    #[inline]
50    fn index(&self, index: I) -> &S::Elem {
51        debug_bounds_check!(self, index);
52        unsafe {
53            &*self.ptr.as_ptr().offset(
54                index
55                    .index_checked(&self.dim, &self.strides)
56                    .unwrap_or_else(|| array_out_of_bounds()),
57            )
58        }
59    }
60}
61
62/// Access the element at **index** mutably.
63///
64/// **Panics** if index is out of bounds.
65impl<S, D, I> IndexMut<I> for ArrayBase<S, D>
66where
67    D: Dimension,
68    I: NdIndex<D>,
69    S: DataMut,
70{
71    #[inline]
72    fn index_mut(&mut self, index: I) -> &mut S::Elem {
73        debug_bounds_check!(self, index);
74        unsafe {
75            &mut *self.as_mut_ptr().offset(
76                index
77                    .index_checked(&self.dim, &self.strides)
78                    .unwrap_or_else(|| array_out_of_bounds()),
79            )
80        }
81    }
82}
83
84/// Return `true` if the array shapes and all elements of `self` and
85/// `rhs` are equal. Return `false` otherwise.
86impl<A, B, S, S2, D> PartialEq<ArrayBase<S2, D>> for ArrayBase<S, D>
87where
88    A: PartialEq<B>,
89    S: Data<Elem = A>,
90    S2: Data<Elem = B>,
91    D: Dimension,
92{
93    fn eq(&self, rhs: &ArrayBase<S2, D>) -> bool {
94        if self.shape() != rhs.shape() {
95            return false;
96        }
97        if let Some(self_s) = self.as_slice() {
98            if let Some(rhs_s) = rhs.as_slice() {
99                return numeric_util::unrolled_eq(self_s, rhs_s);
100            }
101        }
102        Zip::from(self)
103            .and(rhs)
104            .fold_while(true, |_, a, b| {
105                if a != b {
106                    FoldWhile::Done(false)
107                } else {
108                    FoldWhile::Continue(true)
109                }
110            })
111            .into_inner()
112    }
113}
114
115/// Return `true` if the array shapes and all elements of `self` and
116/// `rhs` are equal. Return `false` otherwise.
117impl<'a, A, B, S, S2, D> PartialEq<&'a ArrayBase<S2, D>> for ArrayBase<S, D>
118where
119    A: PartialEq<B>,
120    S: Data<Elem = A>,
121    S2: Data<Elem = B>,
122    D: Dimension,
123{
124    fn eq(&self, rhs: &&ArrayBase<S2, D>) -> bool {
125        *self == **rhs
126    }
127}
128
129/// Return `true` if the array shapes and all elements of `self` and
130/// `rhs` are equal. Return `false` otherwise.
131impl<'a, A, B, S, S2, D> PartialEq<ArrayBase<S2, D>> for &'a ArrayBase<S, D>
132where
133    A: PartialEq<B>,
134    S: Data<Elem = A>,
135    S2: Data<Elem = B>,
136    D: Dimension,
137{
138    fn eq(&self, rhs: &ArrayBase<S2, D>) -> bool {
139        **self == *rhs
140    }
141}
142
143impl<S, D> Eq for ArrayBase<S, D>
144where
145    D: Dimension,
146    S: Data,
147    S::Elem: Eq,
148{
149}
150
151impl<A, S> From<Vec<A>> for ArrayBase<S, Ix1>
152where
153    S: DataOwned<Elem = A>,
154{
155    /// Create a one-dimensional array from a vector (no copying needed).
156    ///
157    /// **Panics** if the length is greater than `isize::MAX`.
158    ///
159    /// ```rust
160    /// use ndarray::Array;
161    ///
162    /// let array = Array::from(vec![1., 2., 3., 4.]);
163    /// ```
164    fn from(v: Vec<A>) -> Self {
165        Self::from_vec(v)
166    }
167}
168
169impl<A, S> FromIterator<A> for ArrayBase<S, Ix1>
170where
171    S: DataOwned<Elem = A>,
172{
173    /// Create a one-dimensional array from an iterable.
174    ///
175    /// **Panics** if the length is greater than `isize::MAX`.
176    ///
177    /// ```rust
178    /// use ndarray::{Array, arr1};
179    /// use std::iter::FromIterator;
180    ///
181    /// // Either use `from_iter` directly or use `Iterator::collect`.
182    /// let array = Array::from_iter((0..5).map(|x| x * x));
183    /// assert!(array == arr1(&[0, 1, 4, 9, 16]))
184    /// ```
185    fn from_iter<I>(iterable: I) -> ArrayBase<S, Ix1>
186    where
187        I: IntoIterator<Item = A>,
188    {
189        Self::from_iter(iterable)
190    }
191}
192
193impl<'a, S, D> IntoIterator for &'a ArrayBase<S, D>
194where
195    D: Dimension,
196    S: Data,
197{
198    type Item = &'a S::Elem;
199    type IntoIter = Iter<'a, S::Elem, D>;
200
201    fn into_iter(self) -> Self::IntoIter {
202        self.iter()
203    }
204}
205
206impl<'a, S, D> IntoIterator for &'a mut ArrayBase<S, D>
207where
208    D: Dimension,
209    S: DataMut,
210{
211    type Item = &'a mut S::Elem;
212    type IntoIter = IterMut<'a, S::Elem, D>;
213
214    fn into_iter(self) -> Self::IntoIter {
215        self.iter_mut()
216    }
217}
218
219impl<'a, A, D> IntoIterator for ArrayView<'a, A, D>
220where
221    D: Dimension,
222{
223    type Item = &'a A;
224    type IntoIter = Iter<'a, A, D>;
225
226    fn into_iter(self) -> Self::IntoIter {
227        self.into_iter_()
228    }
229}
230
231impl<'a, A, D> IntoIterator for ArrayViewMut<'a, A, D>
232where
233    D: Dimension,
234{
235    type Item = &'a mut A;
236    type IntoIter = IterMut<'a, A, D>;
237
238    fn into_iter(self) -> Self::IntoIter {
239        self.into_iter_()
240    }
241}
242
243impl<'a, S, D> hash::Hash for ArrayBase<S, D>
244where
245    D: Dimension,
246    S: Data,
247    S::Elem: hash::Hash,
248{
249    // Note: elements are hashed in the logical order
250    fn hash<H: hash::Hasher>(&self, state: &mut H) {
251        self.shape().hash(state);
252        if let Some(self_s) = self.as_slice() {
253            hash::Hash::hash_slice(self_s, state);
254        } else {
255            for row in self.inner_rows() {
256                if let Some(row_s) = row.as_slice() {
257                    hash::Hash::hash_slice(row_s, state);
258                } else {
259                    for elt in row {
260                        elt.hash(state)
261                    }
262                }
263            }
264        }
265    }
266}
267
268// NOTE: ArrayBase keeps an internal raw pointer that always
269// points into the storage. This is Sync & Send as long as we
270// follow the usual inherited mutability rules, as we do with
271// Vec, &[] and &mut []
272
273/// `ArrayBase` is `Sync` when the storage type is.
274unsafe impl<S, D> Sync for ArrayBase<S, D>
275where
276    S: Sync + Data,
277    D: Sync,
278{
279}
280
281/// `ArrayBase` is `Send` when the storage type is.
282unsafe impl<S, D> Send for ArrayBase<S, D>
283where
284    S: Send + Data,
285    D: Send,
286{
287}
288
289#[cfg(any(feature = "serde"))]
290// Use version number so we can add a packed format later.
291pub const ARRAY_FORMAT_VERSION: u8 = 1u8;
292
293// use "raw" form instead of type aliases here so that they show up in docs
294/// Implementation of `ArrayView::from(&S)` where `S` is a slice or slicable.
295impl<'a, A, Slice: ?Sized> From<&'a Slice> for ArrayView<'a, A, Ix1>
296where
297    Slice: AsRef<[A]>,
298{
299    /// Create a one-dimensional read-only array view of the data in `slice`.
300    ///
301    /// **Panics** if the slice length is greater than `isize::MAX`.
302    fn from(slice: &'a Slice) -> Self {
303        let xs = slice.as_ref();
304        if mem::size_of::<A>() == 0 {
305            assert!(
306                xs.len() <= ::std::isize::MAX as usize,
307                "Slice length must fit in `isize`.",
308            );
309        }
310        unsafe { Self::from_shape_ptr(xs.len(), xs.as_ptr()) }
311    }
312}
313
314/// Implementation of `ArrayView::from(&A)` where `A` is an array.
315impl<'a, A, S, D> From<&'a ArrayBase<S, D>> for ArrayView<'a, A, D>
316where
317    S: Data<Elem = A>,
318    D: Dimension,
319{
320    /// Create a read-only array view of the array.
321    fn from(array: &'a ArrayBase<S, D>) -> Self {
322        array.view()
323    }
324}
325
326/// Implementation of `ArrayViewMut::from(&mut S)` where `S` is a slice or slicable.
327impl<'a, A, Slice: ?Sized> From<&'a mut Slice> for ArrayViewMut<'a, A, Ix1>
328where
329    Slice: AsMut<[A]>,
330{
331    /// Create a one-dimensional read-write array view of the data in `slice`.
332    ///
333    /// **Panics** if the slice length is greater than `isize::MAX`.
334    fn from(slice: &'a mut Slice) -> Self {
335        let xs = slice.as_mut();
336        if mem::size_of::<A>() == 0 {
337            assert!(
338                xs.len() <= ::std::isize::MAX as usize,
339                "Slice length must fit in `isize`.",
340            );
341        }
342        unsafe { Self::from_shape_ptr(xs.len(), xs.as_mut_ptr()) }
343    }
344}
345
346/// Implementation of `ArrayViewMut::from(&mut A)` where `A` is an array.
347impl<'a, A, S, D> From<&'a mut ArrayBase<S, D>> for ArrayViewMut<'a, A, D>
348where
349    S: DataMut<Elem = A>,
350    D: Dimension,
351{
352    /// Create a read-write array view of the array.
353    fn from(array: &'a mut ArrayBase<S, D>) -> Self {
354        array.view_mut()
355    }
356}
357
358/// Argument conversion into an array view
359///
360/// The trait is parameterized over `A`, the element type, and `D`, the
361/// dimensionality of the array. `D` defaults to one-dimensional.
362///
363/// Use `.into()` to do the conversion.
364///
365/// ```
366/// use ndarray::AsArray;
367///
368/// fn sum<'a, V: AsArray<'a, f64>>(data: V) -> f64 {
369///     let array_view = data.into();
370///     array_view.sum()
371/// }
372///
373/// assert_eq!(
374///     sum(&[1., 2., 3.]),
375///     6.
376/// );
377///
378/// ```
379pub trait AsArray<'a, A: 'a, D = Ix1>: Into<ArrayView<'a, A, D>>
380where
381    D: Dimension,
382{
383}
384impl<'a, A: 'a, D, T> AsArray<'a, A, D> for T
385where
386    T: Into<ArrayView<'a, A, D>>,
387    D: Dimension,
388{
389}
390
391/// Create an owned array with a default state.
392///
393/// The array is created with dimension `D::default()`, which results
394/// in for example dimensions `0` and `(0, 0)` with zero elements for the
395/// one-dimensional and two-dimensional cases respectively.
396///
397/// The default dimension for `IxDyn` is `IxDyn(&[0])` (array has zero
398/// elements). And the default for the dimension `()` is `()` (array has
399/// one element).
400///
401/// Since arrays cannot grow, the intention is to use the default value as
402/// placeholder.
403impl<A, S, D> Default for ArrayBase<S, D>
404where
405    S: DataOwned<Elem = A>,
406    D: Dimension,
407    A: Default,
408{
409    // NOTE: We can implement Default for non-zero dimensional array views by
410    // using an empty slice, however we need a trait for nonzero Dimension.
411    fn default() -> Self {
412        ArrayBase::default(D::default())
413    }
414}