ndarray/impl_views/
indexing.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 crate::arraytraits::array_out_of_bounds;
10use crate::imp_prelude::*;
11use crate::NdIndex;
12
13/// Extra indexing methods for array views
14///
15/// These methods are very similar to regular indexing or calling of the
16/// `get`/`get_mut` methods that we can use on any array or array view. The
17/// difference here is in the length of lifetime in the resulting reference.
18///
19/// **Note** that the `ArrayView` (read-only) and `ArrayViewMut` (read-write) differ
20/// in how they are allowed implement this trait -- `ArrayView`'s implementation
21/// is usual. If you put in a `ArrayView<'a, T, D>` here, you get references
22/// `&'a T` out.
23///
24/// For `ArrayViewMut` to obey the borrowing rules we have to consume the
25/// view if we call any of these methods. (The equivalent of reborrow is
26/// `.view_mut()` for read-write array views, but if you can use that,
27/// then the regular indexing / `get_mut` should suffice, too.)
28///
29/// ```
30/// use ndarray::IndexLonger;
31/// use ndarray::ArrayView;
32///
33/// let data = [0.; 256];
34/// let long_life_ref = {
35///     // make a 16 × 16 array view
36///     let view = ArrayView::from(&data[..]).into_shape_with_order((16, 16)).unwrap();
37///
38///     // index the view and with `IndexLonger`.
39///     // Note here that we get a reference with a life that is derived from
40///     // `data`, the base data, instead of being derived from the view
41///     IndexLonger::index(&view, [0, 1])
42/// };
43///
44/// // view goes out of scope
45///
46/// assert_eq!(long_life_ref, &0.);
47///
48/// ```
49pub trait IndexLonger<I>
50{
51    /// The type of the reference to the element that is produced, including
52    /// its lifetime.
53    type Output;
54    /// Get a reference of a element through the view.
55    ///
56    /// This method is like `Index::index` but with a longer lifetime (matching
57    /// the array view); which we can only do for the array view and not in the
58    /// `Index` trait.
59    ///
60    /// See also [the `get` method][1] which works for all arrays and array
61    /// views.
62    ///
63    /// [1]: ArrayBase::get
64    ///
65    /// **Panics** if index is out of bounds.
66    #[track_caller]
67    fn index(self, index: I) -> Self::Output;
68
69    /// Get a reference of a element through the view.
70    ///
71    /// This method is like `ArrayBase::get` but with a longer lifetime (matching
72    /// the array view); which we can only do for the array view and not in the
73    /// `Index` trait.
74    ///
75    /// See also [the `get` method][1] (and [`get_mut`][2]) which works for all arrays and array
76    /// views.
77    ///
78    /// [1]: ArrayBase::get
79    /// [2]: ArrayBase::get_mut
80    ///
81    /// **Panics** if index is out of bounds.
82    #[track_caller]
83    fn get(self, index: I) -> Option<Self::Output>;
84
85    /// Get a reference of a element through the view without boundary check
86    ///
87    /// This method is like `elem` with a longer lifetime (matching the array
88    /// view); which we can't do for general arrays.
89    ///
90    /// See also [the `uget` method][1] which works for all arrays and array
91    /// views.
92    ///
93    /// [1]: ArrayBase::uget
94    ///
95    /// **Note:** only unchecked for non-debug builds of ndarray.
96    ///
97    /// # Safety
98    ///
99    /// The caller must ensure that the index is in-bounds.
100    unsafe fn uget(self, index: I) -> Self::Output;
101}
102
103impl<'a, 'b, I, A, D> IndexLonger<I> for &'b ArrayView<'a, A, D>
104where
105    I: NdIndex<D>,
106    D: Dimension,
107{
108    type Output = &'a A;
109
110    /// Get a reference of a element through the view.
111    ///
112    /// This method is like `Index::index` but with a longer lifetime (matching
113    /// the array view); which we can only do for the array view and not in the
114    /// `Index` trait.
115    ///
116    /// See also [the `get` method][1] which works for all arrays and array
117    /// views.
118    ///
119    /// [1]: ArrayBase::get
120    ///
121    /// **Panics** if index is out of bounds.
122    #[track_caller]
123    fn index(self, index: I) -> &'a A
124    {
125        debug_bounds_check!(self, index);
126        unsafe { &*self.get_ptr(index).unwrap_or_else(|| array_out_of_bounds()) }
127    }
128
129    fn get(self, index: I) -> Option<&'a A>
130    {
131        unsafe { self.get_ptr(index).map(|ptr| &*ptr) }
132    }
133
134    /// Get a reference of a element through the view without boundary check
135    ///
136    /// This method is like `elem` with a longer lifetime (matching the array
137    /// view); which we can't do for general arrays.
138    ///
139    /// See also [the `uget` method][1] which works for all arrays and array
140    /// views.
141    ///
142    /// [1]: ArrayBase::uget
143    ///
144    /// **Note:** only unchecked for non-debug builds of ndarray.
145    unsafe fn uget(self, index: I) -> &'a A
146    {
147        debug_bounds_check!(self, index);
148        &*self.as_ptr().offset(index.index_unchecked(&self.strides))
149    }
150}
151
152impl<'a, I, A, D> IndexLonger<I> for ArrayViewMut<'a, A, D>
153where
154    I: NdIndex<D>,
155    D: Dimension,
156{
157    type Output = &'a mut A;
158
159    /// Convert a mutable array view to a mutable reference of a element.
160    ///
161    /// This method is like `IndexMut::index_mut` but with a longer lifetime
162    /// (matching the array view); which we can only do for the array view and
163    /// not in the `Index` trait.
164    ///
165    /// See also [the `get_mut` method][1] which works for all arrays and array
166    /// views.
167    ///
168    /// [1]: ArrayBase::get_mut
169    ///
170    /// **Panics** if index is out of bounds.
171    #[track_caller]
172    fn index(mut self, index: I) -> &'a mut A
173    {
174        debug_bounds_check!(self, index);
175        unsafe {
176            match self.get_mut_ptr(index) {
177                Some(ptr) => &mut *ptr,
178                None => array_out_of_bounds(),
179            }
180        }
181    }
182
183    /// Convert a mutable array view to a mutable reference of a element, with
184    /// checked access.
185    ///
186    /// See also [the `get_mut` method][1] which works for all arrays and array
187    /// views.
188    ///
189    /// [1]: ArrayBase::get_mut
190    ///
191    fn get(mut self, index: I) -> Option<&'a mut A>
192    {
193        debug_bounds_check!(self, index);
194        unsafe {
195            match self.get_mut_ptr(index) {
196                Some(ptr) => Some(&mut *ptr),
197                None => None,
198            }
199        }
200    }
201
202    /// Convert a mutable array view to a mutable reference of a element without
203    /// boundary check.
204    ///
205    /// See also [the `uget_mut` method][1] which works for all arrays and array
206    /// views.
207    ///
208    /// [1]: ArrayBase::uget_mut
209    ///
210    /// **Note:** only unchecked for non-debug builds of ndarray.
211    unsafe fn uget(mut self, index: I) -> &'a mut A
212    {
213        debug_bounds_check!(self, index);
214        &mut *self
215            .as_mut_ptr()
216            .offset(index.index_unchecked(&self.strides))
217    }
218}