use core::alloc::Layout;
use core::mem::{align_of, size_of};
use core::ptr::NonNull;
#[cfg(not(feature = "std"))]
use alloc::alloc::handle_alloc_error;
#[cfg(feature = "std")]
use std::alloc::handle_alloc_error;
use super::alloc::*;
pub struct AlignedVec<T, const ALIGN: usize = DEFAULT_ALIGN, A: Alloc = Global> {
ptr: NonNull<T>,
len: usize,
cap: usize,
alloc: A,
}
impl<T, const ALIGN: usize> AlignedVec<T, ALIGN, Global> {
#[inline]
pub const fn new() -> Self {
AlignedVec {
ptr: NonNull::dangling(),
len: 0,
cap: 0,
alloc: Global,
}
}
pub fn with_capacity(capacity: usize) -> Self {
Self::with_capacity_in(capacity, Global)
}
pub fn zeros(len: usize) -> Self
where
T: bytemuck::Zeroable,
{
Self::zeros_in(len, Global)
}
pub fn filled(len: usize, value: T) -> Self
where
T: Clone,
{
Self::filled_in(len, value, Global)
}
pub fn from_slice(slice: &[T]) -> Self
where
T: Clone,
{
Self::from_slice_in(slice, Global)
}
}
impl<T, const ALIGN: usize, A: Alloc> AlignedVec<T, ALIGN, A> {
#[inline]
pub fn new_in(alloc: A) -> Self {
AlignedVec {
ptr: NonNull::dangling(),
len: 0,
cap: 0,
alloc,
}
}
pub fn with_capacity_in(capacity: usize, alloc: A) -> Self {
if capacity == 0 {
return Self::new_in(alloc);
}
let layout = Self::layout_for(capacity);
let ptr = alloc.allocate(layout) as *mut T;
if ptr.is_null() {
handle_alloc_error(layout);
}
AlignedVec {
ptr: unsafe { NonNull::new_unchecked(ptr) },
len: 0,
cap: capacity,
alloc,
}
}
pub fn zeros_in(len: usize, alloc: A) -> Self
where
T: bytemuck::Zeroable,
{
if len == 0 {
return Self::new_in(alloc);
}
let layout = Self::layout_for(len);
let ptr = alloc.allocate_zeroed(layout) as *mut T;
if ptr.is_null() {
handle_alloc_error(layout);
}
AlignedVec {
ptr: unsafe { NonNull::new_unchecked(ptr) },
len,
cap: len,
alloc,
}
}
pub fn filled_in(len: usize, value: T, alloc: A) -> Self
where
T: Clone,
{
let mut vec = Self::with_capacity_in(len, alloc);
for _ in 0..len {
vec.push(value.clone());
}
vec
}
pub fn from_slice_in(slice: &[T], alloc: A) -> Self
where
T: Clone,
{
let mut vec = Self::with_capacity_in(slice.len(), alloc);
for item in slice {
vec.push(item.clone());
}
vec
}
#[inline]
pub fn allocator(&self) -> &A {
&self.alloc
}
fn layout_for(capacity: usize) -> Layout {
let size = capacity * size_of::<T>();
let align = ALIGN.max(align_of::<T>());
Layout::from_size_align(size, align).expect("Invalid layout")
}
#[inline]
pub fn len(&self) -> usize {
self.len
}
#[inline]
pub fn is_empty(&self) -> bool {
self.len == 0
}
#[inline]
pub fn capacity(&self) -> usize {
self.cap
}
#[inline]
pub fn as_ptr(&self) -> *const T {
self.ptr.as_ptr()
}
#[inline]
pub fn as_mut_ptr(&mut self) -> *mut T {
self.ptr.as_ptr()
}
#[inline]
pub fn as_slice(&self) -> &[T] {
unsafe { core::slice::from_raw_parts(self.ptr.as_ptr(), self.len) }
}
#[inline]
pub fn as_mut_slice(&mut self) -> &mut [T] {
unsafe { core::slice::from_raw_parts_mut(self.ptr.as_ptr(), self.len) }
}
pub fn push(&mut self, value: T) {
if self.len >= self.cap {
self.grow();
}
unsafe {
self.ptr.as_ptr().add(self.len).write(value);
}
self.len += 1;
}
pub fn pop(&mut self) -> Option<T> {
if self.len == 0 {
return None;
}
self.len -= 1;
unsafe { Some(self.ptr.as_ptr().add(self.len).read()) }
}
pub fn clear(&mut self) {
while self.pop().is_some() {}
}
pub fn resize(&mut self, new_len: usize, value: T)
where
T: Clone,
{
if new_len > self.len {
self.reserve(new_len - self.len);
for _ in self.len..new_len {
self.push(value.clone());
}
} else {
while self.len > new_len {
self.pop();
}
}
}
pub fn reserve(&mut self, additional: usize) {
let required = self.len + additional;
if required > self.cap {
let new_cap = required.max(self.cap * 2).max(8);
self.realloc(new_cap);
}
}
fn grow(&mut self) {
let new_cap = if self.cap == 0 { 8 } else { self.cap * 2 };
self.realloc(new_cap);
}
fn realloc(&mut self, new_cap: usize) {
let new_layout = Self::layout_for(new_cap);
let new_ptr = self.alloc.allocate(new_layout) as *mut T;
if new_ptr.is_null() {
handle_alloc_error(new_layout);
}
if self.cap > 0 {
unsafe {
core::ptr::copy_nonoverlapping(self.ptr.as_ptr(), new_ptr, self.len);
let old_layout = Self::layout_for(self.cap);
self.alloc
.deallocate(self.ptr.as_ptr() as *mut u8, old_layout);
}
}
self.ptr = unsafe { NonNull::new_unchecked(new_ptr) };
self.cap = new_cap;
}
}
impl<T, const ALIGN: usize, A: Alloc> Drop for AlignedVec<T, ALIGN, A> {
fn drop(&mut self) {
for i in 0..self.len {
unsafe {
core::ptr::drop_in_place(self.ptr.as_ptr().add(i));
}
}
if self.cap > 0 {
let layout = Self::layout_for(self.cap);
unsafe {
self.alloc.deallocate(self.ptr.as_ptr() as *mut u8, layout);
}
}
}
}
impl<T, const ALIGN: usize> Default for AlignedVec<T, ALIGN, Global> {
fn default() -> Self {
Self::new()
}
}
impl<T: Clone, const ALIGN: usize, A: Alloc> Clone for AlignedVec<T, ALIGN, A> {
fn clone(&self) -> Self {
Self::from_slice_in(self.as_slice(), self.alloc.clone())
}
}
impl<T, const ALIGN: usize, A: Alloc> core::ops::Deref for AlignedVec<T, ALIGN, A> {
type Target = [T];
fn deref(&self) -> &Self::Target {
self.as_slice()
}
}
impl<T, const ALIGN: usize, A: Alloc> core::ops::DerefMut for AlignedVec<T, ALIGN, A> {
fn deref_mut(&mut self) -> &mut Self::Target {
self.as_mut_slice()
}
}
impl<T, const ALIGN: usize, A: Alloc> core::ops::Index<usize> for AlignedVec<T, ALIGN, A> {
type Output = T;
fn index(&self, index: usize) -> &Self::Output {
&self.as_slice()[index]
}
}
impl<T, const ALIGN: usize, A: Alloc> core::ops::IndexMut<usize> for AlignedVec<T, ALIGN, A> {
fn index_mut(&mut self, index: usize) -> &mut Self::Output {
&mut self.as_mut_slice()[index]
}
}
unsafe impl<T: Send, const ALIGN: usize, A: Alloc + Send> Send for AlignedVec<T, ALIGN, A> {}
unsafe impl<T: Sync, const ALIGN: usize, A: Alloc + Sync> Sync for AlignedVec<T, ALIGN, A> {}