1use crate::prelude_dev::*;
2
3#[non_exhaustive]
4#[derive(Debug, Clone, PartialEq, Eq)]
5pub enum Indexer {
6 Slice(SliceI),
9 Select(isize),
11 Insert,
14 Ellipsis,
16}
17
18pub use Indexer::Ellipsis;
19pub use Indexer::Insert as NewAxis;
20
21impl<R> From<R> for Indexer
24where
25 R: Into<SliceI>,
26{
27 fn from(slice: R) -> Self {
28 Self::Slice(slice.into())
29 }
30}
31
32impl From<Option<usize>> for Indexer {
33 fn from(opt: Option<usize>) -> Self {
34 match opt {
35 Some(_) => panic!("Option<T> should not be used in Indexer."),
36 None => Self::Insert,
37 }
38 }
39}
40
41macro_rules! impl_from_int_into_indexer {
42 ($($t:ty),*) => {
43 $(
44 impl From<$t> for Indexer {
45 fn from(index: $t) -> Self {
46 Self::Select(index as isize)
47 }
48 }
49 )*
50 };
51}
52
53impl_from_int_into_indexer!(usize, isize, u32, i32, u64, i64);
54
55macro_rules! impl_into_axes_index {
60 ($($t:ty),*) => {
61 $(
62 impl TryFrom<$t> for AxesIndex<Indexer> {
63 type Error = Error;
64
65 fn try_from(index: $t) -> Result<Self> {
66 Ok(AxesIndex::Val(index.try_into()?))
67 }
68 }
69
70 impl<const N: usize> TryFrom<[$t; N]> for AxesIndex<Indexer> {
71 type Error = Error;
72
73 fn try_from(index: [$t; N]) -> Result<Self> {
74 let index = index.iter().map(|v| v.clone().into()).collect::<Vec<_>>();
75 Ok(AxesIndex::Vec(index))
76 }
77 }
78
79 impl TryFrom<Vec<$t>> for AxesIndex<Indexer> {
80 type Error = Error;
81
82 fn try_from(index: Vec<$t>) -> Result<Self> {
83 let index = index.iter().map(|v| v.clone().into()).collect::<Vec<_>>();
84 Ok(AxesIndex::Vec(index))
85 }
86 }
87 )*
88 };
89}
90
91impl_into_axes_index!(usize, isize, u32, i32, u64, i64);
92impl_into_axes_index!(Option<usize>);
93impl_into_axes_index!(
94 Slice<isize>,
95 core::ops::Range<isize>,
96 core::ops::RangeFrom<isize>,
97 core::ops::RangeTo<isize>,
98 core::ops::Range<usize>,
99 core::ops::RangeFrom<usize>,
100 core::ops::RangeTo<usize>,
101 core::ops::Range<i32>,
102 core::ops::RangeFrom<i32>,
103 core::ops::RangeTo<i32>,
104 core::ops::RangeFull
105);
106
107impl_from_tuple_to_axes_index!(Indexer);
108
109pub trait IndexerPreserveAPI: Sized {
112 fn dim_narrow(&self, axis: isize, slice: SliceI) -> Result<Self>;
114}
115
116impl<D> IndexerPreserveAPI for Layout<D>
117where
118 D: DimDevAPI,
119{
120 fn dim_narrow(&self, axis: isize, slice: SliceI) -> Result<Self> {
121 let axis = rstsr_check_axis!(axis, self.ndim())?;
123
124 let mut shape = self.shape().clone();
126 let mut stride = self.stride().clone();
127
128 if slice == Slice::new(None, None, None) {
130 return Ok(self.clone());
131 }
132
133 let len_prev = shape[axis] as isize;
135
136 let step = slice.step().unwrap_or(1);
138 rstsr_assert!(step != 0, InvalidValue)?;
139
140 if len_prev == 0 {
142 return Ok(self.clone());
143 }
144
145 if step > 0 {
146 let mut start = slice.start().unwrap_or(0);
148 let mut stop = slice.stop().unwrap_or(len_prev);
149
150 if start < 0 {
152 start = (len_prev + start).max(0);
153 }
154 if stop < 0 {
155 stop = (len_prev + stop).max(0);
156 }
157
158 if start > len_prev || start > stop {
159 start = 0;
161 stop = 0;
162 } else if stop > len_prev {
163 stop = len_prev;
165 }
166
167 let offset = (self.offset() as isize + stride[axis] * start) as usize;
168 shape[axis] = ((stop - start + step - 1) / step).max(0) as usize;
169 stride[axis] *= step;
170 return Self::new(shape, stride, offset);
171 } else {
172 let mut start = slice.start().unwrap_or(len_prev - 1);
175 let mut stop = slice.stop().unwrap_or(-1);
176
177 if start < 0 {
179 start = (len_prev + start).max(0);
180 }
181 if stop < -1 {
182 stop = (len_prev + stop).max(-1);
183 }
184
185 if stop > len_prev - 1 || stop > start {
186 start = 0;
188 stop = 0;
189 } else if start > len_prev - 1 {
190 start = len_prev - 1;
192 }
193
194 let offset = (self.offset() as isize + stride[axis] * start) as usize;
195 shape[axis] = ((stop - start + step + 1) / step).max(0) as usize;
196 stride[axis] *= step;
197 return Self::new(shape, stride, offset);
198 }
199 }
200}
201
202pub trait IndexerSmallerOneAPI {
203 type DOut: DimDevAPI;
204
205 fn dim_select(&self, axis: isize, index: isize) -> Result<Layout<Self::DOut>>;
207
208 fn dim_eliminate(&self, axis: isize) -> Result<Layout<Self::DOut>>;
213
214 fn dim_chop(&self, axis: isize) -> Result<Layout<Self::DOut>>;
217}
218
219impl<D> IndexerSmallerOneAPI for Layout<D>
220where
221 D: DimDevAPI + DimSmallerOneAPI,
222 D::SmallerOne: DimDevAPI,
223{
224 type DOut = <D as DimSmallerOneAPI>::SmallerOne;
225
226 fn dim_select(&self, axis: isize, index: isize) -> Result<Layout<Self::DOut>> {
227 let axis = rstsr_check_axis!(axis, self.ndim())?;
229
230 let shape = self.shape();
232 let stride = self.stride();
233 let mut offset = self.offset() as isize;
234 let mut shape_new = vec![];
235 let mut stride_new = vec![];
236
237 for (i, (&d, &s)) in shape.as_ref().iter().zip(stride.as_ref().iter()).enumerate() {
239 if i == axis {
240 let idx = if index < 0 { d as isize + index } else { index };
242 rstsr_pattern!(idx, 0..d as isize, IndexError)?;
243 offset += s * idx;
244 } else {
245 shape_new.push(d);
247 stride_new.push(s);
248 }
249 }
250
251 let offset = offset as usize;
252 let layout = Layout::<IxD>::new(shape_new, stride_new, offset)?;
253 return layout.into_dim();
254 }
255
256 fn dim_eliminate(&self, axis: isize) -> Result<Layout<Self::DOut>> {
257 let axis = rstsr_check_axis!(axis, self.ndim())?;
259
260 let mut shape = self.shape().as_ref().to_vec();
262 let mut stride = self.stride().as_ref().to_vec();
263 let offset = self.offset();
264
265 if shape[axis] != 1 {
266 rstsr_raise!(InvalidValue, "Dimension to be eliminated is not 1.")?;
267 }
268
269 shape.remove(axis);
270 stride.remove(axis);
271
272 let layout = Layout::<IxD>::new(shape, stride, offset)?;
273 return layout.into_dim();
274 }
275
276 fn dim_chop(&self, axis: isize) -> Result<Layout<Self::DOut>> {
277 let axis = rstsr_check_axis!(axis, self.ndim())?;
279
280 let mut shape = self.shape().as_ref().to_vec();
282 let mut stride = self.stride().as_ref().to_vec();
283 let offset = self.offset();
284
285 shape.remove(axis);
286 stride.remove(axis);
287
288 let layout = Layout::<IxD>::new(shape, stride, offset)?;
289 return layout.into_dim();
290 }
291}
292
293pub trait IndexerLargerOneAPI {
294 type DOut: DimDevAPI;
295
296 fn dim_insert(&self, axis: isize) -> Result<Layout<Self::DOut>>;
299}
300
301impl<D> IndexerLargerOneAPI for Layout<D>
302where
303 D: DimDevAPI + DimLargerOneAPI,
304 D::LargerOne: DimDevAPI,
305{
306 type DOut = <D as DimLargerOneAPI>::LargerOne;
307
308 fn dim_insert(&self, axis: isize) -> Result<Layout<Self::DOut>> {
309 let axis = rstsr_check_axis_insert!(axis, self.ndim())?;
311
312 let is_f_prefer = self.f_prefer();
314 let mut shape = self.shape().as_ref().to_vec();
315 let mut stride = self.stride().as_ref().to_vec();
316 let offset = self.offset();
317
318 if is_f_prefer {
319 if axis == 0 {
320 shape.insert(0, 1);
321 stride.insert(0, 1);
322 } else {
323 shape.insert(axis, 1);
324 stride.insert(axis, stride[axis - 1]);
325 }
326 } else if axis == self.ndim() {
327 shape.push(1);
328 stride.push(1);
329 } else {
330 shape.insert(axis, 1);
331 stride.insert(axis, stride[axis]);
332 }
333
334 let layout = Layout::new(shape, stride, offset)?;
335 return layout.into_dim();
336 }
337}
338
339pub trait IndexerDynamicAPI: IndexerPreserveAPI {
340 fn dim_slice(&self, indexers: &[Indexer]) -> Result<Layout<IxD>>;
342
343 fn dim_split_at(&self, axis: isize) -> Result<(Layout<IxD>, Layout<IxD>)>;
345
346 fn dim_split_axes(&self, axes: &[isize]) -> Result<(Layout<IxD>, Layout<IxD>)>;
352}
353
354impl<D> IndexerDynamicAPI for Layout<D>
355where
356 D: DimDevAPI,
357{
358 fn dim_slice(&self, indexers: &[Indexer]) -> Result<Layout<IxD>> {
359 let shape = self.shape().as_ref().to_vec();
361 let stride = self.stride().as_ref().to_vec();
362 let mut layout = Layout::new(shape, stride, self.offset)?;
363
364 let mut indexers = indexers.to_vec();
366
367 let mut counter_slice = 0;
369 let mut counter_select = 0;
370 let mut idx_ellipsis = None;
371 for (n, indexer) in indexers.iter().enumerate() {
372 match indexer {
373 Indexer::Slice(_) => counter_slice += 1,
374 Indexer::Select(_) => counter_select += 1,
375 Indexer::Ellipsis => match idx_ellipsis {
376 Some(_) => rstsr_raise!(InvalidValue, "Only one ellipsis indexer allowed.")?,
377 None => idx_ellipsis = Some(n),
378 },
379 _ => {},
380 }
381 }
382
383 rstsr_pattern!(counter_slice + counter_select, 0..=self.ndim(), ValueOutOfRange)?;
385
386 let n_ellipsis = self.ndim() - counter_slice - counter_select;
388 if n_ellipsis == 0 {
389 if let Some(idx) = idx_ellipsis {
390 indexers.remove(idx);
391 }
392 } else if let Some(idx_ellipsis) = idx_ellipsis {
393 indexers[idx_ellipsis] = SliceI::new(None, None, None).into();
394 if n_ellipsis > 1 {
395 for _ in 1..n_ellipsis {
396 indexers.insert(idx_ellipsis, SliceI::new(None, None, None).into());
397 }
398 }
399 } else {
400 for _ in 0..n_ellipsis {
401 indexers.push(SliceI::new(None, None, None).into());
402 }
403 }
404
405 let mut cur_dim = self.ndim() as isize;
408 for indexer in indexers.iter().rev() {
409 match indexer {
410 Indexer::Slice(slice) => {
411 cur_dim -= 1;
412 layout = layout.dim_narrow(cur_dim, *slice)?;
413 },
414 Indexer::Select(index) => {
415 cur_dim -= 1;
416 layout = layout.dim_select(cur_dim, *index)?;
417 },
418 Indexer::Insert => {
419 layout = layout.dim_insert(cur_dim)?;
420 },
421 _ => rstsr_raise!(InvalidValue, "Invalid indexer found : {:?}", indexer)?,
422 }
423 }
424
425 rstsr_assert!(cur_dim == 0, Miscellaneous, "Internal program error in indexer.")?;
427
428 return Ok(layout);
429 }
430
431 fn dim_split_at(&self, axis: isize) -> Result<(Layout<IxD>, Layout<IxD>)> {
432 let norm = if axis < 0 { self.ndim() as isize + axis } else { axis };
435 if !(norm >= 0 && norm <= self.ndim() as isize) {
436 return Err(rstsr_axis_error!(axis, self.ndim()));
437 }
438 let axis = norm as usize;
439
440 let shape = self.shape().as_ref().to_vec();
442 let stride = self.stride().as_ref().to_vec();
443 let offset = self.offset();
444
445 let (shape1, shape2) = shape.split_at(axis);
446 let (stride1, stride2) = stride.split_at(axis);
447
448 let layout1 = unsafe { Layout::new_unchecked(shape1.to_vec(), stride1.to_vec(), offset) };
449 let layout2 = unsafe { Layout::new_unchecked(shape2.to_vec(), stride2.to_vec(), offset) };
450 return Ok((layout1, layout2));
451 }
452
453 fn dim_split_axes(&self, axes: &[isize]) -> Result<(Layout<IxD>, Layout<IxD>)> {
454 let axes_update = normalize_axes_index(axes.into(), self.ndim(), false, false)?
458 .into_iter()
459 .map(|axis| axis as usize)
460 .collect::<Vec<usize>>();
461
462 let axes_rest = (0..self.ndim()).filter(|&axis| !axes_update.contains(&axis)).collect::<Vec<_>>();
465
466 let offset = self.offset();
468 let shape_axes = axes_update.iter().map(|&axis| self.shape()[axis]).collect::<Vec<_>>();
469 let strides_axes = axes_update.iter().map(|&axis| self.stride()[axis]).collect::<Vec<_>>();
470 let layout_axes = Layout::new(shape_axes, strides_axes, offset)?;
471
472 let shape_rest = axes_rest.iter().map(|&axis| self.shape()[axis]).collect::<Vec<_>>();
473 let strides_rest = axes_rest.iter().map(|&axis| self.stride()[axis]).collect::<Vec<_>>();
474 let layout_rest = Layout::new(shape_rest, strides_rest, offset)?;
475
476 return Ok((layout_axes, layout_rest));
477 }
478}
479
480#[macro_export]
482macro_rules! slice {
483 ($stop:expr) => {{
484 use $crate::layout::slice::Slice;
485 Slice::<isize>::from(Slice::new(None, $stop, None))
486 }};
487 ($start:expr, $stop:expr) => {{
488 use $crate::layout::slice::Slice;
489 Slice::<isize>::from(Slice::new($start, $stop, None))
490 }};
491 ($start:expr, $stop:expr, $step:expr) => {{
492 use $crate::layout::slice::Slice;
493 Slice::<isize>::from(Slice::new($start, $stop, $step))
494 }};
495}
496
497#[macro_export]
498macro_rules! s {
499 [$($slc:expr),*] => {
501 [$(($slc).into()),*].as_ref()
502 };
503}
504
505#[cfg(test)]
506mod tests {
507 use super::*;
508
509 #[test]
510 fn test_slice() {
511 let t = 3_usize;
512 let s = slice!(1, 2, t);
513 assert_eq!(s.start(), Some(1));
514 assert_eq!(s.stop(), Some(2));
515 assert_eq!(s.step(), Some(3));
516 }
517
518 #[test]
519 fn test_slice_at_dim() {
520 let l = Layout::new([2, 3, 4], [1, 10, 100], 0).unwrap();
521 let s = slice!(10, 1, -1);
522 let l1 = l.dim_narrow(1, s).unwrap();
523 println!("{l1:?}");
524 let l2 = l.dim_select(1, -2).unwrap();
525 println!("{l2:?}");
526 let l3 = l.dim_insert(1).unwrap();
527 println!("{l3:?}");
528
529 let l = Layout::new([2, 3, 4], [100, 10, 1], 0).unwrap();
530 let l3 = l.dim_insert(1).unwrap();
531 println!("{l3:?}");
532
533 let l4 = l.dim_slice(s![Indexer::Ellipsis, 1..3, None, 2]).unwrap();
534 let l4 = l4.into_dim::<Ix3>().unwrap();
535 println!("{l4:?}");
536 assert_eq!(l4.shape(), &[2, 2, 1]);
537 assert_eq!(l4.offset(), 12);
538
539 let l5 = l.dim_slice(s![None, 1, None, 1..3]).unwrap();
540 let l5 = l5.into_dim::<Ix4>().unwrap();
541 println!("{l5:?}");
542 assert_eq!(l5.shape(), &[1, 1, 2, 4]);
543 assert_eq!(l5.offset(), 110);
544 }
545
546 #[test]
547 fn test_slice_with_stride() {
548 let l = Layout::new([24], [1], 0).unwrap();
549 let b = l.dim_narrow(0, slice!(5, 15, 2)).unwrap();
550 assert_eq!(b, Layout::new([5], [2], 5).unwrap());
551 let b = l.dim_narrow(0, slice!(5, 16, 2)).unwrap();
552 assert_eq!(b, Layout::new([6], [2], 5).unwrap());
553 let b = l.dim_narrow(0, slice!(15, 5, -2)).unwrap();
554 assert_eq!(b, Layout::new([5], [-2], 15).unwrap());
555 let b = l.dim_narrow(0, slice!(15, 4, -2)).unwrap();
556 assert_eq!(b, Layout::new([6], [-2], 15).unwrap());
557 }
558
559 #[test]
560 fn test_expand_dims() {
561 let l = Layout::<Ix3>::new([2, 3, 4], [1, 10, 100], 0).unwrap();
562 let l1 = l.dim_insert(0).unwrap();
563 println!("{l1:?}");
564 let l2 = l.dim_insert(1).unwrap();
565 println!("{l2:?}");
566 let l3 = l.dim_insert(3).unwrap();
567 println!("{l3:?}");
568 let l4 = l.dim_insert(-1).unwrap();
569 println!("{l4:?}");
570 let l5 = l.dim_insert(-4).unwrap();
571 println!("{l5:?}");
572 }
573}