toodee/ops.rs
1use core::ops::{Index, IndexMut};
2use core::ptr;
3use core::mem;
4
5use crate::iter::*;
6use crate::view::*;
7use crate::flattenexact::*;
8
9/// A `(col, row)` coordinate in 2D space.
10pub type Coordinate = (usize, usize);
11
12/// An iterator over each "cell" in a 2D array
13pub type Cells<'a, T> = FlattenExact<Rows<'a, T>>;
14/// A mutable iterator over each "cell" in a 2D array
15pub type CellsMut<'a, T> = FlattenExact<RowsMut<'a, T>>;
16
17/// Defines operations common to both `TooDee` and `TooDeeView`. Default implementations are provided
18/// where possible/practical.
19pub trait TooDeeOps<T> : Index<usize, Output=[T]> + Index<Coordinate, Output=T> {
20
21 /// The number of columns in the area represented by this object.
22 fn num_cols(&self) -> usize;
23 /// The number of rows in the area represented by this object.
24 fn num_rows(&self) -> usize;
25
26 /// Returns the size/dimensions of the current object.
27 fn size(&self) -> (usize, usize) {
28 (self.num_cols(), self.num_rows())
29 }
30
31 /// Returns `true` if the array contains no elements.
32 fn is_empty(&self) -> bool {
33 self.num_cols() == 0 || self.num_rows() == 0
34 }
35
36 /// Returns a view (or subset) of the current area based on the coordinates provided.
37 ///
38 /// # Examples
39 ///
40 /// ```
41 /// use toodee::{TooDee,TooDeeOps};
42 /// let toodee : TooDee<u32> = TooDee::new(10, 5);
43 /// let view = toodee.view((1, 1), (9, 4));
44 /// assert_eq!(view.num_cols(), 8);
45 /// assert_eq!(view.num_rows(), 3);
46 /// ```
47 fn view(&self, start: Coordinate, end: Coordinate) -> TooDeeView<'_, T>;
48
49 /// Returns an iterator of slices, where each slice represents an entire row.
50 ///
51 /// # Examples
52 ///
53 /// ```
54 /// use toodee::{TooDee,TooDeeOps};
55 /// let toodee : TooDee<u32> = TooDee::init(10, 5, 42u32);
56 /// let mut sum = 0u32;
57 /// for r in toodee.rows() {
58 /// sum += r.iter().sum::<u32>();
59 /// }
60 /// assert_eq!(sum, 42*50);
61 /// ```
62 fn rows(&self) -> Rows<'_, T>;
63
64 /// Returns an iterator over a single column. Note that the `Col` iterator is indexable.
65 ///
66 /// # Examples
67 ///
68 /// ```
69 /// use toodee::{TooDee,TooDeeOps};
70 /// let toodee : TooDee<u32> = TooDee::init(10, 5, 42u32);
71 /// let mut sum = 0u32;
72 /// for c in toodee.col(1) {
73 /// sum += c;
74 /// }
75 /// assert_eq!(sum, 42*5);
76 /// ```
77 fn col(&self, col: usize) -> Col<'_, T>;
78
79 /// Returns an iterator that traverses all cells within the area.
80 ///
81 /// # Examples
82 ///
83 /// ```
84 /// use toodee::{TooDee,TooDeeOps};
85 /// let toodee : TooDee<u32> = TooDee::init(10, 5, 42u32);
86 /// let mut sum = toodee.cells().sum::<u32>();
87 /// assert_eq!(sum, 42*50);
88 /// ```
89 fn cells(&self) -> Cells<'_, T> {
90 FlattenExact::new(self.rows())
91 }
92
93 /// Returns a row without checking that the row is valid. Generally it's best to use indexing instead, e.g., toodee\[row\]
94 ///
95 /// # Safety
96 ///
97 /// This is generally not recommended, use with caution!
98 /// Calling this method with an invalid row is *[undefined behavior]* even if the resulting reference is not used.
99 unsafe fn get_unchecked_row(&self, row: usize) -> &[T];
100
101 /// Returns a cell without checking that the cell coordinate is valid. Generally it's best to use indexing instead, e.g., toodee\[(col, row)\]
102 ///
103 /// # Safety
104 ///
105 /// This is generally not recommended, use with caution!
106 /// Calling this method with an invalid coordinate is *[undefined behavior]* even if the resulting reference is not used.
107 unsafe fn get_unchecked(&self, coord: Coordinate) -> &T;
108
109}
110
111/// Defines operations common to both `TooDee` and `TooDeeViewMut`. Default implementations
112/// are provided where possible/practical.
113pub trait TooDeeOpsMut<T> : TooDeeOps<T> + IndexMut<usize,Output=[T]> + IndexMut<Coordinate, Output=T> {
114
115 /// Returns a mutable view (or subset) of the current area based on the coordinates provided.
116 ///
117 /// # Examples
118 ///
119 /// ```
120 /// use toodee::{TooDee,TooDeeOps,TooDeeOpsMut};
121 /// let mut toodee : TooDee<u32> = TooDee::new(10, 5);
122 /// let view = toodee.view_mut((1, 1), (9, 4));
123 /// assert_eq!(view.num_cols(), 8);
124 /// assert_eq!(view.num_rows(), 3);
125 /// ```
126 fn view_mut(&mut self, start: Coordinate, end: Coordinate) -> TooDeeViewMut<'_, T>;
127
128 /// Returns a mutable iterator of slices, where each slice represents an entire row.
129 ///
130 /// # Examples
131 ///
132 /// ```
133 /// use toodee::{TooDee,TooDeeOps,TooDeeOpsMut};
134 /// let mut toodee : TooDee<u32> = TooDee::init(10, 5, 42u32);
135 /// for (i, r) in toodee.rows_mut().enumerate() {
136 /// r.iter_mut().for_each(|c| *c -= i as u32);
137 /// }
138 /// assert_eq!(toodee.cells().sum::<u32>(), 42*50 - 10 - 20 - 30 - 40);
139 /// ```
140 fn rows_mut(&mut self) -> RowsMut<'_, T>;
141
142 /// Returns a mutable iterator over a single column. Note that the `ColMut` iterator is indexable.
143 ///
144 /// # Examples
145 ///
146 /// ```
147 /// use toodee::{TooDee,TooDeeOps,TooDeeOpsMut};
148 /// let mut toodee : TooDee<u32> = TooDee::init(10, 5, 42u32);
149 /// for c in toodee.col_mut(4) {
150 /// *c /= 2;
151 /// }
152 /// assert_eq!(toodee.cells().sum::<u32>(), 42*45 + 21*5);
153 /// ```
154 fn col_mut(&mut self, col: usize) -> ColMut<'_, T>;
155
156 /// Returns an iterator that traverses all cells within the area.
157 ///
158 /// # Examples
159 ///
160 /// ```
161 /// use toodee::{TooDee,TooDeeOps,TooDeeOpsMut};
162 /// let mut toodee : TooDee<u32> = TooDee::init(10, 5, 42u32);
163 /// for c in toodee.cells_mut() {
164 /// *c -= 1;
165 /// }
166 /// assert_eq!(toodee.cells().sum::<u32>(), 41*50);
167 /// ```
168 fn cells_mut(&mut self) -> CellsMut<'_, T> {
169 FlattenExact::new(self.rows_mut())
170 }
171
172 /// Fills the entire area with the specified value.
173 ///
174 /// # Examples
175 ///
176 /// ```
177 /// use toodee::{TooDee,TooDeeOps,TooDeeOpsMut};
178 /// let mut toodee : TooDee<u32> = TooDee::init(10, 5, 42u32);
179 /// let mut view = toodee.view_mut((1, 1), (9, 4));
180 /// view.fill(0);
181 /// assert_eq!(toodee.cells().sum::<u32>(), 42*(50 - 8*3));
182 /// ```
183 fn fill(&mut self, fill: T)
184 where T: Clone {
185 for r in self.rows_mut() {
186 r.fill(fill.clone());
187 }
188 }
189
190 /// Swap/exchange the data between two columns.
191 ///
192 /// # Examples
193 ///
194 /// ```
195 /// use toodee::{TooDee,TooDeeOps,TooDeeOpsMut};
196 /// let mut toodee : TooDee<u32> = TooDee::init(10, 5, 42u32);
197 /// for c in toodee.col_mut(2) {
198 /// *c = 1;
199 /// }
200 /// assert_eq!(toodee[(4, 0)], 42);
201 /// toodee.swap_cols(2, 4);
202 /// assert_eq!(toodee[(4, 0)], 1);
203 /// ```
204 fn swap_cols(&mut self, c1: usize, c2: usize) {
205 let num_cols = self.num_cols();
206 assert!(c1 < num_cols);
207 assert!(c2 < num_cols);
208 for r in self.rows_mut() {
209 // The column indices have been checked with asserts (see above), so we can
210 // safely access and swap the elements using `get_unchecked_mut`.
211 unsafe {
212 let pa: *mut T = r.get_unchecked_mut(c1);
213 let pb: *mut T = r.get_unchecked_mut(c2);
214 ptr::swap(pa, pb);
215 }
216 }
217 }
218
219 /// Swap/exchange two cells in the array.
220 ///
221 /// # Panics
222 ///
223 /// Panics if either cell coordinate is out of bounds.
224 ///
225 /// # Examples
226 ///
227 /// ```
228 /// use toodee::{TooDee,TooDeeOps,TooDeeOpsMut};
229 /// let mut toodee = TooDee::from_vec(3, 3, (0u32..9).collect());
230 /// toodee.swap((0,0),(2, 2));
231 /// assert_eq!(toodee.data(), &[8, 1, 2, 3, 4, 5, 6, 7, 0]);
232 /// ```
233 fn swap(&mut self, mut cell1: Coordinate, mut cell2: Coordinate) {
234 if cell1.1 > cell2.1 {
235 mem::swap(&mut cell1, &mut cell2);
236 }
237 let num_cols = self.num_cols();
238 assert!(cell1.0 < num_cols && cell2.0 < num_cols);
239 let mut iter = self.rows_mut();
240 let row1 = iter.nth(cell1.1).unwrap();
241 if cell1.1 == cell2.1 {
242 unsafe {
243 let pa: *mut T = row1.get_unchecked_mut(cell1.0);
244 let pb: *mut T = row1.get_unchecked_mut(cell2.0);
245 ptr::swap(pa, pb);
246 }
247 } else {
248 let row2 = iter.nth(cell2.1 - cell1.1 - 1).unwrap();
249 unsafe {
250 let pa: *mut T = row1.get_unchecked_mut(cell1.0);
251 let pb: *mut T = row2.get_unchecked_mut(cell2.0);
252 ptr::swap(pa, pb);
253 }
254 }
255 }
256
257 /// Swap/exchange the data between two rows. Note that this method is overridden in both `TooDee` and `TooDeeOpsMut`.
258 /// This implementation remains in place for other types that may wish to implement the trait.
259 ///
260 /// # Panics
261 ///
262 /// Panics if either row index is out of bounds.
263 ///
264 /// # Examples
265 ///
266 /// ```
267 /// use toodee::{TooDee,TooDeeOps,TooDeeOpsMut};
268 /// let mut toodee : TooDee<u32> = TooDee::init(10, 5, 42u32);
269 /// toodee[0].iter_mut().for_each(|v| *v = 1);
270 /// assert_eq!(toodee[(0, 2)], 42);
271 /// toodee.view_mut((0, 0), (10, 5)).swap_rows(0, 2);
272 /// assert_eq!(toodee[(0, 2)], 1);
273 /// ```
274 fn swap_rows(&mut self, mut r1: usize, mut r2: usize) {
275 if r1 == r2 {
276 return;
277 }
278 if r2 < r1 {
279 mem::swap(&mut r1, &mut r2);
280 }
281 let mut iter = self.rows_mut();
282 let tmp = iter.nth(r1).unwrap();
283 tmp.swap_with_slice(iter.nth(r2-r1-1).unwrap());
284 }
285
286 /// Return the specified rows as mutable slices.
287 ///
288 /// # Panics
289 ///
290 /// Will panic if `r1` and `r2` are equal, or if either row index is out of bounds.
291 ///
292 /// # Examples
293 ///
294 /// ```
295 /// use toodee::{TooDee,TooDeeOps,TooDeeOpsMut};
296 /// let mut toodee : TooDee<u32> = TooDee::init(10, 5, 42u32);
297 /// let (r1, r2) = toodee.row_pair_mut(0, 4);
298 /// // do something with the row pair
299 /// r1.swap_with_slice(r2);
300 /// ```
301 fn row_pair_mut(&mut self, r1: usize, r2: usize) -> (&mut [T], &mut [T]) {
302 let num_rows = self.num_rows();
303 assert!(r1 < num_rows);
304 assert!(r2 < num_rows);
305 assert_ne!(r1, r2);
306 if r1 < r2 {
307 let mut iter = self.rows_mut();
308 let tmp = iter.nth(r1).unwrap();
309 (tmp, iter.nth(r2-r1-1).unwrap())
310 } else {
311 let mut iter = self.rows_mut();
312 let tmp = iter.nth(r2).unwrap();
313 (iter.nth(r1-r2-1).unwrap(), tmp)
314 }
315 }
316
317 /// Returns a mutable row without checking that the row is valid. Generally it's best to use indexing instead, e.g., toodee\[row\]
318 ///
319 /// # Safety
320 ///
321 /// This is generally not recommended, use with caution!
322 /// Calling this method with an invalid row is *[undefined behavior]* even if the resulting reference is not used.
323 unsafe fn get_unchecked_row_mut(&mut self, row: usize) -> &mut [T];
324
325 /// Returns a mutable cell without checking that the cell coordinate is valid. Generally it's best to use indexing instead, e.g., toodee\[(col, row)\]
326 ///
327 /// # Safety
328 ///
329 /// This is generally not recommended, use with caution!
330 /// Calling this method with an invalid coordinate is *[undefined behavior]* even if the resulting reference is not used.
331 unsafe fn get_unchecked_mut(&mut self, coord: Coordinate) -> &mut T;
332
333}
334