1use std::borrow::Cow;
2use std::fmt::Debug;
3use std::hash::{Hash, Hasher};
4use std::mem::MaybeUninit;
5use std::ops::{Index, IndexMut, Range};
6use std::sync::Arc;
7
8use crate::assume_init::AssumeInit;
9use crate::copy::{
10 copy_into, copy_into_slice, copy_into_uninit, copy_range_into_slice, map_into_slice,
11};
12use crate::errors::{DimensionError, ExpandError, FromDataError, ReshapeError, SliceError};
13use crate::iterators::{
14 AxisChunks, AxisChunksMut, AxisIter, AxisIterMut, InnerIter, InnerIterMut, Iter, IterMut,
15 Lanes, LanesMut, for_each_mut,
16};
17use crate::layout::{
18 AsIndex, AsShape, BroadcastLayout, DynLayout, FromShape, InsertDim, IntoLayout, Layout,
19 LayoutExt, MatrixLayout, MutLayout, NdLayout, OverlapPolicy, RemoveDim, ResizeLayout,
20 SizeArray, SliceWith, TrustedLayout,
21};
22use crate::overlap::may_have_internal_overlap;
23use crate::slice_range::{IntoSliceItems, SliceItem};
24use crate::storage::{
25 Alloc, CowData, GlobalAlloc, IntoStorage, Storage, StorageMut, ViewData, ViewMutData,
26};
27use crate::type_num::IndexCount;
28use crate::{Contiguous, RandomSource};
29
30pub struct TensorBase<S: Storage, L: Layout> {
40 data: S,
41
42 layout: L,
52}
53
54pub trait AsView: Layout {
72 type Elem;
74
75 type Layout: Clone + for<'a> Layout<Index<'a> = Self::Index<'a>>;
78
79 fn view(&self) -> TensorBase<ViewData<'_, Self::Elem>, Self::Layout>;
81
82 fn layout(&self) -> &Self::Layout;
84
85 fn as_cow(&self) -> TensorBase<CowData<'_, Self::Elem>, Self::Layout>
91 where
92 [Self::Elem]: ToOwned,
93 {
94 self.view().as_cow()
95 }
96
97 fn as_dyn(&self) -> TensorBase<ViewData<'_, Self::Elem>, DynLayout> {
99 self.view().as_dyn()
100 }
101
102 fn axis_chunks(&self, dim: usize, chunk_size: usize) -> AxisChunks<'_, Self::Elem, Self::Layout>
104 where
105 Self::Layout: MutLayout,
106 {
107 self.view().axis_chunks(dim, chunk_size)
108 }
109
110 fn axis_iter(&self, dim: usize) -> AxisIter<'_, Self::Elem, Self::Layout>
112 where
113 Self::Layout: MutLayout + RemoveDim,
114 {
115 self.view().axis_iter(dim)
116 }
117
118 fn broadcast<S: IntoLayout>(&self, shape: S) -> TensorBase<ViewData<'_, Self::Elem>, S::Layout>
124 where
125 Self::Layout: BroadcastLayout<S::Layout>,
126 {
127 self.view().broadcast(shape)
128 }
129
130 fn try_broadcast<S: IntoLayout>(
132 &self,
133 shape: S,
134 ) -> Result<TensorBase<ViewData<'_, Self::Elem>, S::Layout>, ExpandError>
135 where
136 Self::Layout: BroadcastLayout<S::Layout>,
137 {
138 self.view().try_broadcast(shape)
139 }
140
141 fn copy_into_slice<'a>(&self, dest: &'a mut [MaybeUninit<Self::Elem>]) -> &'a [Self::Elem]
146 where
147 Self::Elem: Copy;
148
149 fn data(&self) -> Option<&[Self::Elem]>;
151
152 fn get<I: AsIndex<Self::Layout>>(&self, index: I) -> Option<&Self::Elem>
155 where
156 Self::Layout: TrustedLayout,
157 {
158 self.view().get(index)
159 }
160
161 unsafe fn get_unchecked<I: AsIndex<Self::Layout>>(&self, index: I) -> &Self::Elem {
168 let view = self.view();
169 unsafe { view.get_unchecked(index) }
170 }
171
172 fn index_axis(
178 &self,
179 axis: usize,
180 index: usize,
181 ) -> TensorBase<ViewData<'_, Self::Elem>, <Self::Layout as RemoveDim>::Output>
182 where
183 Self::Layout: MutLayout + RemoveDim,
184 {
185 self.view().index_axis(axis, index)
186 }
187
188 fn inner_iter<const N: usize>(&self) -> InnerIter<'_, Self::Elem, NdLayout<N>> {
190 self.view().inner_iter()
191 }
192
193 fn inner_iter_dyn(&self, n: usize) -> InnerIter<'_, Self::Elem, DynLayout> {
197 self.view().inner_iter_dyn(n)
198 }
199
200 fn insert_axis(&mut self, index: usize)
202 where
203 Self::Layout: ResizeLayout;
204
205 fn remove_axis(&mut self, index: usize)
210 where
211 Self::Layout: ResizeLayout;
212
213 fn item(&self) -> Option<&Self::Elem> {
215 self.view().item()
216 }
217
218 fn iter(&self) -> Iter<'_, Self::Elem>;
220
221 fn lanes(&self, dim: usize) -> Lanes<'_, Self::Elem>
223 where
224 Self::Layout: RemoveDim,
225 {
226 self.view().lanes(dim)
227 }
228
229 fn map<F, U>(&self, f: F) -> TensorBase<Vec<U>, Self::Layout>
232 where
233 F: Fn(&Self::Elem) -> U,
234 Self::Layout: FromShape,
235 {
236 self.view().map(f)
237 }
238
239 fn map_in<A: Alloc, F, U>(&self, alloc: A, f: F) -> TensorBase<Vec<U>, Self::Layout>
241 where
242 F: Fn(&Self::Elem) -> U,
243 Self::Layout: FromShape,
244 {
245 self.view().map_in(alloc, f)
246 }
247
248 fn merge_axes(&mut self)
254 where
255 Self::Layout: ResizeLayout;
256
257 fn move_axis(&mut self, from: usize, to: usize)
262 where
263 Self::Layout: MutLayout;
264
265 fn nd_view<const N: usize>(&self) -> TensorBase<ViewData<'_, Self::Elem>, NdLayout<N>> {
270 self.view().nd_view()
271 }
272
273 fn permute(&mut self, order: Self::Index<'_>)
275 where
276 Self::Layout: MutLayout;
277
278 fn permuted(&self, order: Self::Index<'_>) -> TensorBase<ViewData<'_, Self::Elem>, Self::Layout>
280 where
281 Self::Layout: MutLayout,
282 {
283 self.view().permuted(order)
284 }
285
286 fn reshaped<S: Copy + IntoLayout>(
301 &self,
302 shape: S,
303 ) -> TensorBase<CowData<'_, Self::Elem>, S::Layout>
304 where
305 Self::Elem: Clone,
306 {
307 self.view().reshaped(shape)
308 }
309
310 fn reshaped_in<A: Alloc, S: Copy + IntoLayout>(
313 &self,
314 alloc: A,
315 shape: S,
316 ) -> TensorBase<CowData<'_, Self::Elem>, S::Layout>
317 where
318 Self::Elem: Clone,
319 {
320 self.view().reshaped_in(alloc, shape)
321 }
322
323 fn transpose(&mut self)
325 where
326 Self::Layout: MutLayout;
327
328 fn transposed(&self) -> TensorBase<ViewData<'_, Self::Elem>, Self::Layout>
330 where
331 Self::Layout: MutLayout,
332 {
333 self.view().transposed()
334 }
335
336 #[allow(clippy::type_complexity)]
352 fn slice<R: IntoSliceItems + IndexCount>(
353 &self,
354 range: R,
355 ) -> TensorBase<ViewData<'_, Self::Elem>, <Self::Layout as SliceWith<R, R::Count>>::Layout>
356 where
357 Self::Layout: SliceWith<R, R::Count>,
358 {
359 self.view().slice(range)
360 }
361
362 fn slice_axis(
364 &self,
365 axis: usize,
366 range: Range<usize>,
367 ) -> TensorBase<ViewData<'_, Self::Elem>, Self::Layout>
368 where
369 Self::Layout: MutLayout,
370 {
371 self.view().slice_axis(axis, range)
372 }
373
374 #[allow(clippy::type_complexity)]
377 fn try_slice<R: IntoSliceItems + IndexCount>(
378 &self,
379 range: R,
380 ) -> Result<
381 TensorBase<ViewData<'_, Self::Elem>, <Self::Layout as SliceWith<R, R::Count>>::Layout>,
382 SliceError,
383 >
384 where
385 Self::Layout: SliceWith<R, R::Count>,
386 {
387 self.view().try_slice(range)
388 }
389
390 #[allow(clippy::type_complexity)]
395 fn slice_copy<R: Clone + IntoSliceItems + IndexCount>(
396 &self,
397 range: R,
398 ) -> TensorBase<Vec<Self::Elem>, <Self::Layout as SliceWith<R, R::Count>>::Layout>
399 where
400 Self::Elem: Clone,
401 Self::Layout: SliceWith<
402 R,
403 R::Count,
404 Layout: FromShape + for<'a> Layout<Shape<'a>: TryFrom<&'a [usize], Error: Debug>>,
405 >,
406 {
407 self.slice_copy_in(GlobalAlloc::new(), range)
408 }
409
410 #[allow(clippy::type_complexity)]
412 fn slice_copy_in<A: Alloc, R: Clone + IntoSliceItems + IndexCount>(
413 &self,
414 pool: A,
415 range: R,
416 ) -> TensorBase<Vec<Self::Elem>, <Self::Layout as SliceWith<R, R::Count>>::Layout>
417 where
418 Self::Elem: Clone,
419 Self::Layout: SliceWith<
420 R,
421 R::Count,
422 Layout: FromShape + for<'a> Layout<Shape<'a>: TryFrom<&'a [usize], Error: Debug>>,
423 >,
424 {
425 if let Ok(slice_view) = self.try_slice(range.clone()) {
430 return slice_view.to_tensor_in(pool);
431 }
432
433 let items = range.into_slice_items();
434 let sliced_shape: Vec<_> = items
435 .as_ref()
436 .iter()
437 .copied()
438 .enumerate()
439 .filter_map(|(dim, item)| match item {
440 SliceItem::Index(_) => None,
441 SliceItem::Range(range) => Some(range.index_range(self.size(dim)).steps()),
442 })
443 .collect();
444 let sliced_len = sliced_shape.iter().product();
445 let mut sliced_data = pool.alloc(sliced_len);
446
447 copy_range_into_slice(
448 self.as_dyn(),
449 &mut sliced_data.spare_capacity_mut()[..sliced_len],
450 items.as_ref(),
451 );
452
453 unsafe {
455 sliced_data.set_len(sliced_len);
456 }
457
458 let sliced_shape = sliced_shape.as_slice().try_into().expect("slice failed");
459
460 TensorBase::from_data(sliced_shape, sliced_data)
461 }
462
463 fn squeezed(&self) -> TensorView<'_, Self::Elem>
465 where
466 Self::Layout: MutLayout,
467 {
468 self.view().squeezed()
469 }
470
471 fn to_vec(&self) -> Vec<Self::Elem>
474 where
475 Self::Elem: Clone;
476
477 fn to_vec_in<A: Alloc>(&self, alloc: A) -> Vec<Self::Elem>
479 where
480 Self::Elem: Clone;
481
482 fn to_contiguous(&self) -> Contiguous<TensorBase<CowData<'_, Self::Elem>, Self::Layout>>
491 where
492 Self::Elem: Clone,
493 Self::Layout: FromShape,
494 {
495 self.view().to_contiguous()
496 }
497
498 fn to_contiguous_in<A: Alloc>(
501 &self,
502 alloc: A,
503 ) -> Contiguous<TensorBase<CowData<'_, Self::Elem>, Self::Layout>>
504 where
505 Self::Elem: Clone,
506 Self::Layout: FromShape,
507 {
508 self.view().to_contiguous_in(alloc)
509 }
510
511 fn to_shape<S: IntoLayout>(&self, shape: S) -> TensorBase<Vec<Self::Elem>, S::Layout>
513 where
514 Self::Elem: Clone;
515
516 fn to_slice(&self) -> Cow<'_, [Self::Elem]>
523 where
524 Self::Elem: Clone,
525 {
526 self.view().to_slice()
527 }
528
529 fn to_tensor(&self) -> TensorBase<Vec<Self::Elem>, Self::Layout>
531 where
532 Self::Elem: Clone,
533 Self::Layout: FromShape,
534 {
535 self.to_tensor_in(GlobalAlloc::new())
536 }
537
538 fn to_tensor_in<A: Alloc>(&self, alloc: A) -> TensorBase<Vec<Self::Elem>, Self::Layout>
540 where
541 Self::Elem: Clone,
542 Self::Layout: FromShape,
543 {
544 TensorBase::from_data(self.layout().shape(), self.to_vec_in(alloc))
545 }
546
547 fn weakly_checked_view(&self) -> WeaklyCheckedView<ViewData<'_, Self::Elem>, Self::Layout> {
550 self.view().weakly_checked_view()
551 }
552}
553
554impl<S: Storage, L: Layout> TensorBase<S, L> {
555 #[track_caller]
559 pub fn from_data<D: IntoStorage<Output = S>>(shape: L::Shape<'_>, data: D) -> TensorBase<S, L>
560 where
561 L: FromShape,
562 for<'a> L::Shape<'a>: Clone,
563 {
564 let data = data.into_storage();
565 let len = data.len();
566 match Self::try_from_data(shape.clone(), data) {
567 Ok(data) => data,
568 Err(_) => panic!("data length {} does not match shape {:?}", len, shape),
569 }
570 }
571
572 pub fn try_from_data<D: IntoStorage<Output = S>>(
576 shape: L::Shape<'_>,
577 data: D,
578 ) -> Result<TensorBase<S, L>, FromDataError>
579 where
580 L: FromShape,
581 {
582 let data = data.into_storage();
583 let layout = L::from_shape(shape);
584 if layout.min_data_len() != data.len() {
585 return Err(FromDataError::StorageLengthMismatch);
586 }
587 Ok(TensorBase { data, layout })
588 }
589
590 pub fn from_storage_and_layout(data: S, layout: L) -> TensorBase<S, L> {
595 assert!(data.len() >= layout.min_data_len());
596 assert!(!S::MUTABLE || !may_have_internal_overlap(layout.shape(), layout.strides()));
597 TensorBase { data, layout }
598 }
599
600 pub(crate) unsafe fn from_storage_and_layout_unchecked(data: S, layout: L) -> TensorBase<S, L> {
608 debug_assert!(data.len() >= layout.min_data_len());
609 debug_assert!(!S::MUTABLE || !may_have_internal_overlap(layout.shape(), layout.strides()));
610 TensorBase { data, layout }
611 }
612
613 pub fn from_data_with_strides<D: IntoStorage<Output = S>>(
621 shape: L::Shape<'_>,
622 data: D,
623 strides: L::Strides<'_>,
624 ) -> Result<TensorBase<S, L>, FromDataError>
625 where
626 L: MutLayout,
627 {
628 let layout = L::from_shape_and_strides(shape, strides, OverlapPolicy::DisallowOverlap)?;
629 let data = data.into_storage();
630 if layout.min_data_len() > data.len() {
631 return Err(FromDataError::StorageTooShort);
632 }
633 Ok(TensorBase { data, layout })
634 }
635
636 pub fn into_dyn(self) -> TensorBase<S, DynLayout>
639 where
640 L: Into<DynLayout>,
641 {
642 TensorBase {
643 data: self.data,
644 layout: self.layout.into(),
645 }
646 }
647
648 #[track_caller]
655 pub fn with_new_axis(self, axis: usize) -> TensorBase<S, <L as InsertDim>::Output>
656 where
657 L: InsertDim,
658 {
659 assert!(
660 axis <= self.ndim(),
661 "axis {} is out of bounds for tensor with {} dims",
662 axis,
663 self.ndim()
664 );
665 let layout = self.layout.insert_dim(axis);
666 TensorBase {
667 data: self.data,
668 layout,
669 }
670 }
671
672 #[track_caller]
679 pub fn with_axis_removed(self, axis: usize) -> TensorBase<S, <L as RemoveDim>::Output>
680 where
681 L: RemoveDim,
682 {
683 assert!(
684 axis < self.ndim(),
685 "axis {} is out of bounds for tensor with {} dims",
686 axis,
687 self.ndim()
688 );
689 assert!(
690 self.size(axis) == 1,
691 "cannot remove axis {} of size {}",
692 axis,
693 self.size(axis)
694 );
695 let layout = self.layout.remove_dim(axis);
696 TensorBase {
697 data: self.data,
698 layout,
699 }
700 }
701
702 pub(crate) fn into_storage(self) -> S {
706 self.data
707 }
708
709 fn nd_layout<const N: usize>(&self) -> Result<NdLayout<N>, DimensionError> {
712 if self.ndim() != N {
713 return Err(DimensionError {
714 actual: self.ndim(),
715 expected: N,
716 });
717 }
718 let shape: [usize; N] = std::array::from_fn(|i| self.size(i));
719 let strides: [usize; N] = std::array::from_fn(|i| self.stride(i));
720 let layout = NdLayout::from_shape_and_strides(shape, strides, OverlapPolicy::AllowOverlap)
721 .expect("invalid layout");
722 Ok(layout)
723 }
724
725 pub fn into_rank<const N: usize>(self) -> Result<TensorBase<S, NdLayout<N>>, DimensionError> {
727 let layout = self.nd_layout()?;
728 Ok(TensorBase {
729 data: self.data,
730 layout,
731 })
732 }
733
734 pub fn into_permuted(self, order: L::Index<'_>) -> TensorBase<S, L>
736 where
737 L: MutLayout,
738 {
739 TensorBase {
740 layout: self.layout.permuted(order),
741 data: self.data,
742 }
743 }
744
745 pub fn data_ptr(&self) -> *const S::Elem {
747 self.data.as_ptr()
748 }
749}
750
751impl<S: StorageMut, L: Clone + Layout> TensorBase<S, L> {
752 pub fn axis_iter_mut(&mut self, dim: usize) -> AxisIterMut<'_, S::Elem, L>
755 where
756 L: RemoveDim,
757 {
758 AxisIterMut::new(self.view_mut(), dim)
759 }
760
761 pub fn axis_chunks_mut(
765 &mut self,
766 dim: usize,
767 chunk_size: usize,
768 ) -> AxisChunksMut<'_, S::Elem, L>
769 where
770 L: MutLayout,
771 {
772 AxisChunksMut::new(self.view_mut(), dim, chunk_size)
773 }
774
775 pub fn apply<F: Fn(&S::Elem) -> S::Elem>(&mut self, f: F) {
778 if let Some(data) = self.data_mut() {
779 data.iter_mut().for_each(|x| *x = f(x));
781 } else {
782 for_each_mut(self.as_dyn_mut(), |x| *x = f(x));
783 }
784 }
785
786 pub fn as_dyn_mut(&mut self) -> TensorBase<ViewMutData<'_, S::Elem>, DynLayout> {
788 TensorBase {
789 layout: DynLayout::from(&self.layout),
790 data: self.data.view_mut(),
791 }
792 }
793
794 pub fn copy_from<S2: Storage<Elem = S::Elem>>(&mut self, other: &TensorBase<S2, L>)
798 where
799 S::Elem: Clone,
800 L: Clone,
801 {
802 assert!(
803 self.shape() == other.shape(),
804 "copy dest shape {:?} != src shape {:?}",
805 self.shape(),
806 other.shape()
807 );
808
809 if let Some(dest) = self.data_mut() {
810 if let Some(src) = other.data() {
811 dest.clone_from_slice(src);
812 } else {
813 let uninit_dest: &mut [MaybeUninit<S::Elem>] = unsafe { std::mem::transmute(dest) };
816 for x in &mut *uninit_dest {
817 unsafe { x.assume_init_drop() }
820 }
821
822 copy_into_slice(other.as_dyn(), uninit_dest);
824 }
825 } else {
826 copy_into(other.as_dyn(), self.as_dyn_mut());
827 }
828 }
829
830 pub fn data_mut(&mut self) -> Option<&mut [S::Elem]> {
832 let len = self.layout.min_data_len();
835 let data = self.data.slice_mut(0..len);
836
837 self.layout.is_contiguous().then(|| unsafe {
838 data.to_slice_mut()
840 })
841 }
842
843 pub fn index_axis_mut(
849 &mut self,
850 axis: usize,
851 index: usize,
852 ) -> TensorBase<ViewMutData<'_, S::Elem>, <L as RemoveDim>::Output>
853 where
854 L: MutLayout + RemoveDim,
855 {
856 let (offsets, layout) = self.layout.index_axis(axis, index);
857 TensorBase {
858 data: self.data.slice_mut(offsets),
859 layout,
860 }
861 }
862
863 pub fn storage_mut(&mut self) -> ViewMutData<'_, S::Elem> {
865 self.data.view_mut()
866 }
867
868 pub fn fill(&mut self, value: S::Elem)
870 where
871 S::Elem: Clone,
872 {
873 self.apply(|_| value.clone())
874 }
875
876 pub fn get_mut<I: AsIndex<L>>(&mut self, index: I) -> Option<&mut S::Elem>
879 where
880 L: TrustedLayout,
881 {
882 self.offset(index.as_index()).map(|offset| unsafe {
883 self.data.get_unchecked_mut(offset)
885 })
886 }
887
888 pub unsafe fn get_unchecked_mut<I: AsIndex<L>>(&mut self, index: I) -> &mut S::Elem {
895 let offset = self.layout.offset_unchecked(index.as_index());
896 unsafe { self.data.get_unchecked_mut(offset) }
897 }
898
899 pub(crate) fn mut_view_ref(&mut self) -> TensorBase<ViewMutData<'_, S::Elem>, &L> {
900 TensorBase {
901 data: self.data.view_mut(),
902 layout: &self.layout,
903 }
904 }
905
906 pub fn inner_iter_mut<const N: usize>(&mut self) -> InnerIterMut<'_, S::Elem, NdLayout<N>> {
908 InnerIterMut::new(self.view_mut())
909 }
910
911 pub fn inner_iter_dyn_mut(&mut self, n: usize) -> InnerIterMut<'_, S::Elem, DynLayout> {
916 InnerIterMut::new_dyn(self.view_mut(), n)
917 }
918
919 pub fn iter_mut(&mut self) -> IterMut<'_, S::Elem> {
922 IterMut::new(self.mut_view_ref())
923 }
924
925 pub fn lanes_mut(&mut self, dim: usize) -> LanesMut<'_, S::Elem>
928 where
929 L: RemoveDim,
930 {
931 LanesMut::new(self.mut_view_ref(), dim)
932 }
933
934 pub fn nd_view_mut<const N: usize>(
938 &mut self,
939 ) -> TensorBase<ViewMutData<'_, S::Elem>, NdLayout<N>> {
940 assert!(self.ndim() == N, "ndim {} != {}", self.ndim(), N);
941 TensorBase {
942 layout: self.nd_layout().unwrap(),
943 data: self.data.view_mut(),
944 }
945 }
946
947 pub fn permuted_mut(&mut self, order: L::Index<'_>) -> TensorBase<ViewMutData<'_, S::Elem>, L>
951 where
952 L: MutLayout,
953 {
954 TensorBase {
955 layout: self.layout.permuted(order),
956 data: self.data.view_mut(),
957 }
958 }
959
960 pub fn reshaped_mut<SH: IntoLayout>(
966 &mut self,
967 shape: SH,
968 ) -> Result<TensorBase<ViewMutData<'_, S::Elem>, SH::Layout>, ReshapeError> {
969 let layout = self.layout.reshaped_for_view(shape)?;
970 Ok(TensorBase {
971 layout,
972 data: self.data.view_mut(),
973 })
974 }
975
976 pub fn slice_axis_mut(
978 &mut self,
979 axis: usize,
980 range: Range<usize>,
981 ) -> TensorBase<ViewMutData<'_, S::Elem>, L>
982 where
983 L: MutLayout,
984 {
985 let (offset_range, sliced_layout) = self.layout.slice_axis(axis, range.clone()).unwrap();
986 debug_assert_eq!(sliced_layout.size(axis), range.len());
987 TensorBase {
988 data: self.data.slice_mut(offset_range),
989 layout: sliced_layout,
990 }
991 }
992
993 pub fn slice_mut<R: IntoSliceItems + IndexCount>(
998 &mut self,
999 range: R,
1000 ) -> TensorBase<ViewMutData<'_, S::Elem>, <L as SliceWith<R, R::Count>>::Layout>
1001 where
1002 L: SliceWith<R, R::Count>,
1003 {
1004 self.try_slice_mut(range).expect("slice failed")
1005 }
1006
1007 #[allow(clippy::type_complexity)]
1010 pub fn try_slice_mut<R: IntoSliceItems + IndexCount>(
1011 &mut self,
1012 range: R,
1013 ) -> Result<
1014 TensorBase<ViewMutData<'_, S::Elem>, <L as SliceWith<R, R::Count>>::Layout>,
1015 SliceError,
1016 >
1017 where
1018 L: SliceWith<R, R::Count>,
1019 {
1020 let (offset_range, sliced_layout) = self.layout.slice_with(range)?;
1021 Ok(TensorBase {
1022 data: self.data.slice_mut(offset_range),
1023 layout: sliced_layout,
1024 })
1025 }
1026
1027 pub fn view_mut(&mut self) -> TensorBase<ViewMutData<'_, S::Elem>, L>
1029 where
1030 L: Clone,
1031 {
1032 TensorBase {
1033 data: self.data.view_mut(),
1034 layout: self.layout.clone(),
1035 }
1036 }
1037
1038 pub fn weakly_checked_view_mut(&mut self) -> WeaklyCheckedView<ViewMutData<'_, S::Elem>, L> {
1041 WeaklyCheckedView {
1042 base: self.view_mut(),
1043 }
1044 }
1045}
1046
1047impl<T, L: Clone + Layout> TensorBase<Vec<T>, L> {
1048 pub fn arange(start: T, end: T, step: Option<T>) -> TensorBase<Vec<T>, L>
1052 where
1053 T: Copy + PartialOrd + From<bool> + std::ops::Add<Output = T>,
1054 [usize; 1]: AsShape<L>,
1055 L: FromShape,
1056 {
1057 let step = step.unwrap_or((true).into());
1058 let mut data = Vec::new();
1059 let mut curr = start;
1060 while curr < end {
1061 data.push(curr);
1062 curr = curr + step;
1063 }
1064 TensorBase::from_data([data.len()].as_shape(), data)
1065 }
1066
1067 pub fn append<S2: Storage<Elem = T>>(
1073 &mut self,
1074 axis: usize,
1075 other: &TensorBase<S2, L>,
1076 ) -> Result<(), ExpandError>
1077 where
1078 T: Copy,
1079 L: MutLayout,
1080 {
1081 let shape_match = self.ndim() == other.ndim()
1082 && (0..self.ndim()).all(|d| d == axis || self.size(d) == other.size(d));
1083 if !shape_match {
1084 return Err(ExpandError::ShapeMismatch);
1085 }
1086
1087 let old_size = self.size(axis);
1088 let new_size = self.size(axis) + other.size(axis);
1089
1090 let Some(new_layout) = self.expanded_layout(axis, new_size) else {
1091 return Err(ExpandError::InsufficientCapacity);
1092 };
1093
1094 let new_data_len = new_layout.min_data_len();
1095 self.layout = new_layout;
1096
1097 if self.layout.is_contiguous() && self.data.len() + other.len() == new_data_len {
1100 let added = new_data_len - self.data.len();
1101 other.copy_into_slice(&mut self.data.spare_capacity_mut()[..added]);
1102
1103 unsafe {
1106 self.data.set_len(new_data_len);
1107 }
1108
1109 return Ok(());
1110 }
1111
1112 if self.data.len() < new_data_len {
1114 let fill = *other.iter().next().unwrap();
1117 self.data.resize(new_data_len, fill);
1118 }
1119
1120 self.slice_axis_mut(axis, old_size..new_size)
1121 .copy_from(other);
1122
1123 Ok(())
1124 }
1125
1126 pub fn from_vec(vec: Vec<T>) -> TensorBase<Vec<T>, L>
1128 where
1129 [usize; 1]: AsShape<L>,
1130 L: FromShape,
1131 {
1132 TensorBase::from_data([vec.len()].as_shape(), vec)
1133 }
1134
1135 pub fn clip_dim(&mut self, dim: usize, range: Range<usize>)
1141 where
1142 T: Copy,
1143 L: MutLayout,
1144 {
1145 let (start, end) = (range.start, range.end);
1146
1147 assert!(start <= end, "start must be <= end");
1148 assert!(end <= self.size(dim), "end must be <= dim size");
1149
1150 self.layout.resize_dim(dim, end - start);
1151
1152 let range = if self.is_empty() {
1153 0..0
1154 } else {
1155 let start_offset = start * self.layout.stride(dim);
1156 let end_offset = start_offset + self.layout.min_data_len();
1157 start_offset..end_offset
1158 };
1159 self.data.copy_within(range.clone(), 0);
1160 self.data.truncate(range.end - range.start);
1161 }
1162
1163 pub fn has_capacity(&self, axis: usize, new_size: usize) -> bool
1166 where
1167 L: MutLayout,
1168 {
1169 self.expanded_layout(axis, new_size).is_some()
1170 }
1171
1172 fn expanded_layout(&self, axis: usize, new_size: usize) -> Option<L>
1177 where
1178 L: MutLayout,
1179 {
1180 let mut new_layout = self.layout.clone();
1181 new_layout.resize_dim(axis, new_size);
1182 let new_data_len = new_layout.min_data_len();
1183
1184 let has_capacity = new_data_len <= self.data.capacity()
1185 && !may_have_internal_overlap(new_layout.shape(), new_layout.strides());
1186
1187 has_capacity.then_some(new_layout)
1188 }
1189
1190 pub fn into_cow(self) -> TensorBase<CowData<'static, T>, L> {
1195 let TensorBase { data, layout } = self;
1196 TensorBase {
1197 layout,
1198 data: CowData::Owned(data),
1199 }
1200 }
1201
1202 pub fn into_arc(self) -> TensorBase<Arc<Vec<T>>, L> {
1207 let TensorBase { data, layout } = self;
1208 TensorBase {
1209 layout,
1210 data: Arc::new(data),
1211 }
1212 }
1213
1214 pub fn into_data(self) -> Vec<T>
1218 where
1219 T: Clone,
1220 {
1221 if self.is_contiguous() {
1222 self.into_non_contiguous_data()
1223 } else {
1224 self.to_vec()
1225 }
1226 }
1227
1228 pub fn into_non_contiguous_data(mut self) -> Vec<T> {
1231 self.data.truncate(self.layout.min_data_len());
1232 self.data
1233 }
1234
1235 #[track_caller]
1239 pub fn into_shape<S: Copy + IntoLayout>(self, shape: S) -> TensorBase<Vec<T>, S::Layout>
1240 where
1241 T: Clone,
1242 {
1243 let Ok(layout) = self.layout.reshaped_for_copy(shape) else {
1244 panic!(
1245 "element count mismatch reshaping {:?} to {:?}",
1246 self.shape(),
1247 shape
1248 );
1249 };
1250 TensorBase {
1251 layout,
1252 data: self.into_data(),
1253 }
1254 }
1255
1256 pub fn from_fn<F: FnMut(L::Index<'_>) -> T, Idx>(
1263 shape: L::Shape<'_>,
1264 f: F,
1265 ) -> TensorBase<Vec<T>, L>
1266 where
1267 L::Indices: Iterator<Item = Idx>,
1268 Idx: AsIndex<L>,
1269 L: FromShape,
1270 {
1271 Self::from_fn_in(GlobalAlloc::new(), shape, f)
1272 }
1273
1274 pub fn from_fn_in<A: Alloc, F: FnMut(L::Index<'_>) -> T, Idx>(
1276 alloc: A,
1277 shape: L::Shape<'_>,
1278 mut f: F,
1279 ) -> TensorBase<Vec<T>, L>
1280 where
1281 L::Indices: Iterator<Item = Idx>,
1282 Idx: AsIndex<L>,
1283 L: FromShape,
1284 {
1285 let layout = L::from_shape(shape);
1286 let mut data = alloc.alloc(layout.len());
1287 data.extend(layout.indices().map(|idx| f(idx.as_index())));
1288 TensorBase { data, layout }
1289 }
1290
1291 pub fn from_simple_fn<F: FnMut() -> T>(shape: L::Shape<'_>, f: F) -> TensorBase<Vec<T>, L>
1294 where
1295 L: FromShape,
1296 {
1297 Self::from_simple_fn_in(GlobalAlloc::new(), shape, f)
1298 }
1299
1300 pub fn from_simple_fn_in<A: Alloc, F: FnMut() -> T>(
1303 alloc: A,
1304 shape: L::Shape<'_>,
1305 mut f: F,
1306 ) -> TensorBase<Vec<T>, L>
1307 where
1308 L: FromShape,
1309 {
1310 let len = shape.iter().product();
1311 let mut data = alloc.alloc(len);
1312 data.extend(std::iter::from_fn(|| Some(f())).take(len));
1313 TensorBase::from_data(shape, data)
1314 }
1315
1316 pub fn from_scalar(value: T) -> TensorBase<Vec<T>, L>
1318 where
1319 [usize; 0]: AsShape<L>,
1320 L: FromShape,
1321 {
1322 TensorBase::from_data([].as_shape(), vec![value])
1323 }
1324
1325 pub fn full(shape: L::Shape<'_>, value: T) -> TensorBase<Vec<T>, L>
1327 where
1328 T: Clone,
1329 L: FromShape,
1330 {
1331 Self::full_in(GlobalAlloc::new(), shape, value)
1332 }
1333
1334 pub fn full_in<A: Alloc>(alloc: A, shape: L::Shape<'_>, value: T) -> TensorBase<Vec<T>, L>
1336 where
1337 T: Clone,
1338 L: FromShape,
1339 {
1340 let len = shape.iter().product();
1341 let mut data = alloc.alloc(len);
1342 data.resize(len, value);
1343 TensorBase::from_data(shape, data)
1344 }
1345
1346 pub fn make_contiguous(&mut self)
1353 where
1354 T: Clone,
1355 L: FromShape,
1356 {
1357 if self.is_contiguous() {
1358 return;
1359 }
1360 self.data = self.to_vec();
1361 self.layout = L::from_shape(self.layout.shape());
1362 }
1363
1364 pub fn into_contiguous(self) -> Contiguous<Self>
1369 where
1370 T: Clone,
1371 L: FromShape,
1372 {
1373 Contiguous::from_owned(self)
1374 }
1375
1376 pub fn rand<R: RandomSource<T>>(shape: L::Shape<'_>, rand_src: &mut R) -> TensorBase<Vec<T>, L>
1382 where
1383 L: FromShape,
1384 {
1385 Self::from_simple_fn(shape, || rand_src.next())
1386 }
1387
1388 pub fn zeros(shape: L::Shape<'_>) -> TensorBase<Vec<T>, L>
1391 where
1392 T: Clone + Default,
1393 L: FromShape,
1394 {
1395 Self::zeros_in(GlobalAlloc::new(), shape)
1396 }
1397
1398 pub fn zeros_in<A: Alloc>(alloc: A, shape: L::Shape<'_>) -> TensorBase<Vec<T>, L>
1400 where
1401 T: Clone + Default,
1402 L: FromShape,
1403 {
1404 Self::full_in(alloc, shape, T::default())
1407 }
1408
1409 pub fn uninit(shape: L::Shape<'_>) -> TensorBase<Vec<MaybeUninit<T>>, L>
1415 where
1416 MaybeUninit<T>: Clone,
1417 L: FromShape,
1418 {
1419 Self::uninit_in(GlobalAlloc::new(), shape)
1420 }
1421
1422 pub fn uninit_in<A: Alloc>(alloc: A, shape: L::Shape<'_>) -> TensorBase<Vec<MaybeUninit<T>>, L>
1424 where
1425 L: FromShape,
1426 {
1427 let len = shape.iter().product();
1428 let mut data = alloc.alloc(len);
1429
1430 unsafe { data.set_len(len) }
1433
1434 TensorBase::from_data(shape, data)
1435 }
1436
1437 pub fn concat<S2: Storage<Elem = T>>(
1443 dim: usize,
1444 tensors: &[TensorBase<S2, L>],
1445 ) -> Result<TensorBase<Vec<T>, L>, ExpandError>
1446 where
1447 T: Copy,
1448 L: FromShape + MutLayout,
1449 {
1450 let first = tensors.first().ok_or(ExpandError::ShapeMismatch)?;
1451 let total_dim_size: usize = tensors.iter().map(|t| t.size(dim)).sum();
1452
1453 let mut target_layout = first.layout().clone();
1454 target_layout.resize_dim(dim, total_dim_size);
1455
1456 let mut result = Self::with_capacity(target_layout.shape(), dim);
1457 for tensor in tensors {
1458 result.append(dim, tensor)?;
1459 }
1460 Ok(result)
1461 }
1462
1463 pub fn with_capacity(shape: L::Shape<'_>, expand_dim: usize) -> TensorBase<Vec<T>, L>
1470 where
1471 T: Copy,
1472 L: FromShape + MutLayout,
1473 {
1474 Self::with_capacity_in(GlobalAlloc::new(), shape, expand_dim)
1475 }
1476
1477 pub fn with_capacity_in<A: Alloc>(
1479 alloc: A,
1480 shape: L::Shape<'_>,
1481 expand_dim: usize,
1482 ) -> TensorBase<Vec<T>, L>
1483 where
1484 T: Copy,
1485 L: FromShape + MutLayout,
1486 {
1487 let mut tensor = Self::uninit_in(alloc, shape);
1488 tensor.clip_dim(expand_dim, 0..0);
1489
1490 unsafe { tensor.assume_init() }
1493 }
1494}
1495
1496impl<'a, T, L: Layout> TensorBase<CowData<'a, T>, L> {
1497 pub fn into_non_contiguous_data(self) -> Option<Vec<T>> {
1501 match self.data {
1502 CowData::Owned(mut vec) => {
1503 vec.truncate(self.layout.min_data_len());
1504 Some(vec)
1505 }
1506 CowData::Borrowed(_) => None,
1507 }
1508 }
1509
1510 pub fn into_owned(self) -> TensorBase<Vec<T>, L>
1514 where
1515 L: Clone + FromShape,
1516 T: Clone,
1517 {
1518 self.into_owned_in(GlobalAlloc::new())
1519 }
1520
1521 pub fn into_owned_in<A: Alloc>(self, alloc: A) -> TensorBase<Vec<T>, L>
1523 where
1524 L: Clone + FromShape,
1525 T: Clone,
1526 {
1527 match self.data {
1528 CowData::Owned(data) => TensorBase {
1529 data,
1530 layout: self.layout,
1531 },
1532 CowData::Borrowed(_) => {
1533 let data = self.to_vec_in(alloc);
1534 let layout = L::from_shape(self.shape());
1535 TensorBase { data, layout }
1536 }
1537 }
1538 }
1539
1540 pub fn into_shape<S: Clone + IntoLayout>(
1544 self,
1545 shape: S,
1546 ) -> TensorBase<CowData<'a, T>, S::Layout>
1547 where
1548 T: Clone,
1549 L: Clone,
1550 {
1551 self.into_shape_in(GlobalAlloc::new(), shape)
1552 }
1553
1554 pub fn into_shape_in<A: Alloc, S: Clone + IntoLayout>(
1556 self,
1557 alloc: A,
1558 shape: S,
1559 ) -> TensorBase<CowData<'a, T>, S::Layout>
1560 where
1561 T: Clone,
1562 L: Clone,
1563 {
1564 if let Ok(layout) = self.layout.reshaped_for_view(shape.clone()) {
1565 TensorBase {
1566 data: self.data,
1567 layout,
1568 }
1569 } else {
1570 let Ok(layout) = self.layout.reshaped_for_copy(shape.clone()) else {
1571 panic!(
1572 "element count mismatch reshaping {:?} to {:?}",
1573 self.shape(),
1574 shape
1575 );
1576 };
1577
1578 TensorBase {
1579 data: CowData::Owned(self.to_vec_in(alloc)),
1580 layout,
1581 }
1582 }
1583 }
1584}
1585
1586pub enum InitEmpty<Init: Storage, Uninit: Storage, L: Layout> {
1588 Empty(TensorBase<Init, L>),
1590 NotEmpty(TensorBase<Uninit, L>),
1592}
1593
1594impl<T, S: Storage<Elem = MaybeUninit<T>> + AssumeInit, L: Layout + Clone> TensorBase<S, L>
1595where
1596 <S as AssumeInit>::Output: Storage<Elem = T>,
1597{
1598 pub unsafe fn assume_init(self) -> TensorBase<<S as AssumeInit>::Output, L> {
1608 TensorBase {
1609 layout: self.layout,
1610 data: unsafe { self.data.assume_init() },
1611 }
1612 }
1613
1614 pub fn init_if_empty(self) -> InitEmpty<<S as AssumeInit>::Output, S, L> {
1616 if self.is_empty() {
1617 InitEmpty::Empty(unsafe { self.assume_init() })
1619 } else {
1620 InitEmpty::NotEmpty(self)
1621 }
1622 }
1623
1624 pub fn init_from<S2: Storage<Elem = T>>(
1628 mut self,
1629 other: &TensorBase<S2, L>,
1630 ) -> TensorBase<<S as AssumeInit>::Output, L>
1631 where
1632 T: Copy,
1633 S: StorageMut<Elem = MaybeUninit<T>>,
1634 {
1635 assert_eq!(self.shape(), other.shape(), "shape mismatch");
1636
1637 match (self.data_mut(), other.data()) {
1638 (Some(self_data), Some(other_data)) => {
1640 let other_data: &[MaybeUninit<T>] = unsafe { std::mem::transmute(other_data) };
1641 self_data.clone_from_slice(other_data);
1642 }
1643 (Some(self_data), _) => {
1645 copy_into_slice(other.as_dyn(), self_data);
1646 }
1647 _ => {
1649 copy_into_uninit(other.as_dyn(), self.as_dyn_mut());
1650 }
1651 }
1652
1653 unsafe { self.assume_init() }
1654 }
1655}
1656
1657impl<'a, T, L: Clone + Layout> TensorBase<ViewData<'a, T>, L> {
1658 pub fn axis_iter(&self, dim: usize) -> AxisIter<'a, T, L>
1659 where
1660 L: MutLayout + RemoveDim,
1661 {
1662 AxisIter::new(self, dim)
1663 }
1664
1665 pub fn axis_chunks(&self, dim: usize, chunk_size: usize) -> AxisChunks<'a, T, L>
1666 where
1667 L: MutLayout,
1668 {
1669 AxisChunks::new(self, dim, chunk_size)
1670 }
1671
1672 pub fn as_dyn(&self) -> TensorBase<ViewData<'a, T>, DynLayout> {
1676 TensorBase {
1677 data: self.data,
1678 layout: DynLayout::from(&self.layout),
1679 }
1680 }
1681
1682 pub fn as_cow(&self) -> TensorBase<CowData<'a, T>, L> {
1686 TensorBase {
1687 layout: self.layout.clone(),
1688 data: CowData::Borrowed(self.data),
1689 }
1690 }
1691
1692 pub fn broadcast<S: IntoLayout>(&self, shape: S) -> TensorBase<ViewData<'a, T>, S::Layout>
1696 where
1697 L: BroadcastLayout<S::Layout>,
1698 {
1699 self.try_broadcast(shape).unwrap()
1700 }
1701
1702 pub fn try_broadcast<S: IntoLayout>(
1706 &self,
1707 shape: S,
1708 ) -> Result<TensorBase<ViewData<'a, T>, S::Layout>, ExpandError>
1709 where
1710 L: BroadcastLayout<S::Layout>,
1711 {
1712 Ok(TensorBase {
1713 layout: self.layout.broadcast(shape)?,
1714 data: self.data,
1715 })
1716 }
1717
1718 pub fn data(&self) -> Option<&'a [T]> {
1722 let len = self.layout.min_data_len();
1725 let data = self.data.slice(0..len);
1726
1727 self.layout.is_contiguous().then(|| unsafe {
1728 data.as_slice()
1730 })
1731 }
1732
1733 pub fn storage(&self) -> ViewData<'a, T> {
1735 self.data.view()
1736 }
1737
1738 pub fn get<I: AsIndex<L>>(&self, index: I) -> Option<&'a T>
1739 where
1740 L: TrustedLayout,
1741 {
1742 self.offset(index.as_index()).map(|offset|
1743 unsafe {
1748 self.data.get_unchecked(offset)
1749 })
1750 }
1751
1752 pub fn from_slice_with_strides(
1758 shape: L::Shape<'_>,
1759 data: &'a [T],
1760 strides: L::Strides<'_>,
1761 ) -> Result<TensorBase<ViewData<'a, T>, L>, FromDataError>
1762 where
1763 L: MutLayout,
1764 {
1765 let layout = L::from_shape_and_strides(shape, strides, OverlapPolicy::AllowOverlap)?;
1766 if layout.min_data_len() > data.as_ref().len() {
1767 return Err(FromDataError::StorageTooShort);
1768 }
1769 Ok(TensorBase {
1770 data: data.into_storage(),
1771 layout,
1772 })
1773 }
1774
1775 pub unsafe fn get_unchecked<I: AsIndex<L>>(&self, index: I) -> &'a T {
1782 let offset = self.layout.offset_unchecked(index.as_index());
1783 unsafe { self.data.get_unchecked(offset) }
1784 }
1785
1786 pub fn index_axis(
1792 &self,
1793 axis: usize,
1794 index: usize,
1795 ) -> TensorBase<ViewData<'a, T>, <L as RemoveDim>::Output>
1796 where
1797 L: MutLayout + RemoveDim,
1798 {
1799 let (offsets, layout) = self.layout.index_axis(axis, index);
1800 TensorBase {
1801 data: self.data.slice(offsets),
1802 layout,
1803 }
1804 }
1805
1806 pub fn inner_iter<const N: usize>(&self) -> InnerIter<'a, T, NdLayout<N>> {
1810 InnerIter::new(self.view())
1811 }
1812
1813 pub fn inner_iter_dyn(&self, n: usize) -> InnerIter<'a, T, DynLayout> {
1817 InnerIter::new_dyn(self.view(), n)
1818 }
1819
1820 pub fn item(&self) -> Option<&'a T> {
1822 match self.ndim() {
1823 0 => unsafe {
1824 self.data.get(0)
1826 },
1827 _ if self.len() == 1 => self.iter().next(),
1828 _ => None,
1829 }
1830 }
1831
1832 pub fn iter(&self) -> Iter<'a, T> {
1836 Iter::new(self.view_ref())
1837 }
1838
1839 pub fn lanes(&self, dim: usize) -> Lanes<'a, T>
1843 where
1844 L: RemoveDim,
1845 {
1846 assert!(dim < self.ndim());
1847 Lanes::new(self.view_ref(), dim)
1848 }
1849
1850 pub fn nd_view<const N: usize>(&self) -> TensorBase<ViewData<'a, T>, NdLayout<N>> {
1854 assert!(self.ndim() == N, "ndim {} != {}", self.ndim(), N);
1855 TensorBase {
1856 data: self.data,
1857 layout: self.nd_layout().unwrap(),
1858 }
1859 }
1860
1861 pub fn permuted(&self, order: L::Index<'_>) -> TensorBase<ViewData<'a, T>, L>
1865 where
1866 L: MutLayout,
1867 {
1868 TensorBase {
1869 data: self.data,
1870 layout: self.layout.permuted(order),
1871 }
1872 }
1873
1874 pub fn reshaped<S: Copy + IntoLayout>(&self, shape: S) -> TensorBase<CowData<'a, T>, S::Layout>
1878 where
1879 T: Clone,
1880 {
1881 self.reshaped_in(GlobalAlloc::new(), shape)
1882 }
1883
1884 pub fn reshaped_in<A: Alloc, S: Copy + IntoLayout>(
1886 &self,
1887 alloc: A,
1888 shape: S,
1889 ) -> TensorBase<CowData<'a, T>, S::Layout>
1890 where
1891 T: Clone,
1892 {
1893 if let Ok(layout) = self.layout.reshaped_for_view(shape) {
1894 TensorBase {
1895 data: CowData::Borrowed(self.data),
1896 layout,
1897 }
1898 } else {
1899 let Ok(layout) = self.layout.reshaped_for_copy(shape) else {
1900 panic!(
1901 "element count mismatch reshaping {:?} to {:?}",
1902 self.shape(),
1903 shape
1904 );
1905 };
1906
1907 TensorBase {
1908 data: CowData::Owned(self.to_vec_in(alloc)),
1909 layout,
1910 }
1911 }
1912 }
1913
1914 pub fn slice<R: IntoSliceItems + IndexCount>(
1916 &self,
1917 range: R,
1918 ) -> TensorBase<ViewData<'a, T>, <L as SliceWith<R, R::Count>>::Layout>
1919 where
1920 L: SliceWith<R, R::Count>,
1921 {
1922 self.try_slice(range).expect("slice failed")
1923 }
1924
1925 pub fn slice_axis(&self, axis: usize, range: Range<usize>) -> TensorBase<ViewData<'a, T>, L>
1927 where
1928 L: MutLayout,
1929 {
1930 let (offset_range, sliced_layout) = self.layout.slice_axis(axis, range.clone()).unwrap();
1931 debug_assert_eq!(sliced_layout.size(axis), range.len());
1932 TensorBase {
1933 data: self.data.slice(offset_range),
1934 layout: sliced_layout,
1935 }
1936 }
1937
1938 #[allow(clippy::type_complexity)]
1941 pub fn try_slice<R: IntoSliceItems + IndexCount>(
1942 &self,
1943 range: R,
1944 ) -> Result<TensorBase<ViewData<'a, T>, <L as SliceWith<R, R::Count>>::Layout>, SliceError>
1945 where
1946 L: SliceWith<R, R::Count>,
1947 {
1948 let (offset_range, sliced_layout) = self.layout.slice_with(range)?;
1949 Ok(TensorBase {
1950 data: self.data.slice(offset_range),
1951 layout: sliced_layout,
1952 })
1953 }
1954
1955 pub fn squeezed(&self) -> TensorView<'a, T>
1959 where
1960 L: MutLayout,
1961 {
1962 TensorBase {
1963 data: self.data.view(),
1964 layout: self.layout.squeezed(),
1965 }
1966 }
1967
1968 #[allow(clippy::type_complexity)]
1974 pub fn split_at(
1975 &self,
1976 axis: usize,
1977 mid: usize,
1978 ) -> (
1979 TensorBase<ViewData<'a, T>, L>,
1980 TensorBase<ViewData<'a, T>, L>,
1981 )
1982 where
1983 L: MutLayout,
1984 {
1985 let (left, right) = self.layout.split(axis, mid);
1986 let (left_offset_range, left_layout) = left;
1987 let (right_offset_range, right_layout) = right;
1988 let left_data = self.data.slice(left_offset_range.clone());
1989 let right_data = self.data.slice(right_offset_range.clone());
1990
1991 debug_assert_eq!(left_data.len(), left_layout.min_data_len());
1992 let left_view = TensorBase {
1993 data: left_data,
1994 layout: left_layout,
1995 };
1996
1997 debug_assert_eq!(right_data.len(), right_layout.min_data_len());
1998 let right_view = TensorBase {
1999 data: right_data,
2000 layout: right_layout,
2001 };
2002
2003 (left_view, right_view)
2004 }
2005
2006 pub fn to_contiguous(&self) -> Contiguous<TensorBase<CowData<'a, T>, L>>
2011 where
2012 T: Clone,
2013 L: FromShape,
2014 {
2015 self.to_contiguous_in(GlobalAlloc::new())
2016 }
2017
2018 pub fn to_contiguous_in<A: Alloc>(&self, alloc: A) -> Contiguous<TensorBase<CowData<'a, T>, L>>
2021 where
2022 T: Clone,
2023 L: FromShape,
2024 {
2025 let tensor = if let Some(data) = self.data() {
2026 TensorBase {
2027 data: CowData::Borrowed(data.into_storage()),
2028 layout: self.layout.clone(),
2029 }
2030 } else {
2031 let data = self.to_vec_in(alloc);
2032 TensorBase {
2033 data: CowData::Owned(data),
2034 layout: L::from_shape(self.layout.shape()),
2035 }
2036 };
2037 Contiguous::new(tensor).unwrap()
2038 }
2039
2040 pub fn to_slice(&self) -> Cow<'a, [T]>
2045 where
2046 T: Clone,
2047 {
2048 self.data()
2049 .map(Cow::Borrowed)
2050 .unwrap_or_else(|| Cow::Owned(self.to_vec()))
2051 }
2052
2053 pub fn transposed(&self) -> TensorBase<ViewData<'a, T>, L>
2055 where
2056 L: MutLayout,
2057 {
2058 TensorBase {
2059 data: self.data,
2060 layout: self.layout.transposed(),
2061 }
2062 }
2063
2064 pub fn try_slice_dyn<R: IntoSliceItems>(
2065 &self,
2066 range: R,
2067 ) -> Result<TensorView<'a, T>, SliceError>
2068 where
2069 L: MutLayout,
2070 {
2071 let (offset_range, layout) = self.layout.slice_dyn(range.into_slice_items().as_ref())?;
2072 Ok(TensorBase {
2073 data: self.data.slice(offset_range),
2074 layout,
2075 })
2076 }
2077
2078 pub fn view(&self) -> TensorBase<ViewData<'a, T>, L> {
2080 TensorBase {
2081 data: self.data,
2082 layout: self.layout.clone(),
2083 }
2084 }
2085
2086 pub(crate) fn view_ref(&self) -> TensorBase<ViewData<'a, T>, &L> {
2087 TensorBase {
2088 data: self.data,
2089 layout: &self.layout,
2090 }
2091 }
2092
2093 pub fn weakly_checked_view(&self) -> WeaklyCheckedView<ViewData<'a, T>, L> {
2094 WeaklyCheckedView { base: self.view() }
2095 }
2096}
2097
2098impl<S: Storage, L: Layout> Layout for TensorBase<S, L> {
2099 type Shape<'a>
2100 = L::Shape<'a>
2101 where
2102 Self: 'a;
2103 type Strides<'a>
2104 = L::Strides<'a>
2105 where
2106 Self: 'a;
2107 type Index<'a> = L::Index<'a>;
2108 type Indices = L::Indices;
2109
2110 fn ndim(&self) -> usize {
2111 self.layout.ndim()
2112 }
2113
2114 fn len(&self) -> usize {
2115 self.layout.len()
2116 }
2117
2118 fn is_empty(&self) -> bool {
2119 self.layout.is_empty()
2120 }
2121
2122 fn shape(&self) -> Self::Shape<'_> {
2123 self.layout.shape()
2124 }
2125
2126 fn size(&self, dim: usize) -> usize {
2127 self.layout.size(dim)
2128 }
2129
2130 fn strides(&self) -> Self::Strides<'_> {
2131 self.layout.strides()
2132 }
2133
2134 fn stride(&self, dim: usize) -> usize {
2135 self.layout.stride(dim)
2136 }
2137
2138 fn indices(&self) -> Self::Indices {
2139 self.layout.indices()
2140 }
2141
2142 fn offset(&self, index: Self::Index<'_>) -> Option<usize> {
2143 self.layout.offset(index)
2144 }
2145}
2146
2147impl<S: Storage, L: Layout + MatrixLayout> MatrixLayout for TensorBase<S, L> {
2148 fn rows(&self) -> usize {
2149 self.layout.rows()
2150 }
2151
2152 fn cols(&self) -> usize {
2153 self.layout.cols()
2154 }
2155
2156 fn row_stride(&self) -> usize {
2157 self.layout.row_stride()
2158 }
2159
2160 fn col_stride(&self) -> usize {
2161 self.layout.col_stride()
2162 }
2163}
2164
2165impl<T, S: Storage<Elem = T>, L: Layout + Clone> AsView for TensorBase<S, L> {
2166 type Elem = T;
2167 type Layout = L;
2168
2169 fn iter(&self) -> Iter<'_, T> {
2170 self.view().iter()
2171 }
2172
2173 fn copy_into_slice<'a>(&self, dest: &'a mut [MaybeUninit<T>]) -> &'a [T]
2174 where
2175 T: Copy,
2176 {
2177 if let Some(data) = self.data() {
2178 let src_uninit = unsafe { std::mem::transmute::<&[T], &[MaybeUninit<T>]>(data) };
2180 dest.copy_from_slice(src_uninit);
2181 unsafe { dest.assume_init() }
2184 } else {
2185 copy_into_slice(self.as_dyn(), dest)
2186 }
2187 }
2188
2189 fn data(&self) -> Option<&[Self::Elem]> {
2190 self.view().data()
2191 }
2192
2193 fn insert_axis(&mut self, index: usize)
2194 where
2195 L: ResizeLayout,
2196 {
2197 self.layout.insert_axis(index)
2198 }
2199
2200 #[track_caller]
2201 fn remove_axis(&mut self, index: usize)
2202 where
2203 L: ResizeLayout,
2204 {
2205 self.layout.remove_axis(index)
2206 }
2207
2208 fn merge_axes(&mut self)
2209 where
2210 L: ResizeLayout,
2211 {
2212 self.layout.merge_axes()
2213 }
2214
2215 fn layout(&self) -> &L {
2216 &self.layout
2217 }
2218
2219 fn map<F, U>(&self, f: F) -> TensorBase<Vec<U>, L>
2220 where
2221 F: Fn(&Self::Elem) -> U,
2222 L: FromShape,
2223 {
2224 self.map_in(GlobalAlloc::new(), f)
2225 }
2226
2227 fn map_in<A: Alloc, F, U>(&self, alloc: A, f: F) -> TensorBase<Vec<U>, L>
2228 where
2229 F: Fn(&Self::Elem) -> U,
2230 L: FromShape,
2231 {
2232 let len = self.len();
2233 let mut buf = alloc.alloc(len);
2234 if let Some(data) = self.data() {
2235 buf.extend(data.iter().map(f));
2237 } else {
2238 let dest = &mut buf.spare_capacity_mut()[..len];
2239 map_into_slice(self.as_dyn(), dest, f);
2240
2241 unsafe {
2243 buf.set_len(len);
2244 }
2245 };
2246 TensorBase::from_data(self.shape(), buf)
2247 }
2248
2249 fn move_axis(&mut self, from: usize, to: usize)
2250 where
2251 L: MutLayout,
2252 {
2253 self.layout.move_axis(from, to);
2254 }
2255
2256 fn view(&self) -> TensorBase<ViewData<'_, T>, L> {
2257 TensorBase {
2258 data: self.data.view(),
2259 layout: self.layout.clone(),
2260 }
2261 }
2262
2263 fn get<I: AsIndex<L>>(&self, index: I) -> Option<&Self::Elem> {
2267 self.offset(index.as_index()).map(|offset| unsafe {
2268 self.data.get_unchecked(offset)
2270 })
2271 }
2272
2273 unsafe fn get_unchecked<I: AsIndex<L>>(&self, index: I) -> &T {
2274 let offset = self.layout.offset_unchecked(index.as_index());
2275 unsafe { self.data.get_unchecked(offset) }
2276 }
2277
2278 fn permute(&mut self, order: Self::Index<'_>)
2279 where
2280 L: MutLayout,
2281 {
2282 self.layout = self.layout.permuted(order);
2283 }
2284
2285 fn to_vec(&self) -> Vec<T>
2286 where
2287 T: Clone,
2288 {
2289 self.to_vec_in(GlobalAlloc::new())
2290 }
2291
2292 fn to_vec_in<A: Alloc>(&self, alloc: A) -> Vec<T>
2293 where
2294 T: Clone,
2295 {
2296 let len = self.len();
2297 let mut buf = alloc.alloc(len);
2298
2299 if let Some(data) = self.data() {
2300 buf.extend_from_slice(data);
2301 } else {
2302 copy_into_slice(self.as_dyn(), &mut buf.spare_capacity_mut()[..len]);
2303
2304 unsafe { buf.set_len(len) }
2306 }
2307
2308 buf
2309 }
2310
2311 fn to_shape<SH: IntoLayout>(&self, shape: SH) -> TensorBase<Vec<Self::Elem>, SH::Layout>
2312 where
2313 T: Clone,
2314 {
2315 TensorBase {
2316 data: self.to_vec(),
2317 layout: self
2318 .layout
2319 .reshaped_for_copy(shape)
2320 .expect("reshape failed"),
2321 }
2322 }
2323
2324 fn transpose(&mut self)
2325 where
2326 L: MutLayout,
2327 {
2328 self.layout = self.layout.transposed();
2329 }
2330}
2331
2332impl<T, S: Storage<Elem = T>, const N: usize> TensorBase<S, NdLayout<N>> {
2333 #[inline]
2341 pub fn get_array<const M: usize>(&self, base: [usize; N], dim: usize) -> [T; M]
2342 where
2343 T: Copy + Default,
2344 {
2345 let offsets: [usize; M] = array_offsets(&self.layout, base, dim);
2346 let mut result = [T::default(); M];
2347 for i in 0..M {
2348 result[i] = unsafe { *self.data.get_unchecked(offsets[i]) };
2350 }
2351 result
2352 }
2353}
2354
2355impl<T> TensorBase<Vec<T>, DynLayout> {
2356 #[track_caller]
2359 pub fn reshape(&mut self, shape: &[usize])
2360 where
2361 T: Clone,
2362 {
2363 self.reshape_in(GlobalAlloc::new(), shape)
2364 }
2365
2366 #[track_caller]
2368 pub fn reshape_in<A: Alloc>(&mut self, alloc: A, shape: &[usize])
2369 where
2370 T: Clone,
2371 {
2372 if !self.is_contiguous() {
2373 self.data = self.to_vec_in(alloc);
2374 }
2375 let Ok(layout) = self.layout.reshaped_for_copy(shape) else {
2376 panic!(
2377 "element count mismatch reshaping {:?} to {:?}",
2378 self.shape(),
2379 shape
2380 );
2381 };
2382 self.layout = layout;
2383 }
2384}
2385
2386impl<'a, T, L: Layout> TensorBase<ViewMutData<'a, T>, L> {
2387 #[allow(clippy::type_complexity)]
2393 pub fn split_at_mut(
2394 self,
2395 axis: usize,
2396 mid: usize,
2397 ) -> (
2398 TensorBase<ViewMutData<'a, T>, L>,
2399 TensorBase<ViewMutData<'a, T>, L>,
2400 )
2401 where
2402 L: MutLayout,
2403 {
2404 let (left, right) = self.layout.split(axis, mid);
2405 let (left_offset_range, left_layout) = left;
2406 let (right_offset_range, right_layout) = right;
2407 let (left_data, right_data) = self
2408 .data
2409 .split_mut(left_offset_range.clone(), right_offset_range.clone());
2410
2411 debug_assert_eq!(left_data.len(), left_layout.min_data_len());
2412 let left_view = TensorBase {
2413 data: left_data,
2414 layout: left_layout,
2415 };
2416
2417 debug_assert_eq!(right_data.len(), right_layout.min_data_len());
2418 let right_view = TensorBase {
2419 data: right_data,
2420 layout: right_layout,
2421 };
2422
2423 (left_view, right_view)
2424 }
2425
2426 pub fn into_slice_mut(self) -> Option<&'a mut [T]> {
2429 let len = self.layout.min_data_len();
2430 self.is_contiguous().then(|| {
2431 let slice = unsafe { self.data.to_slice_mut() };
2433 &mut slice[..len]
2434 })
2435 }
2436}
2437
2438impl<T, L: FromShape> FromIterator<T> for TensorBase<Vec<T>, L>
2439where
2440 [usize; 1]: AsShape<L>,
2441{
2442 fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> TensorBase<Vec<T>, L> {
2446 let data: Vec<T> = iter.into_iter().collect();
2447 TensorBase::from_data([data.len()].as_shape(), data)
2448 }
2449}
2450
2451impl<T, L: FromShape> From<Vec<T>> for TensorBase<Vec<T>, L>
2452where
2453 [usize; 1]: AsShape<L>,
2454{
2455 fn from(vec: Vec<T>) -> Self {
2457 Self::from_data([vec.len()].as_shape(), vec)
2458 }
2459}
2460
2461impl<'a, T, L: FromShape> From<&'a [T]> for TensorBase<ViewData<'a, T>, L>
2462where
2463 [usize; 1]: AsShape<L>,
2464{
2465 fn from(slice: &'a [T]) -> Self {
2467 Self::from_data([slice.len()].as_shape(), slice)
2468 }
2469}
2470
2471impl<'a, T, L: FromShape, const N: usize> From<&'a [T; N]> for TensorBase<ViewData<'a, T>, L>
2472where
2473 [usize; 1]: AsShape<L>,
2474{
2475 fn from(slice: &'a [T; N]) -> Self {
2477 Self::from_data([slice.len()].as_shape(), slice.as_slice())
2478 }
2479}
2480
2481fn array_offsets<const N: usize, const M: usize>(
2486 layout: &NdLayout<N>,
2487 base: [usize; N],
2488 dim: usize,
2489) -> [usize; M] {
2490 assert!(
2491 base[dim] < usize::MAX - M && layout.size(dim) >= base[dim] + M,
2492 "array indices invalid"
2493 );
2494
2495 let offset = layout.must_offset(base);
2496 let stride = layout.stride(dim);
2497 let mut offsets = [0; M];
2498 for i in 0..M {
2499 offsets[i] = offset + i * stride;
2500 }
2501 offsets
2502}
2503
2504impl<T, S: StorageMut<Elem = T>, const N: usize> TensorBase<S, NdLayout<N>> {
2505 #[inline]
2510 pub fn set_array<const M: usize>(&mut self, base: [usize; N], dim: usize, values: [T; M])
2511 where
2512 T: Copy,
2513 {
2514 let offsets: [usize; M] = array_offsets(&self.layout, base, dim);
2515
2516 for i in 0..M {
2517 unsafe { *self.data.get_unchecked_mut(offsets[i]) = values[i] };
2519 }
2520 }
2521}
2522
2523impl<T, S: Storage<Elem = T>> TensorBase<S, NdLayout<1>> {
2524 #[inline]
2528 pub fn to_array<const M: usize>(&self) -> [T; M]
2529 where
2530 T: Copy + Default,
2531 {
2532 self.get_array([0], 0)
2533 }
2534}
2535
2536impl<T, S: StorageMut<Elem = T>> TensorBase<S, NdLayout<1>> {
2537 #[inline]
2541 pub fn assign_array<const M: usize>(&mut self, values: [T; M])
2542 where
2543 T: Copy + Default,
2544 {
2545 self.set_array([0], 0, values)
2546 }
2547}
2548
2549pub type NdTensorView<'a, T, const N: usize> = TensorBase<ViewData<'a, T>, NdLayout<N>>;
2551
2552pub type NdTensor<T, const N: usize> = TensorBase<Vec<T>, NdLayout<N>>;
2554
2555pub type NdTensorViewMut<'a, T, const N: usize> = TensorBase<ViewMutData<'a, T>, NdLayout<N>>;
2557
2558pub type CowNdTensor<'a, T, const N: usize> = TensorBase<CowData<'a, T>, NdLayout<N>>;
2565
2566pub type Matrix<'a, T = f32> = NdTensorView<'a, T, 2>;
2568
2569pub type MatrixMut<'a, T = f32> = NdTensorViewMut<'a, T, 2>;
2571
2572pub type Tensor<T = f32> = TensorBase<Vec<T>, DynLayout>;
2574
2575pub type TensorView<'a, T = f32> = TensorBase<ViewData<'a, T>, DynLayout>;
2577
2578pub type TensorViewMut<'a, T = f32> = TensorBase<ViewMutData<'a, T>, DynLayout>;
2580
2581pub type CowTensor<'a, T> = TensorBase<CowData<'a, T>, DynLayout>;
2588
2589pub type ArcTensor<T> = TensorBase<Arc<Vec<T>>, DynLayout>;
2595
2596pub type ArcNdTensor<T, const N: usize> = TensorBase<Arc<Vec<T>>, NdLayout<N>>;
2600
2601impl<T, S: Storage<Elem = T>, L: TrustedLayout, I: AsIndex<L>> Index<I> for TensorBase<S, L> {
2602 type Output = T;
2603
2604 fn index(&self, index: I) -> &Self::Output {
2608 let offset = self.layout.must_offset(index.as_index());
2609
2610 unsafe { self.data.get_unchecked(offset) }
2613 }
2614}
2615
2616impl<T, S: StorageMut<Elem = T>, L: TrustedLayout, I: AsIndex<L>> IndexMut<I> for TensorBase<S, L> {
2617 fn index_mut(&mut self, index: I) -> &mut Self::Output {
2621 let index = index.as_index();
2622 let offset = self.layout.must_offset(index);
2623
2624 unsafe { self.data.get_unchecked_mut(offset) }
2627 }
2628}
2629
2630impl<T, S: Storage<Elem = T> + Clone, L: Layout + Clone> Clone for TensorBase<S, L> {
2631 fn clone(&self) -> TensorBase<S, L> {
2632 let data = self.data.clone();
2633 TensorBase {
2634 data,
2635 layout: self.layout.clone(),
2636 }
2637 }
2638}
2639
2640impl<T, S: Storage<Elem = T> + Copy, L: Layout + Copy> Copy for TensorBase<S, L> {}
2641
2642impl<T: PartialEq, S: Storage<Elem = T>, L: Layout + Clone, V: AsView<Elem = T>> PartialEq<V>
2643 for TensorBase<S, L>
2644{
2645 fn eq(&self, other: &V) -> bool {
2646 self.shape().iter().eq(other.shape().iter()) && self.iter().eq(other.iter())
2647 }
2648}
2649
2650impl<T: Eq, S: Storage<Elem = T>, L: Layout + Clone> Eq for TensorBase<S, L> {}
2651
2652impl<T: Hash, S: Storage<Elem = T>, L: Layout + Clone> Hash for TensorBase<S, L> {
2653 fn hash<H: Hasher>(&self, state: &mut H) {
2654 for dim in self.shape().iter() {
2655 dim.hash(state);
2656 }
2657 for elem in self.iter() {
2658 elem.hash(state);
2659 }
2660 }
2661}
2662
2663impl<T, S: Storage<Elem = T>, const N: usize> From<TensorBase<S, NdLayout<N>>>
2664 for TensorBase<S, DynLayout>
2665{
2666 fn from(tensor: TensorBase<S, NdLayout<N>>) -> Self {
2667 Self {
2668 data: tensor.data,
2669 layout: tensor.layout.into(),
2670 }
2671 }
2672}
2673
2674impl<T, S1: Storage<Elem = T>, S2: Storage<Elem = T>, const N: usize>
2675 TryFrom<TensorBase<S1, DynLayout>> for TensorBase<S2, NdLayout<N>>
2676where
2677 S1: Into<S2>,
2678{
2679 type Error = DimensionError;
2680
2681 fn try_from(value: TensorBase<S1, DynLayout>) -> Result<Self, Self::Error> {
2685 let layout: NdLayout<N> = value.layout().try_into()?;
2686 Ok(TensorBase {
2687 data: value.data.into(),
2688 layout,
2689 })
2690 }
2691}
2692
2693pub trait Scalar {}
2698
2699macro_rules! impl_scalar {
2700 ($ty:ty) => {
2701 impl Scalar for $ty {}
2702 };
2703}
2704impl_scalar!(bool);
2705impl_scalar!(u8);
2706impl_scalar!(i8);
2707impl_scalar!(u16);
2708impl_scalar!(i16);
2709impl_scalar!(u32);
2710impl_scalar!(i32);
2711impl_scalar!(u64);
2712impl_scalar!(i64);
2713impl_scalar!(usize);
2714impl_scalar!(isize);
2715impl_scalar!(f32);
2716impl_scalar!(f64);
2717impl_scalar!(String);
2718
2719impl<T: Clone + Scalar, L: Clone + FromShape> From<T> for TensorBase<Vec<T>, L>
2724where
2725 [usize; 0]: AsShape<L>,
2726{
2727 fn from(value: T) -> Self {
2729 Self::from_scalar(value)
2730 }
2731}
2732
2733impl<T: Clone + Scalar, L: FromShape, const D0: usize> From<[T; D0]> for TensorBase<Vec<T>, L>
2734where
2735 [usize; 1]: AsShape<L>,
2736{
2737 fn from(value: [T; D0]) -> Self {
2739 let data: Vec<T> = value.iter().cloned().collect();
2740 Self::from_data([D0].as_shape(), data)
2741 }
2742}
2743
2744impl<T: Clone + Scalar, L: FromShape, const D0: usize, const D1: usize> From<[[T; D1]; D0]>
2745 for TensorBase<Vec<T>, L>
2746where
2747 [usize; 2]: AsShape<L>,
2748{
2749 fn from(value: [[T; D1]; D0]) -> Self {
2751 let data: Vec<_> = value.iter().flat_map(|y| y.iter()).cloned().collect();
2752 Self::from_data([D0, D1].as_shape(), data)
2753 }
2754}
2755
2756impl<T: Clone + Scalar, L: FromShape, const D0: usize, const D1: usize, const D2: usize>
2757 From<[[[T; D2]; D1]; D0]> for TensorBase<Vec<T>, L>
2758where
2759 [usize; 3]: AsShape<L>,
2760{
2761 fn from(value: [[[T; D2]; D1]; D0]) -> Self {
2763 let data: Vec<_> = value
2764 .iter()
2765 .flat_map(|y| y.iter().flat_map(|z| z.iter()))
2766 .cloned()
2767 .collect();
2768 Self::from_data([D0, D1, D2].as_shape(), data)
2769 }
2770}
2771
2772pub struct WeaklyCheckedView<S: Storage, L: Layout> {
2780 base: TensorBase<S, L>,
2781}
2782
2783impl<T, S: Storage<Elem = T>, L: Layout> Layout for WeaklyCheckedView<S, L> {
2784 type Shape<'a>
2785 = L::Shape<'a>
2786 where
2787 Self: 'a;
2788 type Strides<'a>
2789 = L::Strides<'a>
2790 where
2791 Self: 'a;
2792 type Index<'a> = L::Index<'a>;
2793 type Indices = L::Indices;
2794
2795 fn ndim(&self) -> usize {
2796 self.base.ndim()
2797 }
2798
2799 fn offset(&self, index: Self::Index<'_>) -> Option<usize> {
2800 self.base.offset(index)
2801 }
2802
2803 fn len(&self) -> usize {
2804 self.base.len()
2805 }
2806
2807 fn shape(&self) -> Self::Shape<'_> {
2808 self.base.shape()
2809 }
2810
2811 fn strides(&self) -> Self::Strides<'_> {
2812 self.base.strides()
2813 }
2814
2815 fn indices(&self) -> Self::Indices {
2816 self.base.indices()
2817 }
2818}
2819
2820impl<T, S: Storage<Elem = T>, L: Layout, I: AsIndex<L>> Index<I> for WeaklyCheckedView<S, L> {
2821 type Output = T;
2822 fn index(&self, index: I) -> &Self::Output {
2823 let offset = self.base.layout.offset_unchecked(index.as_index());
2824 unsafe {
2825 self.base.data.get(offset).expect("invalid offset")
2827 }
2828 }
2829}
2830
2831impl<T, S: StorageMut<Elem = T>, L: Layout, I: AsIndex<L>> IndexMut<I> for WeaklyCheckedView<S, L> {
2832 fn index_mut(&mut self, index: I) -> &mut Self::Output {
2833 let offset = self.base.layout.offset_unchecked(index.as_index());
2834 unsafe {
2835 self.base.data.get_mut(offset).expect("invalid offset")
2837 }
2838 }
2839}
2840
2841#[cfg(test)]
2842mod tests;