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((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 /// The type of the reference to the element that is produced, including
51 /// its lifetime.
52 type Output;
53 /// Get a reference of a element through the view.
54 ///
55 /// This method is like `Index::index` but with a longer lifetime (matching
56 /// the array view); which we can only do for the array view and not in the
57 /// `Index` trait.
58 ///
59 /// See also [the `get` method][1] which works for all arrays and array
60 /// views.
61 ///
62 /// [1]: ArrayBase::get
63 ///
64 /// **Panics** if index is out of bounds.
65 fn index(self, index: I) -> Self::Output;
66
67 /// Get a reference of a element through the view.
68 ///
69 /// This method is like `ArrayBase::get` but with a longer lifetime (matching
70 /// the array view); which we can only do for the array view and not in the
71 /// `Index` trait.
72 ///
73 /// See also [the `get` method][1] (and [`get_mut`][2]) which works for all arrays and array
74 /// views.
75 ///
76 /// [1]: ArrayBase::get
77 /// [2]: ArrayBase::get_mut
78 ///
79 /// **Panics** if index is out of bounds.
80 fn get(self, index: I) -> Option<Self::Output>;
81
82 /// Get a reference of a element through the view without boundary check
83 ///
84 /// This method is like `elem` with a longer lifetime (matching the array
85 /// view); which we can't do for general arrays.
86 ///
87 /// See also [the `uget` method][1] which works for all arrays and array
88 /// views.
89 ///
90 /// [1]: ArrayBase::uget
91 ///
92 /// **Note:** only unchecked for non-debug builds of ndarray.
93 ///
94 /// # Safety
95 ///
96 /// The caller must ensure that the index is in-bounds.
97 unsafe fn uget(self, index: I) -> Self::Output;
98}
99
100impl<'a, 'b, I, A, D> IndexLonger<I> for &'b ArrayView<'a, A, D>
101where
102 I: NdIndex<D>,
103 D: Dimension,
104{
105 type Output = &'a A;
106
107 /// Get a reference of a element through the view.
108 ///
109 /// This method is like `Index::index` but with a longer lifetime (matching
110 /// the array view); which we can only do for the array view and not in the
111 /// `Index` trait.
112 ///
113 /// See also [the `get` method][1] which works for all arrays and array
114 /// views.
115 ///
116 /// [1]: ArrayBase::get
117 ///
118 /// **Panics** if index is out of bounds.
119 fn index(self, index: I) -> &'a A {
120 debug_bounds_check!(self, index);
121 unsafe { &*self.get_ptr(index).unwrap_or_else(|| array_out_of_bounds()) }
122 }
123
124 fn get(self, index: I) -> Option<&'a A> {
125 unsafe { self.get_ptr(index).map(|ptr| &*ptr) }
126 }
127
128 /// Get a reference of a element through the view without boundary check
129 ///
130 /// This method is like `elem` with a longer lifetime (matching the array
131 /// view); which we can't do for general arrays.
132 ///
133 /// See also [the `uget` method][1] which works for all arrays and array
134 /// views.
135 ///
136 /// [1]: ArrayBase::uget
137 ///
138 /// **Note:** only unchecked for non-debug builds of ndarray.
139 unsafe fn uget(self, index: I) -> &'a A {
140 debug_bounds_check!(self, index);
141 &*self.as_ptr().offset(index.index_unchecked(&self.strides))
142 }
143}
144
145impl<'a, I, A, D> IndexLonger<I> for ArrayViewMut<'a, A, D>
146where
147 I: NdIndex<D>,
148 D: Dimension,
149{
150 type Output = &'a mut A;
151
152 /// Convert a mutable array view to a mutable reference of a element.
153 ///
154 /// This method is like `IndexMut::index_mut` but with a longer lifetime
155 /// (matching the array view); which we can only do for the array view and
156 /// not in the `Index` trait.
157 ///
158 /// See also [the `get_mut` method][1] which works for all arrays and array
159 /// views.
160 ///
161 /// [1]: ArrayBase::get_mut
162 ///
163 /// **Panics** if index is out of bounds.
164 fn index(mut self, index: I) -> &'a mut A {
165 debug_bounds_check!(self, index);
166 unsafe {
167 match self.get_mut_ptr(index) {
168 Some(ptr) => &mut *ptr,
169 None => array_out_of_bounds(),
170 }
171 }
172 }
173
174 /// Convert a mutable array view to a mutable reference of a element, with
175 /// checked access.
176 ///
177 /// See also [the `get_mut` method][1] which works for all arrays and array
178 /// views.
179 ///
180 /// [1]: ArrayBase::get_mut
181 ///
182 fn get(mut self, index: I) -> Option<&'a mut A> {
183 debug_bounds_check!(self, index);
184 unsafe {
185 match self.get_mut_ptr(index) {
186 Some(ptr) => Some(&mut *ptr),
187 None => None,
188 }
189 }
190 }
191
192 /// Convert a mutable array view to a mutable reference of a element without
193 /// boundary check.
194 ///
195 /// See also [the `uget_mut` method][1] which works for all arrays and array
196 /// views.
197 ///
198 /// [1]: ArrayBase::uget_mut
199 ///
200 /// **Note:** only unchecked for non-debug builds of ndarray.
201 unsafe fn uget(mut self, index: I) -> &'a mut A {
202 debug_bounds_check!(self, index);
203 &mut *self
204 .as_mut_ptr()
205 .offset(index.index_unchecked(&self.strides))
206 }
207}