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 is_owned(&self) -> bool {
1514 matches!(self.data, CowData::Owned(_))
1515 }
1516
1517 pub fn into_owned(self) -> TensorBase<Vec<T>, L>
1521 where
1522 L: Clone + FromShape,
1523 T: Clone,
1524 {
1525 self.into_owned_in(GlobalAlloc::new())
1526 }
1527
1528 pub fn into_owned_in<A: Alloc>(self, alloc: A) -> TensorBase<Vec<T>, L>
1530 where
1531 L: Clone + FromShape,
1532 T: Clone,
1533 {
1534 match self.data {
1535 CowData::Owned(data) => TensorBase {
1536 data,
1537 layout: self.layout,
1538 },
1539 CowData::Borrowed(_) => {
1540 let data = self.to_vec_in(alloc);
1541 let layout = L::from_shape(self.shape());
1542 TensorBase { data, layout }
1543 }
1544 }
1545 }
1546
1547 pub fn into_shape<S: Clone + IntoLayout>(
1551 self,
1552 shape: S,
1553 ) -> TensorBase<CowData<'a, T>, S::Layout>
1554 where
1555 T: Clone,
1556 L: Clone,
1557 {
1558 self.into_shape_in(GlobalAlloc::new(), shape)
1559 }
1560
1561 pub fn into_shape_in<A: Alloc, S: Clone + IntoLayout>(
1563 self,
1564 alloc: A,
1565 shape: S,
1566 ) -> TensorBase<CowData<'a, T>, S::Layout>
1567 where
1568 T: Clone,
1569 L: Clone,
1570 {
1571 if let Ok(layout) = self.layout.reshaped_for_view(shape.clone()) {
1572 TensorBase {
1573 data: self.data,
1574 layout,
1575 }
1576 } else {
1577 let Ok(layout) = self.layout.reshaped_for_copy(shape.clone()) else {
1578 panic!(
1579 "element count mismatch reshaping {:?} to {:?}",
1580 self.shape(),
1581 shape
1582 );
1583 };
1584
1585 TensorBase {
1586 data: CowData::Owned(self.to_vec_in(alloc)),
1587 layout,
1588 }
1589 }
1590 }
1591}
1592
1593pub enum InitEmpty<Init: Storage, Uninit: Storage, L: Layout> {
1595 Empty(TensorBase<Init, L>),
1597 NotEmpty(TensorBase<Uninit, L>),
1599}
1600
1601impl<T, S: Storage<Elem = MaybeUninit<T>> + AssumeInit, L: Layout + Clone> TensorBase<S, L>
1602where
1603 <S as AssumeInit>::Output: Storage<Elem = T>,
1604{
1605 pub unsafe fn assume_init(self) -> TensorBase<<S as AssumeInit>::Output, L> {
1615 TensorBase {
1616 layout: self.layout,
1617 data: unsafe { self.data.assume_init() },
1618 }
1619 }
1620
1621 pub fn init_if_empty(self) -> InitEmpty<<S as AssumeInit>::Output, S, L> {
1623 if self.is_empty() {
1624 InitEmpty::Empty(unsafe { self.assume_init() })
1626 } else {
1627 InitEmpty::NotEmpty(self)
1628 }
1629 }
1630
1631 pub fn init_from<S2: Storage<Elem = T>>(
1635 mut self,
1636 other: &TensorBase<S2, L>,
1637 ) -> TensorBase<<S as AssumeInit>::Output, L>
1638 where
1639 T: Copy,
1640 S: StorageMut<Elem = MaybeUninit<T>>,
1641 {
1642 assert_eq!(self.shape(), other.shape(), "shape mismatch");
1643
1644 match (self.data_mut(), other.data()) {
1645 (Some(self_data), Some(other_data)) => {
1647 let other_data: &[MaybeUninit<T>] = unsafe { std::mem::transmute(other_data) };
1648 self_data.clone_from_slice(other_data);
1649 }
1650 (Some(self_data), _) => {
1652 copy_into_slice(other.as_dyn(), self_data);
1653 }
1654 _ => {
1656 copy_into_uninit(other.as_dyn(), self.as_dyn_mut());
1657 }
1658 }
1659
1660 unsafe { self.assume_init() }
1661 }
1662}
1663
1664impl<'a, T, L: Clone + Layout> TensorBase<ViewData<'a, T>, L> {
1665 pub fn axis_iter(&self, dim: usize) -> AxisIter<'a, T, L>
1666 where
1667 L: MutLayout + RemoveDim,
1668 {
1669 AxisIter::new(self, dim)
1670 }
1671
1672 pub fn axis_chunks(&self, dim: usize, chunk_size: usize) -> AxisChunks<'a, T, L>
1673 where
1674 L: MutLayout,
1675 {
1676 AxisChunks::new(self, dim, chunk_size)
1677 }
1678
1679 pub fn as_dyn(&self) -> TensorBase<ViewData<'a, T>, DynLayout> {
1683 TensorBase {
1684 data: self.data,
1685 layout: DynLayout::from(&self.layout),
1686 }
1687 }
1688
1689 pub fn as_cow(&self) -> TensorBase<CowData<'a, T>, L> {
1693 TensorBase {
1694 layout: self.layout.clone(),
1695 data: CowData::Borrowed(self.data),
1696 }
1697 }
1698
1699 pub fn broadcast<S: IntoLayout>(&self, shape: S) -> TensorBase<ViewData<'a, T>, S::Layout>
1703 where
1704 L: BroadcastLayout<S::Layout>,
1705 {
1706 self.try_broadcast(shape).unwrap()
1707 }
1708
1709 pub fn try_broadcast<S: IntoLayout>(
1713 &self,
1714 shape: S,
1715 ) -> Result<TensorBase<ViewData<'a, T>, S::Layout>, ExpandError>
1716 where
1717 L: BroadcastLayout<S::Layout>,
1718 {
1719 Ok(TensorBase {
1720 layout: self.layout.broadcast(shape)?,
1721 data: self.data,
1722 })
1723 }
1724
1725 pub fn data(&self) -> Option<&'a [T]> {
1729 let len = self.layout.min_data_len();
1732 let data = self.data.slice(0..len);
1733
1734 self.layout.is_contiguous().then(|| unsafe {
1735 data.as_slice()
1737 })
1738 }
1739
1740 pub fn storage(&self) -> ViewData<'a, T> {
1742 self.data.view()
1743 }
1744
1745 pub fn get<I: AsIndex<L>>(&self, index: I) -> Option<&'a T>
1746 where
1747 L: TrustedLayout,
1748 {
1749 self.offset(index.as_index()).map(|offset|
1750 unsafe {
1755 self.data.get_unchecked(offset)
1756 })
1757 }
1758
1759 pub fn from_slice_with_strides(
1765 shape: L::Shape<'_>,
1766 data: &'a [T],
1767 strides: L::Strides<'_>,
1768 ) -> Result<TensorBase<ViewData<'a, T>, L>, FromDataError>
1769 where
1770 L: MutLayout,
1771 {
1772 let layout = L::from_shape_and_strides(shape, strides, OverlapPolicy::AllowOverlap)?;
1773 if layout.min_data_len() > data.as_ref().len() {
1774 return Err(FromDataError::StorageTooShort);
1775 }
1776 Ok(TensorBase {
1777 data: data.into_storage(),
1778 layout,
1779 })
1780 }
1781
1782 pub unsafe fn get_unchecked<I: AsIndex<L>>(&self, index: I) -> &'a T {
1789 let offset = self.layout.offset_unchecked(index.as_index());
1790 unsafe { self.data.get_unchecked(offset) }
1791 }
1792
1793 pub fn index_axis(
1799 &self,
1800 axis: usize,
1801 index: usize,
1802 ) -> TensorBase<ViewData<'a, T>, <L as RemoveDim>::Output>
1803 where
1804 L: MutLayout + RemoveDim,
1805 {
1806 let (offsets, layout) = self.layout.index_axis(axis, index);
1807 TensorBase {
1808 data: self.data.slice(offsets),
1809 layout,
1810 }
1811 }
1812
1813 pub fn inner_iter<const N: usize>(&self) -> InnerIter<'a, T, NdLayout<N>> {
1817 InnerIter::new(self.view())
1818 }
1819
1820 pub fn inner_iter_dyn(&self, n: usize) -> InnerIter<'a, T, DynLayout> {
1824 InnerIter::new_dyn(self.view(), n)
1825 }
1826
1827 pub fn item(&self) -> Option<&'a T> {
1829 match self.ndim() {
1830 0 => unsafe {
1831 self.data.get(0)
1833 },
1834 _ if self.len() == 1 => self.iter().next(),
1835 _ => None,
1836 }
1837 }
1838
1839 pub fn iter(&self) -> Iter<'a, T> {
1843 Iter::new(self.view_ref())
1844 }
1845
1846 pub fn lanes(&self, dim: usize) -> Lanes<'a, T>
1850 where
1851 L: RemoveDim,
1852 {
1853 assert!(dim < self.ndim());
1854 Lanes::new(self.view_ref(), dim)
1855 }
1856
1857 pub fn nd_view<const N: usize>(&self) -> TensorBase<ViewData<'a, T>, NdLayout<N>> {
1861 assert!(self.ndim() == N, "ndim {} != {}", self.ndim(), N);
1862 TensorBase {
1863 data: self.data,
1864 layout: self.nd_layout().unwrap(),
1865 }
1866 }
1867
1868 pub fn permuted(&self, order: L::Index<'_>) -> TensorBase<ViewData<'a, T>, L>
1872 where
1873 L: MutLayout,
1874 {
1875 TensorBase {
1876 data: self.data,
1877 layout: self.layout.permuted(order),
1878 }
1879 }
1880
1881 pub fn reshaped<S: Copy + IntoLayout>(&self, shape: S) -> TensorBase<CowData<'a, T>, S::Layout>
1885 where
1886 T: Clone,
1887 {
1888 self.reshaped_in(GlobalAlloc::new(), shape)
1889 }
1890
1891 pub fn reshaped_in<A: Alloc, S: Copy + IntoLayout>(
1893 &self,
1894 alloc: A,
1895 shape: S,
1896 ) -> TensorBase<CowData<'a, T>, S::Layout>
1897 where
1898 T: Clone,
1899 {
1900 if let Ok(layout) = self.layout.reshaped_for_view(shape) {
1901 TensorBase {
1902 data: CowData::Borrowed(self.data),
1903 layout,
1904 }
1905 } else {
1906 let Ok(layout) = self.layout.reshaped_for_copy(shape) else {
1907 panic!(
1908 "element count mismatch reshaping {:?} to {:?}",
1909 self.shape(),
1910 shape
1911 );
1912 };
1913
1914 TensorBase {
1915 data: CowData::Owned(self.to_vec_in(alloc)),
1916 layout,
1917 }
1918 }
1919 }
1920
1921 pub fn slice<R: IntoSliceItems + IndexCount>(
1923 &self,
1924 range: R,
1925 ) -> TensorBase<ViewData<'a, T>, <L as SliceWith<R, R::Count>>::Layout>
1926 where
1927 L: SliceWith<R, R::Count>,
1928 {
1929 self.try_slice(range).expect("slice failed")
1930 }
1931
1932 pub fn slice_axis(&self, axis: usize, range: Range<usize>) -> TensorBase<ViewData<'a, T>, L>
1934 where
1935 L: MutLayout,
1936 {
1937 let (offset_range, sliced_layout) = self.layout.slice_axis(axis, range.clone()).unwrap();
1938 debug_assert_eq!(sliced_layout.size(axis), range.len());
1939 TensorBase {
1940 data: self.data.slice(offset_range),
1941 layout: sliced_layout,
1942 }
1943 }
1944
1945 #[allow(clippy::type_complexity)]
1948 pub fn try_slice<R: IntoSliceItems + IndexCount>(
1949 &self,
1950 range: R,
1951 ) -> Result<TensorBase<ViewData<'a, T>, <L as SliceWith<R, R::Count>>::Layout>, SliceError>
1952 where
1953 L: SliceWith<R, R::Count>,
1954 {
1955 let (offset_range, sliced_layout) = self.layout.slice_with(range)?;
1956 Ok(TensorBase {
1957 data: self.data.slice(offset_range),
1958 layout: sliced_layout,
1959 })
1960 }
1961
1962 pub fn squeezed(&self) -> TensorView<'a, T>
1966 where
1967 L: MutLayout,
1968 {
1969 TensorBase {
1970 data: self.data.view(),
1971 layout: self.layout.squeezed(),
1972 }
1973 }
1974
1975 #[allow(clippy::type_complexity)]
1981 pub fn split_at(
1982 &self,
1983 axis: usize,
1984 mid: usize,
1985 ) -> (
1986 TensorBase<ViewData<'a, T>, L>,
1987 TensorBase<ViewData<'a, T>, L>,
1988 )
1989 where
1990 L: MutLayout,
1991 {
1992 let (left, right) = self.layout.split(axis, mid);
1993 let (left_offset_range, left_layout) = left;
1994 let (right_offset_range, right_layout) = right;
1995 let left_data = self.data.slice(left_offset_range.clone());
1996 let right_data = self.data.slice(right_offset_range.clone());
1997
1998 debug_assert_eq!(left_data.len(), left_layout.min_data_len());
1999 let left_view = TensorBase {
2000 data: left_data,
2001 layout: left_layout,
2002 };
2003
2004 debug_assert_eq!(right_data.len(), right_layout.min_data_len());
2005 let right_view = TensorBase {
2006 data: right_data,
2007 layout: right_layout,
2008 };
2009
2010 (left_view, right_view)
2011 }
2012
2013 pub fn to_contiguous(&self) -> Contiguous<TensorBase<CowData<'a, T>, L>>
2018 where
2019 T: Clone,
2020 L: FromShape,
2021 {
2022 self.to_contiguous_in(GlobalAlloc::new())
2023 }
2024
2025 pub fn to_contiguous_in<A: Alloc>(&self, alloc: A) -> Contiguous<TensorBase<CowData<'a, T>, L>>
2028 where
2029 T: Clone,
2030 L: FromShape,
2031 {
2032 let tensor = if let Some(data) = self.data() {
2033 TensorBase {
2034 data: CowData::Borrowed(data.into_storage()),
2035 layout: self.layout.clone(),
2036 }
2037 } else {
2038 let data = self.to_vec_in(alloc);
2039 TensorBase {
2040 data: CowData::Owned(data),
2041 layout: L::from_shape(self.layout.shape()),
2042 }
2043 };
2044 Contiguous::new(tensor).unwrap()
2045 }
2046
2047 pub fn to_slice(&self) -> Cow<'a, [T]>
2052 where
2053 T: Clone,
2054 {
2055 self.data()
2056 .map(Cow::Borrowed)
2057 .unwrap_or_else(|| Cow::Owned(self.to_vec()))
2058 }
2059
2060 pub fn transposed(&self) -> TensorBase<ViewData<'a, T>, L>
2062 where
2063 L: MutLayout,
2064 {
2065 TensorBase {
2066 data: self.data,
2067 layout: self.layout.transposed(),
2068 }
2069 }
2070
2071 pub fn try_slice_dyn<R: IntoSliceItems>(
2072 &self,
2073 range: R,
2074 ) -> Result<TensorView<'a, T>, SliceError>
2075 where
2076 L: MutLayout,
2077 {
2078 let (offset_range, layout) = self.layout.slice_dyn(range.into_slice_items().as_ref())?;
2079 Ok(TensorBase {
2080 data: self.data.slice(offset_range),
2081 layout,
2082 })
2083 }
2084
2085 pub fn view(&self) -> TensorBase<ViewData<'a, T>, L> {
2087 TensorBase {
2088 data: self.data,
2089 layout: self.layout.clone(),
2090 }
2091 }
2092
2093 pub(crate) fn view_ref(&self) -> TensorBase<ViewData<'a, T>, &L> {
2094 TensorBase {
2095 data: self.data,
2096 layout: &self.layout,
2097 }
2098 }
2099
2100 pub fn weakly_checked_view(&self) -> WeaklyCheckedView<ViewData<'a, T>, L> {
2101 WeaklyCheckedView { base: self.view() }
2102 }
2103}
2104
2105impl<S: Storage, L: Layout> Layout for TensorBase<S, L> {
2106 type Shape<'a>
2107 = L::Shape<'a>
2108 where
2109 Self: 'a;
2110 type Strides<'a>
2111 = L::Strides<'a>
2112 where
2113 Self: 'a;
2114 type Index<'a> = L::Index<'a>;
2115 type Indices = L::Indices;
2116
2117 fn ndim(&self) -> usize {
2118 self.layout.ndim()
2119 }
2120
2121 fn len(&self) -> usize {
2122 self.layout.len()
2123 }
2124
2125 fn is_empty(&self) -> bool {
2126 self.layout.is_empty()
2127 }
2128
2129 fn shape(&self) -> Self::Shape<'_> {
2130 self.layout.shape()
2131 }
2132
2133 fn size(&self, dim: usize) -> usize {
2134 self.layout.size(dim)
2135 }
2136
2137 fn strides(&self) -> Self::Strides<'_> {
2138 self.layout.strides()
2139 }
2140
2141 fn stride(&self, dim: usize) -> usize {
2142 self.layout.stride(dim)
2143 }
2144
2145 fn indices(&self) -> Self::Indices {
2146 self.layout.indices()
2147 }
2148
2149 fn offset(&self, index: Self::Index<'_>) -> Option<usize> {
2150 self.layout.offset(index)
2151 }
2152}
2153
2154impl<S: Storage, L: Layout + MatrixLayout> MatrixLayout for TensorBase<S, L> {
2155 fn rows(&self) -> usize {
2156 self.layout.rows()
2157 }
2158
2159 fn cols(&self) -> usize {
2160 self.layout.cols()
2161 }
2162
2163 fn row_stride(&self) -> usize {
2164 self.layout.row_stride()
2165 }
2166
2167 fn col_stride(&self) -> usize {
2168 self.layout.col_stride()
2169 }
2170}
2171
2172impl<T, S: Storage<Elem = T>, L: Layout + Clone> AsView for TensorBase<S, L> {
2173 type Elem = T;
2174 type Layout = L;
2175
2176 fn iter(&self) -> Iter<'_, T> {
2177 self.view().iter()
2178 }
2179
2180 fn copy_into_slice<'a>(&self, dest: &'a mut [MaybeUninit<T>]) -> &'a [T]
2181 where
2182 T: Copy,
2183 {
2184 if let Some(data) = self.data() {
2185 let src_uninit = unsafe { std::mem::transmute::<&[T], &[MaybeUninit<T>]>(data) };
2187 dest.copy_from_slice(src_uninit);
2188 unsafe { dest.assume_init() }
2191 } else {
2192 copy_into_slice(self.as_dyn(), dest)
2193 }
2194 }
2195
2196 fn data(&self) -> Option<&[Self::Elem]> {
2197 self.view().data()
2198 }
2199
2200 fn insert_axis(&mut self, index: usize)
2201 where
2202 L: ResizeLayout,
2203 {
2204 self.layout.insert_axis(index)
2205 }
2206
2207 #[track_caller]
2208 fn remove_axis(&mut self, index: usize)
2209 where
2210 L: ResizeLayout,
2211 {
2212 self.layout.remove_axis(index)
2213 }
2214
2215 fn merge_axes(&mut self)
2216 where
2217 L: ResizeLayout,
2218 {
2219 self.layout.merge_axes()
2220 }
2221
2222 fn layout(&self) -> &L {
2223 &self.layout
2224 }
2225
2226 fn map<F, U>(&self, f: F) -> TensorBase<Vec<U>, L>
2227 where
2228 F: Fn(&Self::Elem) -> U,
2229 L: FromShape,
2230 {
2231 self.map_in(GlobalAlloc::new(), f)
2232 }
2233
2234 fn map_in<A: Alloc, F, U>(&self, alloc: A, f: F) -> TensorBase<Vec<U>, L>
2235 where
2236 F: Fn(&Self::Elem) -> U,
2237 L: FromShape,
2238 {
2239 let len = self.len();
2240 let mut buf = alloc.alloc(len);
2241 if let Some(data) = self.data() {
2242 buf.extend(data.iter().map(f));
2244 } else {
2245 let dest = &mut buf.spare_capacity_mut()[..len];
2246 map_into_slice(self.as_dyn(), dest, f);
2247
2248 unsafe {
2250 buf.set_len(len);
2251 }
2252 };
2253 TensorBase::from_data(self.shape(), buf)
2254 }
2255
2256 fn move_axis(&mut self, from: usize, to: usize)
2257 where
2258 L: MutLayout,
2259 {
2260 self.layout.move_axis(from, to);
2261 }
2262
2263 fn view(&self) -> TensorBase<ViewData<'_, T>, L> {
2264 TensorBase {
2265 data: self.data.view(),
2266 layout: self.layout.clone(),
2267 }
2268 }
2269
2270 fn get<I: AsIndex<L>>(&self, index: I) -> Option<&Self::Elem> {
2274 self.offset(index.as_index()).map(|offset| unsafe {
2275 self.data.get_unchecked(offset)
2277 })
2278 }
2279
2280 unsafe fn get_unchecked<I: AsIndex<L>>(&self, index: I) -> &T {
2281 let offset = self.layout.offset_unchecked(index.as_index());
2282 unsafe { self.data.get_unchecked(offset) }
2283 }
2284
2285 fn permute(&mut self, order: Self::Index<'_>)
2286 where
2287 L: MutLayout,
2288 {
2289 self.layout = self.layout.permuted(order);
2290 }
2291
2292 fn to_vec(&self) -> Vec<T>
2293 where
2294 T: Clone,
2295 {
2296 self.to_vec_in(GlobalAlloc::new())
2297 }
2298
2299 fn to_vec_in<A: Alloc>(&self, alloc: A) -> Vec<T>
2300 where
2301 T: Clone,
2302 {
2303 let len = self.len();
2304 let mut buf = alloc.alloc(len);
2305
2306 if let Some(data) = self.data() {
2307 buf.extend_from_slice(data);
2308 } else {
2309 copy_into_slice(self.as_dyn(), &mut buf.spare_capacity_mut()[..len]);
2310
2311 unsafe { buf.set_len(len) }
2313 }
2314
2315 buf
2316 }
2317
2318 fn to_shape<SH: IntoLayout>(&self, shape: SH) -> TensorBase<Vec<Self::Elem>, SH::Layout>
2319 where
2320 T: Clone,
2321 {
2322 TensorBase {
2323 data: self.to_vec(),
2324 layout: self
2325 .layout
2326 .reshaped_for_copy(shape)
2327 .expect("reshape failed"),
2328 }
2329 }
2330
2331 fn transpose(&mut self)
2332 where
2333 L: MutLayout,
2334 {
2335 self.layout = self.layout.transposed();
2336 }
2337}
2338
2339impl<T, S: Storage<Elem = T>, const N: usize> TensorBase<S, NdLayout<N>> {
2340 #[inline]
2348 pub fn get_array<const M: usize>(&self, base: [usize; N], dim: usize) -> [T; M]
2349 where
2350 T: Copy + Default,
2351 {
2352 let offsets: [usize; M] = array_offsets(&self.layout, base, dim);
2353 let mut result = [T::default(); M];
2354 for i in 0..M {
2355 result[i] = unsafe { *self.data.get_unchecked(offsets[i]) };
2357 }
2358 result
2359 }
2360}
2361
2362impl<T> TensorBase<Vec<T>, DynLayout> {
2363 #[track_caller]
2366 pub fn reshape(&mut self, shape: &[usize])
2367 where
2368 T: Clone,
2369 {
2370 self.reshape_in(GlobalAlloc::new(), shape)
2371 }
2372
2373 #[track_caller]
2375 pub fn reshape_in<A: Alloc>(&mut self, alloc: A, shape: &[usize])
2376 where
2377 T: Clone,
2378 {
2379 if !self.is_contiguous() {
2380 self.data = self.to_vec_in(alloc);
2381 }
2382 let Ok(layout) = self.layout.reshaped_for_copy(shape) else {
2383 panic!(
2384 "element count mismatch reshaping {:?} to {:?}",
2385 self.shape(),
2386 shape
2387 );
2388 };
2389 self.layout = layout;
2390 }
2391}
2392
2393impl<'a, T, L: Layout> TensorBase<ViewMutData<'a, T>, L> {
2394 #[allow(clippy::type_complexity)]
2400 pub fn split_at_mut(
2401 self,
2402 axis: usize,
2403 mid: usize,
2404 ) -> (
2405 TensorBase<ViewMutData<'a, T>, L>,
2406 TensorBase<ViewMutData<'a, T>, L>,
2407 )
2408 where
2409 L: MutLayout,
2410 {
2411 let (left, right) = self.layout.split(axis, mid);
2412 let (left_offset_range, left_layout) = left;
2413 let (right_offset_range, right_layout) = right;
2414 let (left_data, right_data) = self
2415 .data
2416 .split_mut(left_offset_range.clone(), right_offset_range.clone());
2417
2418 debug_assert_eq!(left_data.len(), left_layout.min_data_len());
2419 let left_view = TensorBase {
2420 data: left_data,
2421 layout: left_layout,
2422 };
2423
2424 debug_assert_eq!(right_data.len(), right_layout.min_data_len());
2425 let right_view = TensorBase {
2426 data: right_data,
2427 layout: right_layout,
2428 };
2429
2430 (left_view, right_view)
2431 }
2432
2433 pub fn into_slice_mut(self) -> Option<&'a mut [T]> {
2436 let len = self.layout.min_data_len();
2437 self.is_contiguous().then(|| {
2438 let slice = unsafe { self.data.to_slice_mut() };
2440 &mut slice[..len]
2441 })
2442 }
2443}
2444
2445impl<T, L: FromShape> FromIterator<T> for TensorBase<Vec<T>, L>
2446where
2447 [usize; 1]: AsShape<L>,
2448{
2449 fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> TensorBase<Vec<T>, L> {
2453 let data: Vec<T> = iter.into_iter().collect();
2454 TensorBase::from_data([data.len()].as_shape(), data)
2455 }
2456}
2457
2458impl<T, L: FromShape> From<Vec<T>> for TensorBase<Vec<T>, L>
2459where
2460 [usize; 1]: AsShape<L>,
2461{
2462 fn from(vec: Vec<T>) -> Self {
2464 Self::from_data([vec.len()].as_shape(), vec)
2465 }
2466}
2467
2468impl<'a, T, L: FromShape> From<&'a [T]> for TensorBase<ViewData<'a, T>, L>
2469where
2470 [usize; 1]: AsShape<L>,
2471{
2472 fn from(slice: &'a [T]) -> Self {
2474 Self::from_data([slice.len()].as_shape(), slice)
2475 }
2476}
2477
2478impl<'a, T, L: FromShape, const N: usize> From<&'a [T; N]> for TensorBase<ViewData<'a, T>, L>
2479where
2480 [usize; 1]: AsShape<L>,
2481{
2482 fn from(slice: &'a [T; N]) -> Self {
2484 Self::from_data([slice.len()].as_shape(), slice.as_slice())
2485 }
2486}
2487
2488fn array_offsets<const N: usize, const M: usize>(
2493 layout: &NdLayout<N>,
2494 base: [usize; N],
2495 dim: usize,
2496) -> [usize; M] {
2497 assert!(
2498 base[dim] < usize::MAX - M && layout.size(dim) >= base[dim] + M,
2499 "array indices invalid"
2500 );
2501
2502 let offset = layout.must_offset(base);
2503 let stride = layout.stride(dim);
2504 let mut offsets = [0; M];
2505 for i in 0..M {
2506 offsets[i] = offset + i * stride;
2507 }
2508 offsets
2509}
2510
2511impl<T, S: StorageMut<Elem = T>, const N: usize> TensorBase<S, NdLayout<N>> {
2512 #[inline]
2517 pub fn set_array<const M: usize>(&mut self, base: [usize; N], dim: usize, values: [T; M])
2518 where
2519 T: Copy,
2520 {
2521 let offsets: [usize; M] = array_offsets(&self.layout, base, dim);
2522
2523 for i in 0..M {
2524 unsafe { *self.data.get_unchecked_mut(offsets[i]) = values[i] };
2526 }
2527 }
2528}
2529
2530impl<T, S: Storage<Elem = T>> TensorBase<S, NdLayout<1>> {
2531 #[inline]
2535 pub fn to_array<const M: usize>(&self) -> [T; M]
2536 where
2537 T: Copy + Default,
2538 {
2539 self.get_array([0], 0)
2540 }
2541}
2542
2543impl<T, S: StorageMut<Elem = T>> TensorBase<S, NdLayout<1>> {
2544 #[inline]
2548 pub fn assign_array<const M: usize>(&mut self, values: [T; M])
2549 where
2550 T: Copy + Default,
2551 {
2552 self.set_array([0], 0, values)
2553 }
2554}
2555
2556pub type NdTensorView<'a, T, const N: usize> = TensorBase<ViewData<'a, T>, NdLayout<N>>;
2558
2559pub type NdTensor<T, const N: usize> = TensorBase<Vec<T>, NdLayout<N>>;
2561
2562pub type NdTensorViewMut<'a, T, const N: usize> = TensorBase<ViewMutData<'a, T>, NdLayout<N>>;
2564
2565pub type CowNdTensor<'a, T, const N: usize> = TensorBase<CowData<'a, T>, NdLayout<N>>;
2572
2573pub type Matrix<'a, T = f32> = NdTensorView<'a, T, 2>;
2575
2576pub type MatrixMut<'a, T = f32> = NdTensorViewMut<'a, T, 2>;
2578
2579pub type Tensor<T = f32> = TensorBase<Vec<T>, DynLayout>;
2581
2582pub type TensorView<'a, T = f32> = TensorBase<ViewData<'a, T>, DynLayout>;
2584
2585pub type TensorViewMut<'a, T = f32> = TensorBase<ViewMutData<'a, T>, DynLayout>;
2587
2588pub type CowTensor<'a, T> = TensorBase<CowData<'a, T>, DynLayout>;
2595
2596pub type ArcTensor<T> = TensorBase<Arc<Vec<T>>, DynLayout>;
2602
2603pub type ArcNdTensor<T, const N: usize> = TensorBase<Arc<Vec<T>>, NdLayout<N>>;
2607
2608impl<T, S: Storage<Elem = T>, L: TrustedLayout, I: AsIndex<L>> Index<I> for TensorBase<S, L> {
2609 type Output = T;
2610
2611 fn index(&self, index: I) -> &Self::Output {
2615 let offset = self.layout.must_offset(index.as_index());
2616
2617 unsafe { self.data.get_unchecked(offset) }
2620 }
2621}
2622
2623impl<T, S: StorageMut<Elem = T>, L: TrustedLayout, I: AsIndex<L>> IndexMut<I> for TensorBase<S, L> {
2624 fn index_mut(&mut self, index: I) -> &mut Self::Output {
2628 let index = index.as_index();
2629 let offset = self.layout.must_offset(index);
2630
2631 unsafe { self.data.get_unchecked_mut(offset) }
2634 }
2635}
2636
2637impl<T, S: Storage<Elem = T> + Clone, L: Layout + Clone> Clone for TensorBase<S, L> {
2638 fn clone(&self) -> TensorBase<S, L> {
2639 let data = self.data.clone();
2640 TensorBase {
2641 data,
2642 layout: self.layout.clone(),
2643 }
2644 }
2645}
2646
2647impl<T, S: Storage<Elem = T> + Copy, L: Layout + Copy> Copy for TensorBase<S, L> {}
2648
2649impl<T: PartialEq, S: Storage<Elem = T>, L: Layout + Clone, V: AsView<Elem = T>> PartialEq<V>
2650 for TensorBase<S, L>
2651{
2652 fn eq(&self, other: &V) -> bool {
2653 self.shape().iter().eq(other.shape().iter()) && self.iter().eq(other.iter())
2654 }
2655}
2656
2657impl<T: Eq, S: Storage<Elem = T>, L: Layout + Clone> Eq for TensorBase<S, L> {}
2658
2659impl<T: Hash, S: Storage<Elem = T>, L: Layout + Clone> Hash for TensorBase<S, L> {
2660 fn hash<H: Hasher>(&self, state: &mut H) {
2661 for dim in self.shape().iter() {
2662 dim.hash(state);
2663 }
2664 for elem in self.iter() {
2665 elem.hash(state);
2666 }
2667 }
2668}
2669
2670impl<T, S: Storage<Elem = T>, const N: usize> From<TensorBase<S, NdLayout<N>>>
2671 for TensorBase<S, DynLayout>
2672{
2673 fn from(tensor: TensorBase<S, NdLayout<N>>) -> Self {
2674 Self {
2675 data: tensor.data,
2676 layout: tensor.layout.into(),
2677 }
2678 }
2679}
2680
2681impl<T, S1: Storage<Elem = T>, S2: Storage<Elem = T>, const N: usize>
2682 TryFrom<TensorBase<S1, DynLayout>> for TensorBase<S2, NdLayout<N>>
2683where
2684 S1: Into<S2>,
2685{
2686 type Error = DimensionError;
2687
2688 fn try_from(value: TensorBase<S1, DynLayout>) -> Result<Self, Self::Error> {
2692 let layout: NdLayout<N> = value.layout().try_into()?;
2693 Ok(TensorBase {
2694 data: value.data.into(),
2695 layout,
2696 })
2697 }
2698}
2699
2700pub trait Scalar {}
2705
2706macro_rules! impl_scalar {
2707 ($ty:ty) => {
2708 impl Scalar for $ty {}
2709 };
2710}
2711impl_scalar!(bool);
2712impl_scalar!(u8);
2713impl_scalar!(i8);
2714impl_scalar!(u16);
2715impl_scalar!(i16);
2716impl_scalar!(u32);
2717impl_scalar!(i32);
2718impl_scalar!(u64);
2719impl_scalar!(i64);
2720impl_scalar!(usize);
2721impl_scalar!(isize);
2722impl_scalar!(f32);
2723impl_scalar!(f64);
2724impl_scalar!(String);
2725
2726impl<T: Clone + Scalar, L: Clone + FromShape> From<T> for TensorBase<Vec<T>, L>
2731where
2732 [usize; 0]: AsShape<L>,
2733{
2734 fn from(value: T) -> Self {
2736 Self::from_scalar(value)
2737 }
2738}
2739
2740impl<T: Clone + Scalar, L: FromShape, const D0: usize> From<[T; D0]> for TensorBase<Vec<T>, L>
2741where
2742 [usize; 1]: AsShape<L>,
2743{
2744 fn from(value: [T; D0]) -> Self {
2746 let data: Vec<T> = value.iter().cloned().collect();
2747 Self::from_data([D0].as_shape(), data)
2748 }
2749}
2750
2751impl<T: Clone + Scalar, L: FromShape, const D0: usize, const D1: usize> From<[[T; D1]; D0]>
2752 for TensorBase<Vec<T>, L>
2753where
2754 [usize; 2]: AsShape<L>,
2755{
2756 fn from(value: [[T; D1]; D0]) -> Self {
2758 let data: Vec<_> = value.iter().flat_map(|y| y.iter()).cloned().collect();
2759 Self::from_data([D0, D1].as_shape(), data)
2760 }
2761}
2762
2763impl<T: Clone + Scalar, L: FromShape, const D0: usize, const D1: usize, const D2: usize>
2764 From<[[[T; D2]; D1]; D0]> for TensorBase<Vec<T>, L>
2765where
2766 [usize; 3]: AsShape<L>,
2767{
2768 fn from(value: [[[T; D2]; D1]; D0]) -> Self {
2770 let data: Vec<_> = value
2771 .iter()
2772 .flat_map(|y| y.iter().flat_map(|z| z.iter()))
2773 .cloned()
2774 .collect();
2775 Self::from_data([D0, D1, D2].as_shape(), data)
2776 }
2777}
2778
2779pub struct WeaklyCheckedView<S: Storage, L: Layout> {
2787 base: TensorBase<S, L>,
2788}
2789
2790impl<T, S: Storage<Elem = T>, L: Layout> Layout for WeaklyCheckedView<S, L> {
2791 type Shape<'a>
2792 = L::Shape<'a>
2793 where
2794 Self: 'a;
2795 type Strides<'a>
2796 = L::Strides<'a>
2797 where
2798 Self: 'a;
2799 type Index<'a> = L::Index<'a>;
2800 type Indices = L::Indices;
2801
2802 fn ndim(&self) -> usize {
2803 self.base.ndim()
2804 }
2805
2806 fn offset(&self, index: Self::Index<'_>) -> Option<usize> {
2807 self.base.offset(index)
2808 }
2809
2810 fn len(&self) -> usize {
2811 self.base.len()
2812 }
2813
2814 fn shape(&self) -> Self::Shape<'_> {
2815 self.base.shape()
2816 }
2817
2818 fn strides(&self) -> Self::Strides<'_> {
2819 self.base.strides()
2820 }
2821
2822 fn indices(&self) -> Self::Indices {
2823 self.base.indices()
2824 }
2825}
2826
2827impl<T, S: Storage<Elem = T>, L: Layout, I: AsIndex<L>> Index<I> for WeaklyCheckedView<S, L> {
2828 type Output = T;
2829 fn index(&self, index: I) -> &Self::Output {
2830 let offset = self.base.layout.offset_unchecked(index.as_index());
2831 unsafe {
2832 self.base.data.get(offset).expect("invalid offset")
2834 }
2835 }
2836}
2837
2838impl<T, S: StorageMut<Elem = T>, L: Layout, I: AsIndex<L>> IndexMut<I> for WeaklyCheckedView<S, L> {
2839 fn index_mut(&mut self, index: I) -> &mut Self::Output {
2840 let offset = self.base.layout.offset_unchecked(index.as_index());
2841 unsafe {
2842 self.base.data.get_mut(offset).expect("invalid offset")
2844 }
2845 }
2846}
2847
2848#[cfg(test)]
2849mod tests;