1use std::marker::PhantomData;
22use std::ops::{Index, IndexMut};
23
24use tinyvec::ArrayVec;
25
26use crate::element_op::{ComposableElementOp, ElementOp, ElementOpApply, Identity};
27use crate::{AxisVec, Result, StrideVec, StridedError, INLINE_RANK};
28
29#[inline(always)]
35fn arrayvec_from_slice<T: Copy + Default>(src: &[T]) -> ArrayVec<[T; INLINE_RANK]> {
36 debug_assert!(src.len() <= INLINE_RANK);
37 let n = src.len();
38 let mut buf = [T::default(); INLINE_RANK];
39 match n {
40 0 => {}
41 1 => buf[0] = src[0],
42 2 => {
43 buf[0] = src[0];
44 buf[1] = src[1];
45 }
46 3 => {
47 buf[0] = src[0];
48 buf[1] = src[1];
49 buf[2] = src[2];
50 }
51 4 => {
52 buf[0] = src[0];
53 buf[1] = src[1];
54 buf[2] = src[2];
55 buf[3] = src[3];
56 }
57 5 => {
58 buf[0] = src[0];
59 buf[1] = src[1];
60 buf[2] = src[2];
61 buf[3] = src[3];
62 buf[4] = src[4];
63 }
64 6 => {
65 buf[0] = src[0];
66 buf[1] = src[1];
67 buf[2] = src[2];
68 buf[3] = src[3];
69 buf[4] = src[4];
70 buf[5] = src[5];
71 }
72 7 => {
73 buf[0] = src[0];
74 buf[1] = src[1];
75 buf[2] = src[2];
76 buf[3] = src[3];
77 buf[4] = src[4];
78 buf[5] = src[5];
79 buf[6] = src[6];
80 }
81 _ => {
82 buf[0] = src[0];
83 buf[1] = src[1];
84 buf[2] = src[2];
85 buf[3] = src[3];
86 buf[4] = src[4];
87 buf[5] = src[5];
88 buf[6] = src[6];
89 buf[7] = src[7];
90 }
91 }
92 ArrayVec::from_array_len(buf, n)
93}
94
95#[derive(Clone, Debug)]
97struct SpilledMeta {
98 dims: Box<[usize]>,
99 strides: Box<[isize]>,
100}
101
102#[derive(Debug)]
109struct ViewMeta {
110 inline_dims: ArrayVec<[usize; INLINE_RANK]>,
111 inline_strides: ArrayVec<[isize; INLINE_RANK]>,
112 spilled: Option<Box<SpilledMeta>>,
113}
114
115impl Clone for ViewMeta {
116 #[inline]
117 fn clone(&self) -> Self {
118 Self {
119 inline_dims: self.inline_dims,
120 inline_strides: self.inline_strides,
121 spilled: self.spilled.clone(),
122 }
123 }
124}
125
126impl ViewMeta {
127 #[inline(always)]
128 fn from_slices(dims: &[usize], strides: &[isize]) -> Self {
129 debug_assert_eq!(dims.len(), strides.len());
130 if dims.len() <= INLINE_RANK {
131 Self {
132 inline_dims: arrayvec_from_slice(dims),
133 inline_strides: arrayvec_from_slice(strides),
134 spilled: None,
135 }
136 } else {
137 Self {
138 inline_dims: ArrayVec::new(),
139 inline_strides: ArrayVec::new(),
140 spilled: Some(Box::new(SpilledMeta {
141 dims: dims.into(),
142 strides: strides.into(),
143 })),
144 }
145 }
146 }
147
148 #[inline]
149 fn dims(&self) -> &[usize] {
150 match &self.spilled {
151 Some(spilled) => &spilled.dims,
152 None => self.inline_dims.as_slice(),
153 }
154 }
155
156 #[inline]
157 fn strides(&self) -> &[isize] {
158 match &self.spilled {
159 Some(spilled) => &spilled.strides,
160 None => self.inline_strides.as_slice(),
161 }
162 }
163}
164
165#[inline]
166fn empty_layout(dims: &[usize]) -> bool {
167 dims.iter().any(|&dim| dim == 0)
168}
169
170#[inline]
171fn empty_const_ptr<T>() -> *const T {
172 core::ptr::NonNull::<T>::dangling().as_ptr()
173}
174
175#[inline]
176fn empty_mut_ptr<T>() -> *mut T {
177 core::ptr::NonNull::<T>::dangling().as_ptr()
178}
179
180#[inline]
186pub(crate) fn validate_bounds(
187 len: usize,
188 dims: &[usize],
189 strides: &[isize],
190 offset: isize,
191) -> Result<()> {
192 if dims.len() != strides.len() {
193 return Err(StridedError::StrideLengthMismatch);
194 }
195 if dims.iter().any(|&d| d == 0) {
197 return Ok(());
198 }
199 let mut min_offset = offset;
201 let mut max_offset = offset;
202 for (&dim, &stride) in dims.iter().zip(strides.iter()) {
203 if dim > 1 {
204 let last = dim
205 .checked_sub(1)
206 .and_then(|value| isize::try_from(value).ok())
207 .ok_or(StridedError::OffsetOverflow)?;
208 let end = stride
209 .checked_mul(last)
210 .ok_or(StridedError::OffsetOverflow)?;
211 if end >= 0 {
212 max_offset = max_offset
213 .checked_add(end)
214 .ok_or(StridedError::OffsetOverflow)?;
215 } else {
216 min_offset = min_offset
217 .checked_add(end)
218 .ok_or(StridedError::OffsetOverflow)?;
219 }
220 }
221 }
222 if min_offset < 0 || max_offset < 0 {
223 return Err(StridedError::OffsetOverflow);
224 }
225 if max_offset as usize >= len {
226 return Err(StridedError::OffsetOverflow);
227 }
228 Ok(())
229}
230
231#[inline]
239fn indexed_offset(dims: &[usize], strides: &[isize], indices: &[usize], base: isize) -> isize {
240 assert_eq!(indices.len(), dims.len(), "wrong number of indices");
241 let mut offset = base;
242 for (i, &index) in indices.iter().enumerate() {
243 assert!(
244 index < dims[i],
245 "index {} out of bounds for dim {}",
246 index,
247 dims[i]
248 );
249 offset = isize::try_from(index)
250 .ok()
251 .and_then(|index| index.checked_mul(strides[i]))
252 .and_then(|step| offset.checked_add(step))
253 .expect("index offset overflow");
254 }
255 offset
256}
257
258#[inline]
272pub fn col_major_strides(dims: &[usize]) -> StrideVec {
273 let rank = dims.len();
274 if rank == 0 {
275 return StrideVec::new();
276 }
277 let mut strides = StrideVec::new();
278 strides.resize(rank, 1isize);
279 for i in 1..rank {
280 strides[i] = strides[i - 1] * dims[i - 1] as isize;
281 }
282 strides
283}
284
285#[inline]
299pub fn row_major_strides(dims: &[usize]) -> StrideVec {
300 let rank = dims.len();
301 if rank == 0 {
302 return StrideVec::new();
303 }
304 let mut strides = StrideVec::new();
305 strides.resize(rank, 1isize);
306 for i in (0..rank - 1).rev() {
307 strides[i] = strides[i + 1] * dims[i + 1] as isize;
308 }
309 strides
310}
311
312pub struct StridedView<'a, T, Op = Identity> {
348 ptr: *const T,
349 data: &'a [T],
350 meta: ViewMeta,
351 offset: isize,
352 _op: PhantomData<Op>,
353}
354
355unsafe impl<T: Sync, Op: Send> Send for StridedView<'_, T, Op> {}
356unsafe impl<T: Sync, Op: Sync> Sync for StridedView<'_, T, Op> {}
357
358impl<T, Op> Clone for StridedView<'_, T, Op> {
359 #[inline]
360 fn clone(&self) -> Self {
361 Self {
362 ptr: self.ptr,
363 data: self.data,
364 meta: self.meta.clone(),
365 offset: self.offset,
366 _op: PhantomData,
367 }
368 }
369}
370
371impl<T: std::fmt::Debug, Op> std::fmt::Debug for StridedView<'_, T, Op> {
372 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
373 f.debug_struct("StridedView")
374 .field("dims", &self.meta.dims())
375 .field("strides", &self.meta.strides())
376 .field("offset", &self.offset)
377 .finish()
378 }
379}
380
381#[inline]
386fn base_ptr<T>(data: &[T], dims: &[usize], offset: isize) -> *const T {
387 if empty_layout(dims) {
388 empty_const_ptr()
389 } else {
390 unsafe { data.as_ptr().offset(offset) }
391 }
392}
393
394#[inline]
396fn from_meta<'a, T, Op>(
397 data: &'a [T],
398 dims: &[usize],
399 strides: &[isize],
400 offset: isize,
401) -> StridedView<'a, T, Op> {
402 let meta = ViewMeta::from_slices(dims, strides);
403 let ptr = base_ptr(data, meta.dims(), offset);
404 StridedView {
405 ptr,
406 data,
407 meta,
408 offset,
409 _op: PhantomData,
410 }
411}
412
413impl<'a, T, Op> StridedView<'a, T, Op> {
414 #[inline]
431 pub fn new(data: &'a [T], dims: &[usize], strides: &[isize], offset: isize) -> Result<Self> {
432 validate_bounds(data.len(), dims, strides, offset)?;
433 Ok(from_meta(data, dims, strides, offset))
434 }
435
436 #[inline]
451 pub unsafe fn new_unchecked(
452 data: &'a [T],
453 dims: &[usize],
454 strides: &[isize],
455 offset: isize,
456 ) -> Self {
457 from_meta(data, dims, strides, offset)
458 }
459
460 #[inline]
462 pub fn dims(&self) -> &[usize] {
463 self.meta.dims()
464 }
465
466 #[inline]
468 pub fn strides(&self) -> &[isize] {
469 self.meta.strides()
470 }
471
472 #[inline]
474 pub fn offset(&self) -> isize {
475 self.offset
476 }
477
478 #[inline]
480 pub fn ndim(&self) -> usize {
481 self.dims().len()
482 }
483
484 #[inline]
486 pub fn len(&self) -> usize {
487 self.dims().iter().product()
488 }
489
490 #[inline]
492 pub fn is_empty(&self) -> bool {
493 self.dims().iter().any(|&d| d == 0)
494 }
495
496 #[inline]
498 pub fn data(&self) -> &'a [T] {
499 self.data
500 }
501
502 #[inline]
504 pub fn ptr(&self) -> *const T {
505 self.ptr
506 }
507
508 pub fn permute(&self, perm: &[usize]) -> Result<StridedView<'a, T, Op>> {
510 let rank = self.dims().len();
511 if perm.len() != rank {
512 return Err(StridedError::RankMismatch(perm.len(), rank));
513 }
514 let mut seen: tinyvec::TinyVec<[bool; INLINE_RANK]> = tinyvec::TinyVec::new();
515 seen.resize(rank, false);
516 for &p in perm {
517 if p >= rank {
518 return Err(StridedError::InvalidAxis { axis: p, rank });
519 }
520 if seen[p] {
521 return Err(StridedError::InvalidAxis { axis: p, rank });
522 }
523 seen[p] = true;
524 }
525 let new_dims: AxisVec = perm.iter().map(|&p| self.dims()[p]).collect();
526 let new_strides: StrideVec = perm.iter().map(|&p| self.strides()[p]).collect();
527 Ok(from_meta(self.data, &new_dims, &new_strides, self.offset))
528 }
529
530 pub fn diagonal_view(&self, axis_pairs: &[(usize, usize)]) -> Result<StridedView<'a, T, Op>> {
551 let ndim = self.ndim();
552 let mut root: tinyvec::TinyVec<[usize; INLINE_RANK]> = (0..ndim).collect();
557 fn find(root: &mut [usize], mut ax: usize) -> usize {
558 while root[ax] != ax {
559 root[ax] = root[root[ax]];
560 ax = root[ax];
561 }
562 ax
563 }
564 for &(a, b) in axis_pairs {
565 let hi = a.max(b);
566 if hi >= ndim {
567 return Err(StridedError::InvalidAxis {
568 axis: hi,
569 rank: ndim,
570 });
571 }
572 if a == b {
573 return Err(StridedError::InvalidAxis {
574 axis: a,
575 rank: ndim,
576 });
577 }
578 let (ra, rb) = (find(&mut root, a), find(&mut root, b));
579 root[ra.max(rb)] = ra.min(rb);
580 }
581
582 let mut dims: AxisVec = AxisVec::new();
587 let mut strides: StrideVec = StrideVec::new();
588 let mut position: tinyvec::TinyVec<[usize; INLINE_RANK]> =
589 tinyvec::TinyVec::with_capacity(ndim);
590 for ax in 0..ndim {
591 let r = find(&mut root, ax);
592 if r == ax {
593 position.push(dims.len());
594 dims.push(self.dims()[ax]);
595 strides.push(self.strides()[ax]);
596 } else {
597 position.push(usize::MAX);
598 let p = position[r];
599 strides[p] = strides[p]
600 .checked_add(self.strides()[ax])
601 .ok_or(StridedError::OffsetOverflow)?;
602 dims[p] = dims[p].min(self.dims()[ax]);
603 }
604 }
605
606 validate_bounds(self.data().len(), &dims, &strides, self.offset())?;
610
611 Ok(from_meta(self.data(), &dims, &strides, self.offset()))
612 }
613
614 pub fn broadcast(&self, target_dims: &[usize]) -> Result<StridedView<'a, T, Op>> {
618 if self.dims().len() != target_dims.len() {
619 return Err(StridedError::RankMismatch(
620 self.dims().len(),
621 target_dims.len(),
622 ));
623 }
624 let mut new_strides = StrideVec::with_capacity(self.dims().len());
625 for i in 0..self.dims().len() {
626 if self.dims()[i] == target_dims[i] {
627 new_strides.push(self.strides()[i]);
628 } else if self.dims()[i] == 1 {
629 new_strides.push(0);
630 } else {
631 return Err(StridedError::ShapeMismatch(
632 self.dims().to_vec(),
633 target_dims.to_vec(),
634 ));
635 }
636 }
637 Ok(from_meta(self.data, target_dims, &new_strides, self.offset))
638 }
639}
640
641impl<'a, T: Copy + ElementOpApply, Op: ComposableElementOp<T>> StridedView<'a, T, Op> {
643 pub fn transpose_2d(&self) -> Result<StridedView<'a, T, Op::ComposeTranspose>> {
647 if self.dims().len() != 2 {
648 return Err(StridedError::RankMismatch(self.dims().len(), 2));
649 }
650 Ok(from_meta(
651 self.data,
652 &[self.dims()[1], self.dims()[0]],
653 &[self.strides()[1], self.strides()[0]],
654 self.offset,
655 ))
656 }
657
658 pub fn adjoint_2d(&self) -> Result<StridedView<'a, T, Op::ComposeAdjoint>> {
662 if self.dims().len() != 2 {
663 return Err(StridedError::RankMismatch(self.dims().len(), 2));
664 }
665 Ok(from_meta(
666 self.data,
667 &[self.dims()[1], self.dims()[0]],
668 &[self.strides()[1], self.strides()[0]],
669 self.offset,
670 ))
671 }
672
673 #[inline]
677 pub fn conj(&self) -> StridedView<'a, T, Op::ComposeConj> {
678 StridedView {
679 ptr: self.ptr,
680 data: self.data,
681 meta: self.meta.clone(),
682 offset: self.offset,
683 _op: PhantomData,
684 }
685 }
686}
687
688impl<'a, T: Copy, Op: ElementOp<T>> StridedView<'a, T, Op> {
690 pub fn get(&self, indices: &[usize]) -> T {
697 let offset = indexed_offset(self.dims(), self.strides(), indices, 0);
698 Op::apply(unsafe { *self.ptr.offset(offset) })
699 }
700
701 #[inline]
706 pub unsafe fn get_unchecked(&self, indices: &[usize]) -> T {
707 let mut idx = 0isize;
708 for (i, &index) in indices.iter().enumerate() {
709 idx += index as isize * self.strides()[i];
710 }
711 Op::apply(*self.ptr.offset(idx))
712 }
713}
714
715pub struct StridedViewMut<'a, T> {
724 ptr: *mut T,
725 data: &'a mut [T],
726 meta: ViewMeta,
727 offset: isize,
728}
729
730unsafe impl<T: Send> Send for StridedViewMut<'_, T> {}
731
732impl<T: std::fmt::Debug> std::fmt::Debug for StridedViewMut<'_, T> {
733 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
734 f.debug_struct("StridedViewMut")
735 .field("dims", &self.meta.dims())
736 .field("strides", &self.meta.strides())
737 .field("offset", &self.offset)
738 .finish()
739 }
740}
741
742impl<'a, T> StridedViewMut<'a, T> {
743 #[inline]
745 fn from_meta(data: &'a mut [T], dims: &[usize], strides: &[isize], offset: isize) -> Self {
746 let meta = ViewMeta::from_slices(dims, strides);
747 let ptr = if empty_layout(meta.dims()) {
748 empty_mut_ptr()
749 } else {
750 unsafe { data.as_mut_ptr().offset(offset) }
751 };
752 Self {
753 ptr,
754 data,
755 meta,
756 offset,
757 }
758 }
759
760 #[inline]
776 pub fn new(
777 data: &'a mut [T],
778 dims: &[usize],
779 strides: &[isize],
780 offset: isize,
781 ) -> Result<Self> {
782 validate_bounds(data.len(), dims, strides, offset)?;
783 Ok(Self::from_meta(data, dims, strides, offset))
784 }
785
786 #[inline]
801 pub unsafe fn new_unchecked(
802 data: &'a mut [T],
803 dims: &[usize],
804 strides: &[isize],
805 offset: isize,
806 ) -> Self {
807 Self::from_meta(data, dims, strides, offset)
808 }
809
810 #[inline]
812 pub fn dims(&self) -> &[usize] {
813 self.meta.dims()
814 }
815
816 #[inline]
818 pub fn strides(&self) -> &[isize] {
819 self.meta.strides()
820 }
821
822 #[inline]
824 pub fn offset(&self) -> isize {
825 self.offset
826 }
827
828 #[inline]
830 pub fn ndim(&self) -> usize {
831 self.dims().len()
832 }
833
834 #[inline]
836 pub fn len(&self) -> usize {
837 self.dims().iter().product()
838 }
839
840 #[inline]
842 pub fn is_empty(&self) -> bool {
843 self.dims().iter().any(|&d| d == 0)
844 }
845
846 #[inline]
848 pub fn ptr(&self) -> *const T {
849 self.ptr as *const T
850 }
851
852 #[inline]
854 pub fn as_mut_ptr(&self) -> *mut T {
855 self.ptr
856 }
857
858 #[inline]
860 pub fn data(&self) -> &[T] {
861 &self.data
862 }
863
864 #[inline]
866 pub fn data_mut(&mut self) -> &mut [T] {
867 &mut self.data
868 }
869
870 pub fn permute(self, perm: &[usize]) -> Result<StridedViewMut<'a, T>> {
875 let rank = self.dims().len();
876 if perm.len() != rank {
877 return Err(StridedError::RankMismatch(perm.len(), rank));
878 }
879 let mut seen: tinyvec::TinyVec<[bool; INLINE_RANK]> = tinyvec::TinyVec::new();
880 seen.resize(rank, false);
881 for &p in perm {
882 if p >= rank {
883 return Err(StridedError::InvalidAxis { axis: p, rank });
884 }
885 if seen[p] {
886 return Err(StridedError::InvalidAxis { axis: p, rank });
887 }
888 seen[p] = true;
889 }
890 let new_dims: AxisVec = perm.iter().map(|&p| self.dims()[p]).collect();
891 let new_strides: StrideVec = perm.iter().map(|&p| self.strides()[p]).collect();
892 Ok(Self::from_meta(
893 self.data,
894 &new_dims,
895 &new_strides,
896 self.offset,
897 ))
898 }
899
900 #[inline]
917 pub fn as_view(&self) -> StridedView<'_, T, Identity> {
918 StridedView {
919 ptr: self.ptr as *const T,
920 data: unsafe { std::slice::from_raw_parts(self.data.as_ptr(), self.data.len()) },
921 meta: self.meta.clone(),
922 offset: self.offset,
923 _op: PhantomData,
924 }
925 }
926}
927
928impl<'a, T: Copy> StridedViewMut<'a, T> {
929 pub fn get(&self, indices: &[usize]) -> T {
936 let offset = indexed_offset(self.dims(), self.strides(), indices, 0);
937 unsafe { *self.ptr.offset(offset) }
938 }
939
940 pub fn set(&mut self, indices: &[usize], value: T) {
947 let offset = indexed_offset(self.dims(), self.strides(), indices, 0);
948 unsafe {
949 *self.ptr.offset(offset) = value;
950 }
951 }
952}
953
954pub struct StridedArray<T> {
962 data: Vec<T>,
963 meta: ViewMeta,
964 offset: isize,
965}
966
967impl<T: std::fmt::Debug> std::fmt::Debug for StridedArray<T> {
968 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
969 f.debug_struct("StridedArray")
970 .field("dims", &self.meta.dims())
971 .field("strides", &self.meta.strides())
972 .field("offset", &self.offset)
973 .finish()
974 }
975}
976
977impl<T: Clone> Clone for StridedArray<T> {
978 fn clone(&self) -> Self {
979 Self {
980 data: self.data.clone(),
981 meta: self.meta.clone(),
982 offset: self.offset,
983 }
984 }
985}
986
987impl<T: Clone + Default> StridedArray<T> {
988 pub fn col_major(dims: &[usize]) -> Self {
1003 let total: usize = dims.iter().product();
1004 let data = vec![T::default(); total];
1005 let strides = col_major_strides(dims);
1006 Self {
1007 data,
1008 meta: ViewMeta::from_slices(dims, &strides),
1009 offset: 0,
1010 }
1011 }
1012
1013 pub fn row_major(dims: &[usize]) -> Self {
1028 let total: usize = dims.iter().product();
1029 let data = vec![T::default(); total];
1030 let strides = row_major_strides(dims);
1031 Self {
1032 data,
1033 meta: ViewMeta::from_slices(dims, &strides),
1034 offset: 0,
1035 }
1036 }
1037
1038 pub fn from_fn_col_major(dims: &[usize], mut f: impl FnMut(&[usize]) -> T) -> Self {
1042 let total: usize = dims.iter().product();
1043 let strides = col_major_strides(dims);
1044 let rank = dims.len();
1045 let mut data = Vec::with_capacity(total);
1046 let mut idx: AxisVec = AxisVec::new();
1047 idx.resize(rank, 0usize);
1048 let idx: &mut [usize] = &mut idx[..];
1051 for _ in 0..total {
1052 data.push(f(idx));
1053 for d in 0..rank {
1054 idx[d] += 1;
1055 if idx[d] < dims[d] {
1056 break;
1057 }
1058 idx[d] = 0;
1059 }
1060 }
1061 Self {
1062 data,
1063 meta: ViewMeta::from_slices(dims, &strides),
1064 offset: 0,
1065 }
1066 }
1067
1068 pub fn from_fn_row_major(dims: &[usize], mut f: impl FnMut(&[usize]) -> T) -> Self {
1072 let total: usize = dims.iter().product();
1073 let strides = row_major_strides(dims);
1074 let rank = dims.len();
1075 let mut data = Vec::with_capacity(total);
1076 let mut idx: AxisVec = AxisVec::new();
1077 idx.resize(rank, 0usize);
1078 let idx: &mut [usize] = &mut idx[..];
1080 for _ in 0..total {
1081 data.push(f(idx));
1082 for d in (0..rank).rev() {
1083 idx[d] += 1;
1084 if idx[d] < dims[d] {
1085 break;
1086 }
1087 idx[d] = 0;
1088 }
1089 }
1090 Self {
1091 data,
1092 meta: ViewMeta::from_slices(dims, &strides),
1093 offset: 0,
1094 }
1095 }
1096}
1097
1098impl<T> StridedArray<T> {
1099 pub fn from_parts(
1101 data: Vec<T>,
1102 dims: &[usize],
1103 strides: &[isize],
1104 offset: isize,
1105 ) -> Result<Self> {
1106 validate_bounds(data.len(), dims, strides, offset)?;
1107 Ok(Self {
1108 data,
1109 meta: ViewMeta::from_slices(dims, strides),
1110 offset,
1111 })
1112 }
1113
1114 #[inline]
1116 pub fn dims(&self) -> &[usize] {
1117 self.meta.dims()
1118 }
1119
1120 #[inline]
1122 pub fn strides(&self) -> &[isize] {
1123 self.meta.strides()
1124 }
1125
1126 #[inline]
1128 pub fn ndim(&self) -> usize {
1129 self.dims().len()
1130 }
1131
1132 #[inline]
1134 pub fn len(&self) -> usize {
1135 self.dims().iter().product()
1136 }
1137
1138 #[inline]
1140 pub fn is_empty(&self) -> bool {
1141 self.dims().iter().any(|&d| d == 0)
1142 }
1143
1144 #[inline]
1146 pub fn data(&self) -> &[T] {
1147 &self.data
1148 }
1149
1150 #[inline]
1152 pub fn data_mut(&mut self) -> &mut [T] {
1153 &mut self.data
1154 }
1155
1156 #[inline]
1158 pub fn view(&self) -> StridedView<'_, T> {
1159 let ptr = if self.is_empty() {
1160 empty_const_ptr()
1161 } else {
1162 unsafe { self.data.as_ptr().offset(self.offset) }
1163 };
1164 StridedView {
1165 ptr,
1166 data: &self.data,
1167 meta: self.meta.clone(),
1168 offset: self.offset,
1169 _op: PhantomData,
1170 }
1171 }
1172
1173 #[inline]
1175 pub fn view_mut(&mut self) -> StridedViewMut<'_, T> {
1176 let ptr = if self.is_empty() {
1177 empty_mut_ptr()
1178 } else {
1179 unsafe { self.data.as_mut_ptr().offset(self.offset) }
1180 };
1181 StridedViewMut {
1182 ptr,
1183 data: &mut self.data,
1184 meta: self.meta.clone(),
1185 offset: self.offset,
1186 }
1187 }
1188
1189 pub fn permuted(self, perm: &[usize]) -> Result<Self> {
1194 let rank = self.dims().len();
1195 if perm.len() != rank {
1196 return Err(StridedError::RankMismatch(perm.len(), rank));
1197 }
1198 let mut seen: tinyvec::TinyVec<[bool; INLINE_RANK]> = tinyvec::TinyVec::new();
1199 seen.resize(rank, false);
1200 for &p in perm {
1201 if p >= rank {
1202 return Err(StridedError::InvalidAxis { axis: p, rank });
1203 }
1204 if seen[p] {
1205 return Err(StridedError::InvalidAxis { axis: p, rank });
1206 }
1207 seen[p] = true;
1208 }
1209 let new_dims: AxisVec = perm.iter().map(|&p| self.dims()[p]).collect();
1210 let new_strides: StrideVec = perm.iter().map(|&p| self.strides()[p]).collect();
1211 Ok(Self {
1212 data: self.data,
1213 meta: ViewMeta::from_slices(&new_dims, &new_strides),
1214 offset: self.offset,
1215 })
1216 }
1217
1218 pub fn into_data(self) -> Vec<T> {
1220 self.data
1221 }
1222
1223 pub fn iter(&self) -> std::slice::Iter<'_, T> {
1225 self.data.iter()
1226 }
1227
1228 pub fn iter_mut(&mut self) -> std::slice::IterMut<'_, T> {
1230 self.data.iter_mut()
1231 }
1232}
1233
1234impl<T: Default> StridedArray<T> {
1235 pub fn col_major_from_buffer(mut buf: Vec<T>, dims: &[usize]) -> Self {
1240 let total: usize = dims.iter().product();
1241 if buf.len() >= total {
1242 buf.truncate(total);
1243 } else {
1244 buf.resize_with(total, T::default);
1245 }
1246 for v in buf.iter_mut() {
1248 *v = T::default();
1249 }
1250 let strides = col_major_strides(dims);
1251 Self {
1252 data: buf,
1253 meta: ViewMeta::from_slices(dims, &strides),
1254 offset: 0,
1255 }
1256 }
1257}
1258
1259impl<T: Copy> StridedArray<T> {
1260 pub unsafe fn col_major_uninit(dims: &[usize]) -> Self {
1265 let total: usize = dims.iter().product();
1266 let mut data = Vec::with_capacity(total);
1267 data.set_len(total);
1268 let strides = col_major_strides(dims);
1269 Self {
1270 data,
1271 meta: ViewMeta::from_slices(dims, &strides),
1272 offset: 0,
1273 }
1274 }
1275
1276 pub unsafe fn col_major_from_buffer_uninit(mut buf: Vec<T>, dims: &[usize]) -> Self {
1281 let total: usize = dims.iter().product();
1282 if buf.capacity() < total {
1283 buf.reserve(total - buf.len());
1284 }
1285 buf.set_len(total);
1286 let strides = col_major_strides(dims);
1287 Self {
1288 data: buf,
1289 meta: ViewMeta::from_slices(dims, &strides),
1290 offset: 0,
1291 }
1292 }
1293}
1294
1295impl<T: Copy> StridedArray<T> {
1296 pub fn get(&self, indices: &[usize]) -> T {
1303 self.view().get(indices)
1304 }
1305
1306 pub fn set(&mut self, indices: &[usize], value: T) {
1313 let offset = indexed_offset(self.dims(), self.strides(), indices, self.offset);
1314 self.data[offset as usize] = value;
1315 }
1316}
1317
1318impl<T: Copy> Index<&[usize]> for StridedArray<T> {
1319 type Output = T;
1320
1321 fn index(&self, indices: &[usize]) -> &T {
1322 let offset = indexed_offset(self.dims(), self.strides(), indices, self.offset);
1323 &self.data[offset as usize]
1324 }
1325}
1326
1327impl<T: Copy> IndexMut<&[usize]> for StridedArray<T> {
1328 fn index_mut(&mut self, indices: &[usize]) -> &mut T {
1329 let offset = indexed_offset(self.dims(), self.strides(), indices, self.offset);
1330 &mut self.data[offset as usize]
1331 }
1332}
1333
1334#[cfg(test)]
1339mod tests {
1340 use super::*;
1341
1342 #[test]
1343 fn empty_views_use_dangling_base_pointers_for_extreme_offsets() {
1344 let dims = [0usize];
1345 let strides = [1isize];
1346 let data: [f64; 0] = [];
1347 let view = StridedView::<f64>::new(&data, &dims, &strides, isize::MAX).unwrap();
1348 assert_eq!(view.ptr(), empty_const_ptr());
1349
1350 let mut data: [f64; 0] = [];
1351 let view = StridedViewMut::new(&mut data, &dims, &strides, isize::MAX).unwrap();
1352 assert_eq!(view.ptr(), empty_const_ptr());
1353 assert_eq!(view.as_mut_ptr(), empty_mut_ptr());
1354
1355 let array =
1356 StridedArray::<f64>::from_parts(Vec::new(), &dims, &strides, isize::MAX).unwrap();
1357 assert_eq!(array.view().ptr(), empty_const_ptr());
1358
1359 let mut array =
1360 StridedArray::<f64>::from_parts(Vec::new(), &dims, &strides, isize::MAX).unwrap();
1361 let view = array.view_mut();
1362 assert_eq!(view.ptr(), empty_const_ptr());
1363 assert_eq!(view.as_mut_ptr(), empty_mut_ptr());
1364 }
1365 use num_complex::Complex64;
1366
1367 #[test]
1368 fn test_col_major_strides() {
1369 assert_eq!(col_major_strides(&[3, 4]).as_slice(), &[1, 3]);
1370 assert_eq!(col_major_strides(&[2, 3, 4]).as_slice(), &[1, 2, 6]);
1371 }
1372
1373 #[test]
1374 fn test_row_major_strides() {
1375 assert_eq!(row_major_strides(&[3, 4]).as_slice(), &[4, 1]);
1376 assert_eq!(row_major_strides(&[2, 3, 4]).as_slice(), &[12, 4, 1]);
1377 }
1378
1379 #[test]
1380 fn test_strided_view_new() {
1381 let data = vec![1.0, 2.0, 3.0, 4.0, 5.0, 6.0];
1382 let view = StridedView::<f64>::new(&data, &[2, 3], &[3, 1], 0).unwrap();
1383 assert_eq!(view.ndim(), 2);
1384 assert_eq!(view.dims(), &[2, 3]);
1385 assert_eq!(view.strides(), &[3, 1]);
1386 assert_eq!(view.len(), 6);
1387 }
1388
1389 #[test]
1390 fn test_strided_view_get() {
1391 let data = vec![1.0, 2.0, 3.0, 4.0, 5.0, 6.0];
1392 let view = StridedView::<f64>::new(&data, &[2, 3], &[3, 1], 0).unwrap();
1393 assert_eq!(view.get(&[0, 0]), 1.0);
1394 assert_eq!(view.get(&[0, 1]), 2.0);
1395 assert_eq!(view.get(&[0, 2]), 3.0);
1396 assert_eq!(view.get(&[1, 0]), 4.0);
1397 assert_eq!(view.get(&[1, 2]), 6.0);
1398 }
1399
1400 #[test]
1401 fn test_strided_view_col_major() {
1402 let data = vec![1.0, 2.0, 3.0, 4.0, 5.0, 6.0];
1404 let view = StridedView::<f64>::new(&data, &[2, 3], &[1, 2], 0).unwrap();
1405 assert_eq!(view.get(&[0, 0]), 1.0); assert_eq!(view.get(&[1, 0]), 2.0); assert_eq!(view.get(&[0, 1]), 3.0); assert_eq!(view.get(&[1, 1]), 4.0); assert_eq!(view.get(&[0, 2]), 5.0); assert_eq!(view.get(&[1, 2]), 6.0); }
1412
1413 #[test]
1414 fn test_strided_view_permute() {
1415 let data = vec![1.0, 2.0, 3.0, 4.0, 5.0, 6.0];
1416 let view = StridedView::<f64>::new(&data, &[2, 3], &[3, 1], 0).unwrap();
1417 let perm = view.permute(&[1, 0]).unwrap();
1418 assert_eq!(perm.dims(), &[3, 2]);
1419 assert_eq!(perm.strides(), &[1, 3]);
1420 assert_eq!(perm.get(&[0, 0]), 1.0);
1421 assert_eq!(perm.get(&[1, 0]), 2.0);
1422 assert_eq!(perm.get(&[0, 1]), 4.0);
1423 }
1424
1425 #[test]
1426 fn test_strided_view_transpose_2d() {
1427 let data = vec![1.0, 2.0, 3.0, 4.0, 5.0, 6.0];
1428 let view = StridedView::<f64>::new(&data, &[2, 3], &[3, 1], 0).unwrap();
1429 let t = view.transpose_2d().unwrap();
1430 assert_eq!(t.dims(), &[3, 2]);
1431 assert_eq!(t.get(&[0, 0]), 1.0);
1432 assert_eq!(t.get(&[1, 0]), 2.0);
1433 assert_eq!(t.get(&[0, 1]), 4.0);
1434 }
1435
1436 #[test]
1437 fn test_strided_view_conj() {
1438 let data = vec![Complex64::new(1.0, 2.0), Complex64::new(3.0, 4.0)];
1439 let view = StridedView::<Complex64>::new(&data, &[2], &[1], 0).unwrap();
1440 let c = view.conj();
1441 assert_eq!(c.get(&[0]), Complex64::new(1.0, -2.0));
1442 assert_eq!(c.get(&[1]), Complex64::new(3.0, -4.0));
1443 }
1444
1445 #[test]
1446 fn test_strided_view_adjoint_2d() {
1447 let data = vec![
1448 Complex64::new(1.0, 2.0),
1449 Complex64::new(3.0, 4.0),
1450 Complex64::new(5.0, 6.0),
1451 Complex64::new(7.0, 8.0),
1452 ];
1453 let view = StridedView::<Complex64>::new(&data, &[2, 2], &[2, 1], 0).unwrap();
1455 let adj = view.adjoint_2d().unwrap();
1456 assert_eq!(adj.dims(), &[2, 2]);
1457 assert_eq!(adj.get(&[0, 0]), Complex64::new(1.0, -2.0));
1459 assert_eq!(adj.get(&[1, 0]), Complex64::new(3.0, -4.0));
1460 assert_eq!(adj.get(&[0, 1]), Complex64::new(5.0, -6.0));
1461 }
1462
1463 #[test]
1464 fn test_strided_view_broadcast() {
1465 let data = vec![1.0, 2.0, 3.0];
1466 let view = StridedView::<f64>::new(&data, &[1, 3], &[3, 1], 0).unwrap();
1467 let broad = view.broadcast(&[4, 3]).unwrap();
1468 assert_eq!(broad.dims(), &[4, 3]);
1469 for i in 0..4 {
1470 assert_eq!(broad.get(&[i, 0]), 1.0);
1471 assert_eq!(broad.get(&[i, 1]), 2.0);
1472 assert_eq!(broad.get(&[i, 2]), 3.0);
1473 }
1474 }
1475
1476 #[test]
1477 fn test_strided_view_mut() {
1478 let mut data = vec![0.0; 6];
1479 {
1480 let mut view = StridedViewMut::<f64>::new(&mut data, &[2, 3], &[3, 1], 0).unwrap();
1481 view.set(&[0, 0], 1.0);
1482 view.set(&[1, 2], 6.0);
1483 }
1484 assert_eq!(data[0], 1.0);
1485 assert_eq!(data[5], 6.0);
1486 }
1487
1488 #[test]
1489 fn test_strided_view_mut_as_view() {
1490 let mut data = vec![1.0, 2.0, 3.0];
1491 let vm = StridedViewMut::<f64>::new(&mut data, &[3], &[1], 0).unwrap();
1492 let v = vm.as_view();
1493 assert_eq!(v.get(&[0]), 1.0);
1494 assert_eq!(v.get(&[2]), 3.0);
1495 }
1496
1497 #[test]
1498 fn test_strided_tensor_col_major() {
1499 let t = StridedArray::<f64>::from_fn_col_major(&[2, 3], |idx| (idx[0] * 3 + idx[1]) as f64);
1500 assert_eq!(t.dims(), &[2, 3]);
1501 assert_eq!(t.strides(), &[1, 2]); assert_eq!(t.get(&[0, 0]), 0.0);
1503 assert_eq!(t.get(&[1, 0]), 3.0);
1504 assert_eq!(t.get(&[0, 1]), 1.0);
1505 assert_eq!(t.get(&[1, 2]), 5.0);
1506 }
1507
1508 #[test]
1509 fn test_strided_tensor_row_major() {
1510 let t = StridedArray::<f64>::from_fn_row_major(&[2, 3], |idx| (idx[0] * 3 + idx[1]) as f64);
1511 assert_eq!(t.dims(), &[2, 3]);
1512 assert_eq!(t.strides(), &[3, 1]); assert_eq!(t.get(&[0, 0]), 0.0);
1514 assert_eq!(t.get(&[0, 1]), 1.0);
1515 assert_eq!(t.get(&[1, 0]), 3.0);
1516 assert_eq!(t.get(&[1, 2]), 5.0);
1517 }
1518
1519 #[test]
1520 fn test_strided_tensor_view() {
1521 let t =
1522 StridedArray::<f64>::from_fn_col_major(&[2, 3], |idx| (idx[0] * 10 + idx[1]) as f64);
1523 let v = t.view();
1524 assert_eq!(v.get(&[0, 0]), 0.0);
1525 assert_eq!(v.get(&[1, 0]), 10.0);
1526 assert_eq!(v.get(&[0, 2]), 2.0);
1527 }
1528
1529 #[test]
1530 fn test_strided_tensor_view_mut() {
1531 let mut t = StridedArray::<f64>::col_major(&[2, 3]);
1532 {
1533 let mut vm = t.view_mut();
1534 vm.set(&[1, 2], 42.0);
1535 }
1536 assert_eq!(t.get(&[1, 2]), 42.0);
1537 }
1538
1539 #[test]
1540 fn test_strided_tensor_index() {
1541 let t =
1542 StridedArray::<f64>::from_fn_row_major(&[3, 4], |idx| (idx[0] * 10 + idx[1]) as f64);
1543 assert_eq!(t[&[0usize, 0] as &[usize]], 0.0);
1544 assert_eq!(t[&[2usize, 3] as &[usize]], 23.0);
1545 }
1546
1547 #[test]
1548 fn test_strided_tensor_index_mut() {
1549 let mut t = StridedArray::<f64>::row_major(&[2, 3]);
1550 t[&[1usize, 2] as &[usize]] = 99.0;
1551 assert_eq!(t.get(&[1, 2]), 99.0);
1552 }
1553
1554 #[test]
1555 fn test_validate_bounds_ok() {
1556 assert!(validate_bounds(6, &[2, 3], &[3, 1], 0).is_ok());
1557 assert!(validate_bounds(6, &[2, 3], &[1, 2], 0).is_ok());
1558 }
1559
1560 #[test]
1561 fn test_validate_bounds_out_of_range() {
1562 assert!(validate_bounds(5, &[2, 3], &[3, 1], 0).is_err());
1563 }
1564
1565 #[test]
1566 fn test_validate_bounds_empty() {
1567 assert!(validate_bounds(0, &[0, 3], &[3, 1], 0).is_ok());
1568 }
1569
1570 #[test]
1571 fn test_validate_bounds_with_offset() {
1572 assert!(validate_bounds(7, &[2, 3], &[3, 1], 1).is_ok());
1573 assert!(validate_bounds(6, &[2, 3], &[3, 1], 1).is_err());
1574 }
1575
1576 #[test]
1577 fn test_strided_tensor_3d() {
1578 let t = StridedArray::<f64>::from_fn_col_major(&[2, 3, 4], |idx| {
1579 (idx[0] * 100 + idx[1] * 10 + idx[2]) as f64
1580 });
1581 assert_eq!(t.ndim(), 3);
1582 assert_eq!(t.strides(), &[1, 2, 6]); assert_eq!(t.get(&[0, 0, 0]), 0.0);
1584 assert_eq!(t.get(&[1, 0, 0]), 100.0);
1585 assert_eq!(t.get(&[0, 1, 0]), 10.0);
1586 assert_eq!(t.get(&[0, 0, 1]), 1.0);
1587 assert_eq!(t.get(&[1, 2, 3]), 123.0);
1588 }
1589
1590 #[test]
1591 fn test_diagonal_view_2d() {
1592 let data: Vec<f64> = (0..9).map(|x| x as f64).collect();
1595 let view = StridedView::<f64>::new(&data, &[3, 3], &[3, 1], 0).unwrap();
1596 let diag = view.diagonal_view(&[(0, 1)]).unwrap();
1597 assert_eq!(diag.dims(), &[3]);
1598 assert_eq!(diag.strides(), &[4]);
1599 assert_eq!(diag.get(&[0]), 0.0); assert_eq!(diag.get(&[1]), 4.0); assert_eq!(diag.get(&[2]), 8.0); }
1603
1604 #[test]
1605 fn test_diagonal_view_3d_adjacent() {
1606 let data: Vec<f64> = (0..12).map(|x| x as f64).collect();
1609 let view = StridedView::<f64>::new(&data, &[2, 2, 3], &[6, 3, 1], 0).unwrap();
1610 let diag = view.diagonal_view(&[(0, 1)]).unwrap();
1611 assert_eq!(diag.dims(), &[2, 3]);
1612 assert_eq!(diag.strides(), &[9, 1]);
1613 assert_eq!(diag.get(&[0, 0]), 0.0);
1614 assert_eq!(diag.get(&[0, 2]), 2.0);
1615 assert_eq!(diag.get(&[1, 0]), 9.0);
1616 }
1617
1618 #[test]
1619 fn test_diagonal_view_3d_non_adjacent() {
1620 let data: Vec<f64> = (0..12).map(|x| x as f64).collect();
1623 let view = StridedView::<f64>::new(&data, &[2, 3, 2], &[6, 2, 1], 0).unwrap();
1624 let diag = view.diagonal_view(&[(0, 2)]).unwrap();
1625 assert_eq!(diag.dims(), &[2, 3]);
1626 assert_eq!(diag.strides(), &[7, 2]);
1627 assert_eq!(diag.get(&[0, 0]), 0.0);
1628 assert_eq!(diag.get(&[0, 1]), 2.0);
1629 assert_eq!(diag.get(&[1, 0]), 7.0);
1630 assert_eq!(diag.get(&[1, 2]), 11.0);
1631 }
1632
1633 #[test]
1634 fn test_diagonal_view_two_pairs() {
1635 let data: Vec<f64> = (0..36).map(|x| x as f64).collect();
1637 let view = StridedView::<f64>::new(&data, &[2, 3, 2, 3], &[18, 6, 3, 1], 0).unwrap();
1638 let diag = view.diagonal_view(&[(0, 2), (1, 3)]).unwrap();
1639 assert_eq!(diag.dims(), &[2, 3]);
1640 assert_eq!(diag.strides(), &[21, 7]);
1641 assert_eq!(diag.get(&[0, 0]), 0.0);
1642 assert_eq!(diag.get(&[1, 1]), 28.0);
1643 }
1644
1645 #[test]
1646 fn test_diagonal_view_pairs_sharing_a_high_axis_fuse_all_three() {
1647 let data: Vec<f64> = (0..8).map(|x| x as f64).collect();
1651 let view = StridedView::<f64>::new(&data, &[2, 2, 2], &[4, 2, 1], 0).unwrap();
1652 let diag = view.diagonal_view(&[(0, 2), (1, 2)]).unwrap();
1653 assert_eq!(diag.dims(), &[2]);
1654 assert_eq!(diag.strides(), &[7]);
1655 assert_eq!(diag.get(&[1]), 7.0);
1656 }
1657
1658 #[test]
1659 fn test_diagonal_view_repeated_pair_is_idempotent() {
1660 let data: Vec<f64> = (0..8).map(|x| x as f64).collect();
1663 let view = StridedView::<f64>::new(&data, &[2, 2, 2], &[4, 2, 1], 0).unwrap();
1664 let once = view.diagonal_view(&[(0, 1)]).unwrap();
1665 let twice = view.diagonal_view(&[(0, 1), (1, 0)]).unwrap();
1666 assert_eq!(twice.dims(), once.dims());
1667 assert_eq!(twice.strides(), once.strides());
1668 assert_eq!(twice.strides(), &[6, 1]);
1669 }
1670
1671 #[test]
1672 fn test_diagonal_view_chained_pairs_are_order_independent() {
1673 let data: Vec<f64> = (0..27).map(|x| x as f64).collect();
1677 let view = StridedView::<f64>::new(&data, &[3, 3, 3], &[1, 3, 9], 0).unwrap();
1678 for pairs in [
1679 [(0, 1), (1, 2)],
1680 [(1, 2), (0, 1)],
1681 [(2, 1), (1, 0)],
1682 [(0, 2), (2, 1)],
1683 ] {
1684 let diag = view.diagonal_view(&pairs).unwrap();
1685 assert_eq!(diag.dims(), &[3], "{pairs:?}");
1686 assert_eq!(diag.strides(), &[13], "{pairs:?}");
1687 assert_eq!(diag.get(&[2]), 26.0, "{pairs:?}");
1688 }
1689 }
1690
1691 #[test]
1692 fn test_diagonal_view_chained_pairs_keep_free_axes_in_order() {
1693 let dims = [3usize, 4, 2, 3];
1696 let strides = [1isize, 3, 12, 24];
1697 let data: Vec<f64> = (0..72).map(|x| x as f64).collect();
1698 let view = StridedView::<f64>::new(&data, &dims, &strides, 0).unwrap();
1699 let a = view.diagonal_view(&[(2, 3), (0, 2)]).unwrap();
1700 let b = view.diagonal_view(&[(0, 2), (2, 3)]).unwrap();
1701 for diag in [a, b] {
1702 assert_eq!(diag.dims(), &[2, 4]);
1703 assert_eq!(diag.strides(), &[37, 3]);
1704 assert_eq!(diag.get(&[1, 2]), 43.0);
1705 }
1706 }
1707
1708 #[test]
1709 fn test_diagonal_view_fuses_a_shared_low_axis_in_bounds() {
1710 let data: Vec<f64> = (0..8).map(|x| x as f64).collect();
1713 let view = StridedView::<f64>::new(&data, &[2, 2, 2], &[4, 2, 1], 0).unwrap();
1714 let diag = view.diagonal_view(&[(0, 1), (0, 2)]).unwrap();
1715 assert_eq!(diag.dims(), &[2]);
1716 assert_eq!(diag.strides(), &[7]);
1717 assert_eq!(diag.get(&[0]), 0.0);
1718 assert_eq!(diag.get(&[1]), 7.0);
1719 }
1720
1721 #[test]
1722 fn test_custom_type_without_element_op_apply() {
1723 #[derive(Debug, Clone, Copy, PartialEq)]
1726 struct MyScalar(f64);
1727
1728 impl Default for MyScalar {
1729 fn default() -> Self {
1730 MyScalar(0.0)
1731 }
1732 }
1733
1734 let data = vec![MyScalar(1.0), MyScalar(2.0), MyScalar(3.0), MyScalar(4.0)];
1736 let arr = StridedArray::from_parts(data, &[2, 2], &[2, 1], 0).unwrap();
1737
1738 assert_eq!(arr.get(&[0, 0]), MyScalar(1.0));
1740 assert_eq!(arr.get(&[1, 0]), MyScalar(3.0));
1741
1742 let view: StridedView<MyScalar> = arr.view();
1744 assert_eq!(view.get(&[0, 1]), MyScalar(2.0));
1745
1746 let perm = view.permute(&[1, 0]).unwrap();
1748 assert_eq!(perm.get(&[0, 0]), MyScalar(1.0));
1749 assert_eq!(perm.get(&[0, 1]), MyScalar(3.0)); }
1751
1752 #[test]
1753 #[should_panic(expected = "wrong number of indices")]
1754 fn test_index_rejects_a_short_index() {
1755 let arr = StridedArray::from_parts(vec![0.0f64; 4], &[2, 2], &[2, 1], 0).unwrap();
1756 let _ = arr[&[1][..]];
1758 }
1759
1760 #[test]
1761 #[should_panic(expected = "wrong number of indices")]
1762 fn test_view_get_rejects_a_short_index() {
1763 let data = vec![0.0f64; 4];
1764 let view = StridedView::<f64>::new(&data, &[2, 2], &[2, 1], 0).unwrap();
1765 let _ = view.get(&[1]);
1766 }
1767
1768 #[test]
1769 #[should_panic(expected = "out of bounds")]
1770 fn test_view_set_rejects_an_out_of_bounds_index() {
1771 let mut data = vec![0.0f64; 4];
1772 let mut view = StridedViewMut::<f64>::new(&mut data, &[2, 2], &[2, 1], 0).unwrap();
1773 view.set(&[2, 0], 1.0);
1774 }
1775}