1extern crate alloc;
4
5use crate::align::Alignment;
6use crate::numa::NumaAllocator;
7use crate::view::SimdView;
8use core::alloc::Layout;
9use core::marker::PhantomData;
10use core::ops::{Deref, DerefMut};
11
12#[cfg(not(feature = "mnemosyne-memory"))]
13use alloc::alloc::{alloc, dealloc};
14
15pub struct AlignedVec<T, Align: Alignment> {
20 ptr: *mut T,
21 len: usize,
22 cap: usize,
23 node: Option<u32>,
24 alloc_align: u32,
25 _marker: PhantomData<(T, Align)>,
26}
27
28unsafe impl<T: Send, Align: Alignment> Send for AlignedVec<T, Align> {}
29unsafe impl<T: Sync, Align: Alignment> Sync for AlignedVec<T, Align> {}
30
31impl<T, Align> AlignedVec<T, Align>
32where
33 Align: Alignment,
34{
35 #[inline(always)]
36 fn layout_for_capacity(capacity: usize, align: usize) -> Layout {
37 let size = capacity
38 .checked_mul(core::mem::size_of::<T>())
39 .expect("Capacity overflow");
40 Layout::from_size_align(size, align)
41 .expect("align is power-of-2, size validated by checked_mul")
42 }
43
44 #[inline]
46 pub fn new() -> Self {
47 Self {
48 ptr: core::ptr::NonNull::dangling().as_ptr(),
49 len: 0,
50 cap: 0,
51 node: None,
52 alloc_align: if Align::IS_ALIGNED {
53 Align::ALIGN_BYTES as u32
54 } else {
55 core::mem::align_of::<T>() as u32
56 },
57 _marker: PhantomData,
58 }
59 }
60
61 pub fn with_capacity(capacity: usize) -> Self {
64 let default_align = if Align::IS_ALIGNED {
65 Align::ALIGN_BYTES as u32
66 } else {
67 core::mem::align_of::<T>() as u32
68 };
69 if core::mem::size_of::<T>() == 0 {
70 return Self {
71 ptr: core::ptr::NonNull::dangling().as_ptr(),
72 len: 0,
73 cap: usize::MAX,
74 node: None,
75 alloc_align: default_align,
76 _marker: PhantomData,
77 };
78 }
79 if capacity == 0 {
80 return Self::new();
81 }
82
83 let align = if Align::IS_ALIGNED {
84 Align::ALIGN_BYTES
85 } else {
86 core::mem::align_of::<T>()
87 };
88 let layout = Self::layout_for_capacity(capacity, align);
89
90 #[cfg(feature = "mnemosyne-memory")]
91 let ptr =
92 unsafe { core::alloc::GlobalAlloc::alloc(&mnemosyne::Mnemosyne, layout) as *mut T };
93 #[cfg(not(feature = "mnemosyne-memory"))]
94 let ptr = unsafe { alloc(layout) as *mut T };
95
96 if ptr.is_null() {
97 alloc::alloc::handle_alloc_error(layout);
98 }
99
100 Self {
101 ptr,
102 len: 0,
103 cap: capacity,
104 node: None,
105 alloc_align: align as u32,
106 _marker: PhantomData,
107 }
108 }
109
110 pub fn with_capacity_numa(capacity: usize, node: u32) -> Self {
113 let default_align = if Align::IS_ALIGNED {
114 Align::ALIGN_BYTES as u32
115 } else {
116 core::mem::align_of::<T>() as u32
117 };
118 if core::mem::size_of::<T>() == 0 {
119 return Self {
120 ptr: core::ptr::NonNull::dangling().as_ptr(),
121 len: 0,
122 cap: usize::MAX,
123 node: Some(node),
124 alloc_align: default_align,
125 _marker: PhantomData,
126 };
127 }
128 if capacity == 0 {
129 return Self {
130 ptr: core::ptr::NonNull::dangling().as_ptr(),
131 len: 0,
132 cap: 0,
133 node: Some(node),
134 alloc_align: default_align,
135 _marker: PhantomData,
136 };
137 }
138
139 let align = if Align::IS_ALIGNED {
140 Align::ALIGN_BYTES
141 } else {
142 core::mem::align_of::<T>()
143 };
144 let layout = Self::layout_for_capacity(capacity, align);
145
146 let allocator = crate::numa::MnemosyneNumaAllocator;
147 let ptr = unsafe { allocator.alloc_on_node(layout, node) as *mut T };
148 if ptr.is_null() {
149 alloc::alloc::handle_alloc_error(layout);
150 }
151
152 Self {
153 ptr,
154 len: 0,
155 cap: capacity,
156 node: Some(node),
157 alloc_align: align as u32,
158 _marker: PhantomData,
159 }
160 }
161
162 pub fn push(&mut self, value: T) {
164 if core::mem::size_of::<T>() == 0 {
165 core::mem::forget(value);
168 self.len = self.len.checked_add(1).expect("Length overflow");
169 self.cap = usize::MAX;
170 return;
171 }
172 if self.len == self.cap {
173 self.grow();
174 }
175 unsafe {
176 core::ptr::write(self.ptr.add(self.len), value);
177 self.len += 1;
178 }
179 }
180
181 pub fn reserve(&mut self, additional: usize) {
192 if core::mem::size_of::<T>() == 0 {
193 self.cap = usize::MAX;
194 return;
195 }
196 let needed = self.len.checked_add(additional).expect("Capacity overflow");
197 if needed <= self.cap {
198 return;
199 }
200 let new_cap = needed.max(self.cap.saturating_mul(2)).max(4);
204 self.grow_to(new_cap);
205 }
206
207 pub fn extend_from_slice(&mut self, src: &[T])
214 where
215 T: Copy,
216 {
217 self.reserve(src.len());
218 if src.is_empty() {
219 return;
220 }
221 unsafe {
226 core::ptr::copy_nonoverlapping(src.as_ptr(), self.ptr.add(self.len), src.len());
227 self.len += src.len();
228 }
229 }
230
231 #[inline(always)]
233 pub fn len(&self) -> usize {
234 self.len
235 }
236
237 #[inline(always)]
239 pub fn is_empty(&self) -> bool {
240 self.len == 0
241 }
242
243 #[inline(always)]
245 pub fn capacity(&self) -> usize {
246 self.cap
247 }
248
249 #[inline(always)]
251 pub fn as_ptr(&self) -> *const T {
252 self.ptr
253 }
254
255 #[inline(always)]
257 pub fn as_mut_ptr(&mut self) -> *mut T {
258 self.ptr
259 }
260
261 #[inline(always)]
270 pub fn spare_capacity_mut(&mut self) -> &mut [core::mem::MaybeUninit<T>] {
271 unsafe {
277 core::slice::from_raw_parts_mut(
278 self.ptr.add(self.len) as *mut core::mem::MaybeUninit<T>,
279 self.cap - self.len,
280 )
281 }
282 }
283
284 #[inline(always)]
290 pub unsafe fn set_len(&mut self, new_len: usize) {
291 debug_assert!(new_len <= self.cap);
292 self.len = new_len;
293 }
294
295 #[inline(always)]
297 pub fn as_slice(&self) -> &[T] {
298 if self.len == 0 {
299 &[]
300 } else {
301 unsafe { core::slice::from_raw_parts(self.ptr, self.len) }
302 }
303 }
304
305 #[inline(always)]
307 pub fn as_mut_slice(&mut self) -> &mut [T] {
308 if self.len == 0 {
309 &mut []
310 } else {
311 unsafe { core::slice::from_raw_parts_mut(self.ptr, self.len) }
312 }
313 }
314
315 #[inline]
323 pub fn from_slice(src: &[T]) -> Self
324 where
325 T: Copy,
326 {
327 let n = src.len();
328 if n == 0 {
329 return Self::new();
330 }
331 if core::mem::size_of::<T>() == 0 {
332 let mut v = Self::new();
333 v.len = n;
334 v.cap = usize::MAX;
335 return v;
336 }
337 let mut v = Self::with_capacity(n);
338 unsafe {
339 core::ptr::copy_nonoverlapping(src.as_ptr(), v.ptr, n);
340 v.len = n;
341 }
342 v
343 }
344
345 #[inline]
352 pub fn from_slice_clone(src: &[T]) -> Self
353 where
354 T: Clone,
355 {
356 let n = src.len();
357 if n == 0 {
358 return Self::new();
359 }
360 if core::mem::size_of::<T>() == 0 {
361 let mut v = Self::new();
362 v.len = n;
363 v.cap = usize::MAX;
364 return v;
365 }
366 let mut v = Self::with_capacity(n);
367 for i in 0..n {
368 unsafe {
369 core::ptr::write(v.ptr.add(i), src[i].clone());
370 v.len = i + 1;
371 }
372 }
373 v
374 }
375
376 #[inline(always)]
378 pub fn view<'a, Arch>(
379 &'a self,
380 ) -> SimdView<'a, T, Arch, Align, crate::execution::Unmasked, &'a [T]>
381 where
382 Arch: crate::arch::SimdArch,
383 {
384 SimdView::new(self.as_slice())
385 .expect("AlignedVec guarantees aligned buffer of sufficient length")
386 }
387
388 #[inline(always)]
390 pub fn view_mut<'a, Arch>(
391 &'a mut self,
392 ) -> SimdView<'a, T, Arch, Align, crate::execution::Unmasked, &'a mut [T]>
393 where
394 Arch: crate::arch::SimdArch,
395 {
396 SimdView::new_mut(self.as_mut_slice())
397 .expect("AlignedVec guarantees aligned buffer of sufficient length")
398 }
399
400 #[inline(always)]
408 pub unsafe fn into_alignment_unchecked<NewAlign: Alignment>(self) -> AlignedVec<T, NewAlign> {
409 let md = core::mem::ManuallyDrop::new(self);
410 AlignedVec {
411 ptr: md.ptr,
412 len: md.len,
413 cap: md.cap,
414 node: md.node,
415 alloc_align: md.alloc_align,
416 _marker: PhantomData,
417 }
418 }
419
420 #[inline(always)]
422 pub fn into_unaligned(self) -> AlignedVec<T, crate::align::Unaligned> {
423 unsafe { self.into_alignment_unchecked() }
424 }
425
426 #[inline]
429 pub fn try_into_alignment<NewAlign: Alignment>(self) -> Option<AlignedVec<T, NewAlign>> {
430 if NewAlign::IS_ALIGNED {
431 let addr = self.as_ptr() as usize;
432 if addr % NewAlign::ALIGN_BYTES == 0 {
433 unsafe { Some(self.into_alignment_unchecked()) }
434 } else {
435 None
436 }
437 } else {
438 unsafe { Some(self.into_alignment_unchecked()) }
439 }
440 }
441
442 fn layout_for(&self, capacity: usize) -> Layout {
443 Self::layout_for_capacity(capacity, self.alloc_align as usize)
444 }
445
446 fn grow(&mut self) {
447 if core::mem::size_of::<T>() == 0 {
448 self.cap = usize::MAX;
449 return;
450 }
451
452 let new_cap = if self.cap == 0 {
453 4
454 } else {
455 self.cap.checked_mul(2).expect("Capacity overflow")
456 };
457 self.grow_to(new_cap);
458 }
459
460 fn grow_to(&mut self, new_cap: usize) {
471 let new_layout = self.layout_for(new_cap);
472
473 let old_ptr = self.ptr;
474 let new_ptr = if self.cap == 0 {
475 if let Some(node) = self.node {
476 let allocator = crate::numa::MnemosyneNumaAllocator;
477 unsafe { allocator.alloc_on_node(new_layout, node) as *mut T }
478 } else {
479 #[cfg(feature = "mnemosyne-memory")]
480 unsafe {
481 core::alloc::GlobalAlloc::alloc(&mnemosyne::Mnemosyne, new_layout) as *mut T
482 }
483 #[cfg(not(feature = "mnemosyne-memory"))]
484 unsafe {
485 alloc(new_layout) as *mut T
486 }
487 }
488 } else {
489 let old_layout = self.layout_for(self.cap);
490 unsafe {
491 if let Some(node) = self.node {
492 let allocator = crate::numa::MnemosyneNumaAllocator;
493 allocator.realloc_on_node(self.ptr as *mut u8, old_layout, new_layout, node)
494 as *mut T
495 } else {
496 #[cfg(feature = "mnemosyne-memory")]
497 let ptr = core::alloc::GlobalAlloc::realloc(
498 &mnemosyne::Mnemosyne,
499 self.ptr as *mut u8,
500 old_layout,
501 new_layout.size(),
502 ) as *mut T;
503 #[cfg(not(feature = "mnemosyne-memory"))]
504 let ptr =
505 alloc::alloc::realloc(self.ptr as *mut u8, old_layout, new_layout.size())
506 as *mut T;
507 ptr
508 }
509 }
510 };
511
512 if new_ptr.is_null() {
513 alloc::alloc::handle_alloc_error(new_layout);
514 }
515
516 if self.node.is_none() && self.cap > 0 && new_ptr != old_ptr {
517 crate::numa::locality::bump_alloc_generation();
518 }
519
520 self.ptr = new_ptr;
521 self.cap = new_cap;
522 }
523}
524
525impl<T, Align: Alignment> Deref for AlignedVec<T, Align> {
526 type Target = [T];
527
528 #[inline(always)]
529 fn deref(&self) -> &Self::Target {
530 self.as_slice()
531 }
532}
533
534impl<T, Align: Alignment> DerefMut for AlignedVec<T, Align> {
535 #[inline(always)]
536 fn deref_mut(&mut self) -> &mut Self::Target {
537 self.as_mut_slice()
538 }
539}
540
541struct DeallocGuard<T, Align: Alignment> {
542 ptr: *mut T,
543 cap: usize,
544 node: Option<u32>,
545 alloc_align: u32,
546 _marker: PhantomData<(T, Align)>,
547}
548
549impl<T, Align: Alignment> Drop for DeallocGuard<T, Align> {
550 fn drop(&mut self) {
551 if !self.ptr.is_null() && self.cap > 0 {
552 crate::numa::locality::bump_alloc_generation();
553 unsafe {
554 let layout = AlignedVec::<T, Align>::layout_for_capacity(
555 self.cap,
556 self.alloc_align as usize,
557 );
558 if let Some(node) = self.node {
559 let allocator = crate::numa::MnemosyneNumaAllocator;
560 allocator.dealloc_on_node(self.ptr as *mut u8, layout, node);
561 } else {
562 #[cfg(feature = "mnemosyne-memory")]
563 core::alloc::GlobalAlloc::dealloc(
564 &mnemosyne::Mnemosyne,
565 self.ptr as *mut u8,
566 layout,
567 );
568 #[cfg(not(feature = "mnemosyne-memory"))]
569 dealloc(self.ptr as *mut u8, layout);
570 }
571 }
572 }
573 }
574}
575
576impl<T, Align: Alignment> Drop for AlignedVec<T, Align> {
577 fn drop(&mut self) {
578 if core::mem::size_of::<T>() == 0 {
579 if self.len > 0 {
580 unsafe {
581 core::ptr::drop_in_place(core::ptr::slice_from_raw_parts_mut(
582 self.ptr, self.len,
583 ));
584 }
585 }
586 return;
587 }
588 if !self.ptr.is_null() && self.cap > 0 {
589 let ptr = self.ptr;
590 let cap = self.cap;
591 let len = self.len;
592 let alloc_align = self.alloc_align;
593
594 self.ptr = core::ptr::null_mut();
595 self.cap = 0;
596 self.len = 0;
597
598 let _guard: DeallocGuard<T, Align> = DeallocGuard {
599 ptr,
600 cap,
601 node: self.node,
602 alloc_align,
603 _marker: PhantomData,
604 };
605 unsafe {
606 core::ptr::drop_in_place(core::ptr::slice_from_raw_parts_mut(ptr, len));
607 }
608 }
609 }
610}
611
612impl<T: Clone, Align: Alignment> Clone for AlignedVec<T, Align> {
613 fn clone(&self) -> Self {
614 if core::mem::size_of::<T>() == 0 {
615 let mut new_vec = Self {
616 ptr: core::ptr::NonNull::dangling().as_ptr(),
617 len: 0,
618 cap: usize::MAX,
619 node: self.node,
620 alloc_align: self.alloc_align,
621 _marker: PhantomData,
622 };
623 for val in self.as_slice() {
624 new_vec.push(val.clone());
625 }
626 return new_vec;
627 }
628 let mut new_vec = if let Some(node) = self.node {
629 Self::with_capacity_numa(self.len, node)
630 } else {
631 Self::with_capacity(self.len)
632 };
633 for i in 0..self.len {
634 unsafe {
635 let val = (*self.ptr.add(i)).clone();
636 core::ptr::write(new_vec.ptr.add(i), val);
637 new_vec.len = i + 1;
638 }
639 }
640 new_vec
641 }
642}
643
644impl<T, Align: Alignment> Default for AlignedVec<T, Align> {
645 #[inline]
646 fn default() -> Self {
647 Self::new()
648 }
649}
650
651impl<T: core::fmt::Debug, Align: Alignment> core::fmt::Debug for AlignedVec<T, Align> {
652 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
653 core::fmt::Debug::fmt(self.as_slice(), f)
654 }
655}
656
657impl<T: PartialEq, Align1: Alignment, Align2: Alignment> PartialEq<AlignedVec<T, Align2>>
658 for AlignedVec<T, Align1>
659{
660 #[inline]
661 fn eq(&self, other: &AlignedVec<T, Align2>) -> bool {
662 self.as_slice() == other.as_slice()
663 }
664}
665
666impl<T: Eq, Align: Alignment> Eq for AlignedVec<T, Align> {}
667
668impl<T: PartialEq, Align: Alignment> PartialEq<[T]> for AlignedVec<T, Align> {
669 #[inline]
670 fn eq(&self, other: &[T]) -> bool {
671 self.as_slice() == other
672 }
673}
674
675impl<T: PartialEq, Align: Alignment> PartialEq<AlignedVec<T, Align>> for [T] {
676 #[inline]
677 fn eq(&self, other: &AlignedVec<T, Align>) -> bool {
678 self == other.as_slice()
679 }
680}