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