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}