1use core::{ffi::c_void, mem::ManuallyDrop};
2
3#[cfg(feature = "cpu")]
4use crate::cpu::{CPUPtr, CPU};
5
6#[cfg(not(feature = "cpu"))]
7use crate::CPU;
8
9use crate::{
10 flag::AllocFlag, shape::Shape, Alloc, ClearBuf, CloneBuf, CommonPtrs, Device, DevicelessAble,
11 Ident, IsShapeIndep, MainMemory, PtrType, Read, ShallowCopy, WriteBuf,
12};
13
14pub use self::num::Num;
15pub use impl_from_const::*;
16
17mod impl_from;
18mod impl_from_const;
19mod num;
20
21#[cfg_attr(feature = "cpu", doc = "```")]
25#[cfg_attr(not(feature = "cpu"), doc = "```ignore")]
26pub struct Buffer<'a, T = f32, D: Device = CPU, S: Shape = ()> {
38 pub ptr: D::Ptr<T, S>,
40 pub device: Option<&'a D>,
42 #[cfg(not(feature = "no-std"))]
44 pub ident: Option<Ident>,
45}
46
47unsafe impl<'a, T, D: Device, S: Shape> Send for Buffer<'a, T, D, S> {}
48
49unsafe impl<'a, T, D: Device, S: Shape> Sync for Buffer<'a, T, D, S> {}
50
51impl<'a, T, D: Device, S: Shape> Buffer<'a, T, D, S> {
52 #[cfg_attr(feature = "cpu", doc = "```")]
55 #[cfg_attr(not(feature = "cpu"), doc = "```ignore")]
56 #[inline]
70 pub fn new(device: &'a D, len: usize) -> Buffer<'a, T, D, S>
71 where
72 D: Alloc<'a, T, S>, {
74 let ptr = device.alloc(len, AllocFlag::None);
75
76 #[cfg(not(feature = "no-std"))]
77 let ident = device.add_to_cache(&ptr);
78
79 Buffer {
80 ptr,
81 device: Some(device),
82 #[cfg(not(feature = "no-std"))]
85 ident,
86 }
87 }
88
89 #[cfg_attr(feature = "cpu", doc = "```")]
93 #[cfg_attr(not(feature = "cpu"), doc = "```ignore")]
94 #[inline]
107 pub fn deviceless<'b>(device: &'b D, len: usize) -> Buffer<'a, T, D, S>
108 where
109 D: DevicelessAble<'b, T, S>,
110 {
111 Buffer {
112 ptr: device.alloc(len, AllocFlag::None),
113 #[cfg(not(feature = "no-std"))]
114 ident: None,
115 device: None,
116 }
117 }
118
119 pub fn device(&self) -> &'a D {
122 self.device
123 .expect("Called device() on a deviceless buffer.")
124 }
125
126 #[inline]
128 pub fn read(&'a self) -> D::Read<'a>
129 where
130 T: Clone + Default,
131 D: Read<T, S>,
132 {
133 self.device().read(self)
134 }
135
136 #[cfg_attr(feature = "cpu", doc = "```")]
140 #[cfg_attr(not(feature = "cpu"), doc = "```ignore")]
141 #[inline]
149 #[cfg(not(feature = "no-std"))]
150 pub fn read_to_vec(&self) -> Vec<T>
151 where
152 D: Read<T, S>,
153 T: Default + Clone,
154 {
155 self.device().read_to_vec(self)
156 }
157
158 #[cfg_attr(feature = "cpu", doc = "```")]
163 #[cfg_attr(not(feature = "cpu"), doc = "```ignore")]
164 #[inline]
173 pub fn write(&mut self, data: &[T])
174 where
175 D: WriteBuf<T, S, D>,
176 {
177 self.device().write(self, data)
178 }
179
180 #[inline]
182 pub fn write_buf(&mut self, src: &Buffer<T, D, S>)
183 where
184 T: Clone,
185 D: WriteBuf<T, S, D>,
186 {
187 self.device().write_buf(self, src)
188 }
189
190 #[cfg_attr(feature = "cpu", doc = "```")]
193 #[cfg_attr(not(feature = "cpu"), doc = "```ignore")]
194 #[inline]
201 pub fn len(&self) -> usize {
202 self.ptr.size()
203 }
204
205 #[inline]
212 pub unsafe fn shallow(&self) -> Buffer<'a, T, D, S>
213 where
214 <D as Device>::Ptr<T, S>: ShallowCopy,
215 {
216 Buffer {
217 ptr: self.ptr.shallow(),
218 device: self.device,
219 #[cfg(not(feature = "no-std"))]
220 ident: self.ident,
221 }
222 }
223
224 pub unsafe fn shallow_or_clone(&self) -> Buffer<'a, T, D, S>
232 where
233 <D as Device>::Ptr<T, S>: ShallowCopy,
234 T: Clone,
235 D: CloneBuf<'a, T, S>,
236 {
237 {
238 #[cfg(not(feature = "realloc"))]
239 self.shallow()
240 }
241
242 #[cfg(feature = "realloc")]
243 self.clone()
244 }
245
246 #[inline]
250 pub fn id(&self) -> Ident {
251 #[cfg(feature = "no-std")]
252 {
253 unimplemented!("This buffer has no trackable id. Who?: e.g. 'Stack' Buffer, Buffers created via Buffer::from_raw_host..(..), `Num` (scalar) Buffer")
254 }
255
256 #[cfg(not(feature = "no-std"))]
257 self.ident.expect("This buffer has no trackable id. Who?: e.g. 'Stack' Buffer, Buffers created via Buffer::from_raw_host..(..), `Num` (scalar) Buffer")
258 }
259
260 pub fn clear(&mut self)
262 where
263 D: ClearBuf<T, S, D>,
264 {
265 self.device().clear(self)
266 }
267}
268
269impl<'a, T, D: Device, S: Shape> Drop for Buffer<'a, T, D, S> {
270 #[inline]
271 fn drop(&mut self) {
272 if self.ptr.flag() != AllocFlag::None {
273 return;
274 }
275
276 #[cfg(not(feature = "no-std"))]
277 if let Some(device) = self.device {
278 if let Some(ident) = self.ident {
279 device.remove(ident)
280 }
281 }
282 }
283}
284
285impl<'a, T, D: Device, S: Shape> Buffer<'a, T, D, S> {
287 #[cfg_attr(feature = "cpu", doc = "```")]
290 #[cfg_attr(not(feature = "cpu"), doc = "```ignore")]
291 #[inline]
299 pub fn to_dims<O: Shape>(self) -> Buffer<'a, T, D, O>
300 where
301 D: crate::ToDim<T, S, O>,
302 D::Ptr<T, S>: ShallowCopy,
303 {
304 let buf = ManuallyDrop::new(self);
305
306 let ptr = buf.device().to_dim(unsafe { buf.ptr.shallow() });
307
308 Buffer {
309 ptr,
310 device: buf.device,
311 #[cfg(not(feature = "no-std"))]
312 ident: buf.ident,
313 }
314 }
315}
316
317impl<'a, T, D: IsShapeIndep, S: Shape> Buffer<'a, T, D, S> {
318 #[inline]
321 pub fn as_dims<'b, O: Shape>(&self) -> &Buffer<'b, T, D, O> {
322 unsafe { &*(self as *const Self).cast() }
326 }
327
328 #[inline]
331 pub fn as_dims_mut<'b, O: Shape>(&mut self) -> &mut Buffer<'b, T, D, O> {
332 unsafe { &mut *(self as *mut Self).cast() }
333 }
334}
335
336impl<'a, T, D: Device, S: Shape> Buffer<'a, T, D, S>
337where
338 D::Ptr<T, S>: CommonPtrs<T>,
339{
340 #[inline]
341 pub fn ptrs(&self) -> (*const T, *mut c_void, u64) {
343 self.ptr.ptrs()
344 }
345
346 #[inline]
347 pub fn ptrs_mut(&mut self) -> (*mut T, *mut c_void, u64) {
349 self.ptr.ptrs_mut()
350 }
351}
352
353impl<'a, T, D: Device> Buffer<'a, T, D> {
354 #[inline]
363 pub fn is_empty(&self) -> bool {
364 self.len() == 0
365 }
366}
367
368impl<'a, T, D: Device, S: Shape> Buffer<'a, T, D, S> {
369 #[inline]
373 pub fn from_slice(device: &'a D, slice: &[T]) -> Self
374 where
375 T: Clone,
376 D: Alloc<'a, T, S>,
377 {
378 let ptr = device.with_slice(slice);
379
380 #[cfg(not(feature = "no-std"))]
381 let ident = device.add_to_cache(&ptr);
382
383 Buffer {
384 ptr,
385 #[cfg(not(feature = "no-std"))]
386 ident,
387 device: Some(device),
388 }
389 }
390
391 #[cfg(not(feature = "no-std"))]
395 #[inline]
396 pub fn from_vec(device: &'a D, data: Vec<T>) -> Self
397 where
398 T: Clone,
399 D: Alloc<'a, T, S>,
400 {
401 let ptr = device.alloc_with_vec(data);
402 let ident = device.add_to_cache(&ptr);
403
404 Buffer {
405 ptr,
406 ident,
407 device: Some(device),
408 }
409 }
410
411 #[inline]
416 pub fn from_array(device: &'a D, array: S::ARR<T>) -> Buffer<T, D, S>
417 where
418 T: Clone,
419 D: Alloc<'a, T, S>,
420 {
421 let ptr = device.with_array(array);
422
423 #[cfg(not(feature = "no-std"))]
424 let ident = device.add_to_cache(&ptr);
425
426 Buffer {
427 ptr,
428 #[cfg(not(feature = "no-std"))]
429 ident,
430 device: Some(device),
431 }
432 }
433}
434
435#[cfg(feature = "cpu")]
436impl<'a, T, S: Shape> Buffer<'a, T, CPU, S> {
437 #[inline]
459 pub unsafe fn from_raw_host(ptr: *mut T, len: usize) -> Buffer<'a, T, CPU, S> {
460 Buffer {
461 ptr: CPUPtr::from_ptr(ptr, len, AllocFlag::Wrapper),
462 device: None,
463 ident: None,
464 }
465 }
466
467 #[inline]
474 pub unsafe fn from_raw_host_device(
475 device: &'a CPU,
476 ptr: *mut T,
477 len: usize,
478 ) -> Buffer<'a, T, CPU, S> {
479 Buffer {
480 ptr: CPUPtr::from_ptr(ptr, len, AllocFlag::Wrapper),
481 device: Some(device),
482 ident: None,
483 }
484 }
485}
486
487#[cfg(feature = "opencl")]
488impl<'a, T, S: Shape> Buffer<'a, T, crate::OpenCL, S> {
489 #[inline]
491 pub fn cl_ptr(&self) -> *mut c_void {
492 assert!(
493 !self.ptr.ptr.is_null(),
494 "called cl_ptr() on an invalid OpenCL buffer"
495 );
496 self.ptrs().1
497 }
498}
499
500#[cfg(feature = "cuda")]
501impl<'a, T> Buffer<'a, T, crate::CUDA> {
502 #[inline]
505 pub fn cu_ptr(&self) -> u64 {
506 assert!(
507 self.ptrs().2 != 0,
508 "called cu_ptr() on an invalid CUDA buffer"
509 );
510 self.ptr.ptr
511 }
512}
513
514impl<'a, T, D: MainMemory, S: Shape> Buffer<'a, T, D, S> {
515 #[inline(always)]
517 pub fn as_slice(&self) -> &[T] {
518 self
519 }
520
521 #[inline(always)]
523 pub fn as_mut_slice(&mut self) -> &mut [T] {
524 self
525 }
526}
527
528impl<'a, T, D: MainMemory, S: Shape> Buffer<'a, T, D, S>
529where
530 D::Ptr<T, S>: CommonPtrs<T>,
531{
532 #[inline]
534 pub fn host_ptr(&self) -> *const T {
535 assert!(
536 !self.ptrs().0.is_null(),
537 "called host_ptr() on an invalid CPU buffer (this would dereference a null pointer)"
538 );
539 self.ptrs().0
540 }
541
542 #[inline]
544 pub fn host_ptr_mut(&mut self) -> *mut T {
545 assert!(
546 !self.ptrs().0.is_null(),
547 "called host_ptr_mut() on an invalid CPU buffer (this would dereference a null pointer)"
548 );
549 self.ptrs_mut().0
550 }
551}
552
553impl<'a, T, D, S> Clone for Buffer<'a, T, D, S>
554where
555 T: Clone,
556 D: CloneBuf<'a, T, S> + Device,
557 S: Shape,
558{
559 fn clone(&self) -> Self {
560 self.device().clone_buf(self)
561 }
562}
563
564impl<'a, T, D: Device, S: Shape> Default for Buffer<'a, T, D, S>
570where
571 D::Ptr<T, S>: Default,
572{
573 fn default() -> Self {
574 Self {
575 ptr: D::Ptr::<T, S>::default(),
576 device: None,
577 #[cfg(not(feature = "no-std"))]
578 ident: None,
579 }
580 }
581}
582
583impl<T, D: MainMemory> AsRef<[T]> for Buffer<'_, T, D> {
584 #[inline]
585 fn as_ref(&self) -> &[T] {
586 self
587 }
588}
589
590impl<T, D: MainMemory> AsMut<[T]> for Buffer<'_, T, D> {
591 #[inline]
592 fn as_mut(&mut self) -> &mut [T] {
593 self
594 }
595}
596
597#[cfg_attr(feature = "cpu", doc = "```")]
602#[cfg_attr(not(feature = "cpu"), doc = "```ignore")]
603impl<T, D: MainMemory, S: Shape> core::ops::Deref for Buffer<'_, T, D, S> {
622 type Target = [T];
623
624 #[inline]
625 fn deref(&self) -> &Self::Target {
626 unsafe { core::slice::from_raw_parts(D::as_ptr(&self.ptr), self.len()) }
627 }
628}
629
630#[cfg_attr(feature = "cpu", doc = "```")]
635#[cfg_attr(not(feature = "cpu"), doc = "```ignore")]
636impl<T, D: MainMemory, S: Shape> core::ops::DerefMut for Buffer<'_, T, D, S> {
653 #[inline]
654 fn deref_mut(&mut self) -> &mut Self::Target {
655 unsafe { core::slice::from_raw_parts_mut(D::as_ptr_mut(&mut self.ptr), self.len()) }
656 }
657}
658
659#[cfg(not(feature = "no-std"))]
660use core::fmt::Debug;
661
662#[cfg(not(feature = "no-std"))]
663impl<'a, T, D> Debug for Buffer<'a, T, D>
664where
665 T: Debug + Default + Clone + 'a,
666 D: Read<T> + Device + 'a,
667 for<'b> <D as Read<T>>::Read<'b>: Debug,
668 D::Ptr<T, ()>: CommonPtrs<T>,
669{
670 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
671 f.debug_struct("Buffer")
672 .field("ptr (CPU, CL, CU)", &self.ptrs())
673 .field("len", &self.len());
674 writeln!(f, ",")?;
675
676 if !self.ptrs().0.is_null() {
677 let slice = unsafe { std::slice::from_raw_parts(self.ptrs().0, self.len()) };
678 writeln!(f, "CPU: {slice:?}")?;
679 }
680
681 #[cfg(feature = "opencl")]
682 if !self.ptrs().1.is_null() {
683 write!(f, "OpenCL: {:?}, ", self.read())?;
684 }
685
686 #[cfg(feature = "cuda")]
687 if self.ptrs().2 != 0 {
688 write!(f, "CUDA: {:?}, ", self.read())?;
689 }
690
691 write!(
692 f,
693 "datatype={}, device={device} }}",
694 core::any::type_name::<T>(),
695 device = core::any::type_name::<D>()
696 )
697 }
698}
699
700impl<'a, T, D: MainMemory, S: Shape> core::iter::IntoIterator for &'a Buffer<'_, T, D, S> {
701 type Item = &'a T;
702
703 type IntoIter = core::slice::Iter<'a, T>;
704
705 #[inline]
706 fn into_iter(self) -> Self::IntoIter {
707 self.iter()
708 }
709}
710
711impl<'a, T, D: MainMemory, S: Shape> core::iter::IntoIterator for &'a mut Buffer<'_, T, D, S> {
712 type Item = &'a mut T;
713
714 type IntoIter = core::slice::IterMut<'a, T>;
715
716 #[inline]
717 fn into_iter(self) -> Self::IntoIter {
718 self.iter_mut()
719 }
720}
721
722#[cfg(test)]
723mod tests {
724 use crate::Buffer;
725
726 #[cfg(feature = "cpu")]
727 #[test]
728 fn test_deref() {
729 let device = crate::CPU::new();
730 let buf: Buffer<i32> = Buffer::from((&device, [1, 2, 3, 4]));
731 let slice = &*buf;
732 assert_eq!(slice, &[1, 2, 3, 4]);
733 }
734
735 #[cfg(feature = "opencl")]
736 #[cfg(unified_cl)]
737 #[test]
738 fn test_deref_cl() -> crate::Result<()> {
739 use crate::OpenCL;
740
741 let device = OpenCL::new(0)?;
742 let buf = Buffer::from((&device, [1, 2, 3, 4]));
743 let slice = &*buf;
744 assert_eq!(slice, &[1, 2, 3, 4]);
745
746 Ok(())
747 }
748
749 #[cfg(feature = "stack")]
750 #[test]
751 fn test_deref_stack() -> crate::Result<()> {
752 use crate::{shape::Dim1, stack::Stack};
753
754 let buf = Buffer::<i32, _, Dim1<4>>::from((Stack, [1i32, 2, 3, 4]));
756 let slice = &*buf;
757 assert_eq!(slice, &[1, 2, 3, 4]);
758
759 Ok(())
760 }
761
762 #[cfg(feature = "cpu")]
763 #[test]
764 fn test_debug_print() {
765 let device = crate::CPU::new();
766 let buf = Buffer::from((&device, [1, 2, 3, 4, 5, 6]));
767
768 println!("{buf:?}",);
769 }
770
771 #[cfg(feature = "cpu")]
772 #[test]
773 fn test_to_dims() {
774 use crate::Dim2;
775
776 let device = crate::CPU::new();
777 let buf = Buffer::from((&device, [1, 2, 3, 4, 5, 6]));
778 let buf_dim2 = buf.to_dims::<Dim2<3, 2>>();
779
780 buf_dim2.to_dims::<()>();
781 }
782
783 #[cfg(feature = "cpu")]
784 #[test]
785 fn test_id_cpu() {
786 use crate::{Ident, CPU};
787
788 let device = CPU::new();
789
790 let buf = Buffer::from((&device, [1, 2, 3, 4]));
791 assert_eq!(buf.id(), Ident { idx: 0, len: 4 })
792 }
793
794 #[cfg(feature = "stack")]
795 #[cfg(not(feature = "no-std"))]
796 #[should_panic]
797 #[test]
798 fn test_id_stack() {
799 use crate::{Stack, WithShape};
800
801 let device = Stack;
802
803 let buf = Buffer::with(&device, [1, 2, 3, 4]);
804 buf.id();
805 }
806}