use core::alloc::Layout;
use core::hash::Hash;
use core::marker::PhantomData;
use core::mem::{align_of, size_of, ManuallyDrop};
use core::ops::Range;
use core::ptr;
use core::slice;
use ::alloc::alloc;
use ::alloc::vec::Vec;
use crate::buf::Buf;
use crate::buf_mut::BufMut;
use crate::error::{Error, ErrorKind};
use crate::offset::DefaultTargetSize;
use crate::pair::Pair;
use crate::phf::MapRef;
use crate::r#ref::Ref;
use crate::r#unsized::Unsized;
use crate::slice::Slice;
use crate::store_struct::StoreStruct;
use crate::visit::Visit;
use crate::zero_copy::{UnsizedZeroCopy, ZeroCopy};
use crate::TargetSize;
pub const DEFAULT_ALIGNMENT: usize = align_of::<usize>();
pub struct AlignedBuf<O: TargetSize = DefaultTargetSize> {
data: ptr::NonNull<u8>,
len: usize,
capacity: usize,
requested: usize,
align: usize,
_marker: PhantomData<O>,
}
impl AlignedBuf {
pub const fn new() -> Self {
Self::with_alignment(DEFAULT_ALIGNMENT)
}
pub fn with_capacity(capacity: usize) -> Self {
Self::with_capacity_and_alignment(capacity, DEFAULT_ALIGNMENT)
}
pub const fn with_alignment(align: usize) -> Self {
assert!(align.is_power_of_two(), "Alignment has to be power of two");
Self {
data: ptr::NonNull::dangling(),
len: 0,
capacity: 0,
requested: align,
align,
_marker: PhantomData,
}
}
}
impl<O: TargetSize> AlignedBuf<O> {
pub fn with_capacity_and_alignment(capacity: usize, align: usize) -> Self {
if capacity == 0 {
assert!(align.is_power_of_two(), "Alignment has to be power of two");
return Self {
data: ptr::NonNull::dangling(),
len: 0,
capacity: 0,
requested: align,
align,
_marker: PhantomData,
};
}
let layout = Layout::from_size_align(capacity, align).expect("Illegal memory layout");
unsafe {
let data = alloc::alloc(layout);
if data.is_null() {
alloc::handle_alloc_error(layout);
}
Self {
data: ptr::NonNull::new_unchecked(data),
len: 0,
capacity,
requested: align,
align,
_marker: PhantomData,
}
}
}
pub fn len(&self) -> usize {
self.len
}
pub unsafe fn set_len(&mut self, len: usize) {
self.len = len;
}
pub fn clear(&mut self) {
self.len = 0;
}
pub fn is_empty(&self) -> bool {
self.len == 0
}
pub fn capacity(&self) -> usize {
self.capacity
}
pub fn requested(&self) -> usize {
self.requested
}
pub fn align(&self) -> usize {
self.align
}
pub fn as_ptr(&self) -> *const u8 {
self.data.as_ptr() as *const _
}
pub fn as_ptr_mut(&mut self) -> *mut u8 {
self.data.as_ptr()
}
pub fn as_slice(&self) -> &[u8] {
unsafe { slice::from_raw_parts(self.as_ptr(), self.len()) }
}
pub fn as_mut_slice(&mut self) -> &mut [u8] {
unsafe { slice::from_raw_parts_mut(self.as_ptr_mut(), self.len()) }
}
pub fn store<T>(&mut self, value: &T) -> Result<Ref<T, O>, Error>
where
T: ZeroCopy,
{
let ptr = self.next_offset::<T>();
value.store_to(self)?;
Ok(Ref::new(ptr))
}
pub fn store_struct<T>(&mut self, value: &T) -> AlignedBufStoreStruct<'_, T, O>
where
T: ZeroCopy,
{
self.ensure_capacity(self.len.wrapping_add(size_of::<T>()));
unsafe {
ptr::copy_nonoverlapping(value, self.as_ptr_mut().wrapping_add(self.len).cast(), 1);
}
let len = self.len;
AlignedBufStoreStruct::new(self, len)
}
fn store_inner<T>(&mut self, value: &T) -> Result<(), Error>
where
T: ZeroCopy,
{
self.request_align(align_of::<T>());
value.store_to(self)?;
Ok(())
}
pub fn store_unsized<T>(&mut self, value: &T) -> Result<Unsized<T, O>, Error>
where
T: ?Sized + UnsizedZeroCopy,
{
let ptr = self.next_offset_with(T::ALIGN);
value.store_to(self)?;
Ok(Unsized::new(ptr, value.size()))
}
pub fn store_slice<T>(&mut self, values: &[T]) -> Result<Slice<T, O>, Error>
where
T: ZeroCopy,
{
let ptr = self.next_offset::<T>();
for value in values {
value.store_to(self)?;
}
Ok(Slice::new(ptr, values.len()))
}
pub fn insert_map<K, V>(&mut self, entries: &mut [Pair<K, V>]) -> Result<MapRef<K, V, O>, Error>
where
K: Visit + ZeroCopy,
V: ZeroCopy,
K::Target: Hash,
{
let mut hash_state = {
let buf = self.as_aligned();
crate::phf::generator::generate_hash(buf, entries)?
};
for a in 0..hash_state.map.len() {
loop {
let b = hash_state.map[a];
if hash_state.map[a] != a {
entries.swap(a, b);
hash_state.map.swap(a, b);
continue;
}
break;
}
}
let entries = self.store_slice(entries)?;
let mut displacements = Vec::new();
for (a, b) in hash_state.displacements {
displacements.push(Pair { a, b });
}
let displacements = self.store_slice(&displacements)?;
Ok(MapRef::new(hash_state.key, entries, displacements))
}
#[inline]
pub fn extend_from_slice(&mut self, bytes: &[u8]) -> Result<(), Error> {
let Some(capacity) = self.capacity.checked_add(bytes.len()) else {
panic!("Capacity overflow");
};
self.ensure_capacity(capacity);
unsafe {
let dst = self.as_ptr_mut().wrapping_add(self.len);
ptr::copy_nonoverlapping(bytes.as_ptr(), dst, bytes.len());
self.len = self.len.wrapping_add(bytes.len());
}
Ok(())
}
pub fn as_aligned_owned_buf(&self) -> Self {
let mut new = Self::with_capacity_and_alignment(self.len, self.requested);
unsafe {
ptr::copy_nonoverlapping(self.as_ptr(), new.as_ptr_mut(), self.len);
new.set_len(self.len);
}
new
}
pub fn as_ref(&self) -> Result<&Buf, Error> {
if !self.is_aligned_to(self.requested) {
return Err(Error::new(ErrorKind::AlignmentMismatch {
range: self.range(),
align: self.requested,
}));
}
Ok(Buf::new(self.as_slice()))
}
pub fn as_mut(&mut self) -> Result<&mut Buf, Error> {
if !self.is_aligned_to(self.requested) {
return Err(Error::new(ErrorKind::AlignmentMismatch {
range: self.range(),
align: self.requested,
}));
}
Ok(Buf::new_mut(self.as_mut_slice()))
}
pub unsafe fn as_ref_unchecked(&self) -> &Buf {
Buf::new(self.as_slice())
}
pub unsafe fn as_mut_unchecked(&mut self) -> &mut Buf {
Buf::new_mut(self.as_mut_slice())
}
pub fn as_aligned(&mut self) -> &Buf {
unsafe {
if self.requested != self.align {
let (old_layout, new_layout) = self.layouts(self.capacity);
self.alloc_new(old_layout, new_layout);
}
self.as_ref_unchecked()
}
}
pub fn as_mut_aligned(&mut self) -> &mut Buf {
unsafe {
if self.requested != self.align {
let (old_layout, new_layout) = self.layouts(self.capacity);
self.alloc_new(old_layout, new_layout);
}
self.as_mut_unchecked()
}
}
#[inline]
pub fn is_aligned_to(&self, align: usize) -> bool {
crate::buf::is_aligned_to(self.as_ptr(), align)
}
pub fn request_align(&mut self, align: usize) {
assert!(
align.is_power_of_two(),
"Alignment has to be a power of two"
);
let len = self.len.next_multiple_of(align);
self.requested = self.requested.max(align);
if len > self.len {
self.ensure_capacity(len);
unsafe {
ptr::write_bytes(self.as_ptr_mut().wrapping_add(self.len), 0, len - self.len);
}
self.len = len;
}
}
pub fn next_offset_with(&mut self, align: usize) -> usize {
self.request_align(align);
self.len
}
pub fn next_offset<T>(&mut self) -> usize
where
T: ZeroCopy,
{
self.request_align(align_of::<T>());
self.len
}
fn ensure_capacity(&mut self, new_capacity: usize) {
if self.capacity >= new_capacity {
return;
}
let (old_layout, new_layout) = self.layouts(new_capacity.max(self.requested));
if old_layout.size() == 0 {
self.alloc_init(new_layout);
} else if new_layout.align() == old_layout.align() {
self.alloc_realloc(old_layout, new_layout);
} else {
self.alloc_new(old_layout, new_layout);
}
}
fn layouts(&self, new_capacity: usize) -> (Layout, Layout) {
let old_layout = unsafe { Layout::from_size_align_unchecked(self.capacity, self.align) };
let layout =
Layout::from_size_align(new_capacity, self.requested).expect("Proposed layout invalid");
(old_layout, layout)
}
fn alloc_init(&mut self, new_layout: Layout) {
unsafe {
let ptr = alloc::alloc(new_layout);
if ptr.is_null() {
alloc::handle_alloc_error(new_layout);
}
self.data = ptr::NonNull::new_unchecked(ptr);
self.capacity = new_layout.size();
self.align = self.requested;
}
}
fn alloc_realloc(&mut self, old_layout: Layout, new_layout: Layout) {
debug_assert_eq!(old_layout.align(), new_layout.align());
unsafe {
let ptr = alloc::realloc(self.as_ptr_mut(), old_layout, new_layout.size());
if ptr.is_null() {
alloc::handle_alloc_error(old_layout);
}
self.data = ptr::NonNull::new_unchecked(ptr);
self.capacity = new_layout.size();
}
}
fn alloc_new(&mut self, old_layout: Layout, new_layout: Layout) {
unsafe {
let ptr = alloc::alloc(new_layout);
if ptr.is_null() {
alloc::handle_alloc_error(new_layout);
}
ptr::copy_nonoverlapping(self.as_ptr(), ptr, self.len);
alloc::dealloc(self.as_ptr_mut(), old_layout);
self.data = ptr::NonNull::new_unchecked(ptr);
self.capacity = new_layout.size();
self.align = self.requested;
}
}
pub(crate) fn range(&self) -> Range<usize> {
let end = self.data.as_ptr().wrapping_add(self.len);
self.data.as_ptr() as usize..end as usize
}
}
impl<O: TargetSize> Clone for AlignedBuf<O> {
fn clone(&self) -> Self {
unsafe {
let mut new =
ManuallyDrop::new(Self::with_capacity_and_alignment(self.len, self.align));
ptr::copy_nonoverlapping(self.as_ptr(), new.as_ptr_mut(), self.len);
new.requested = self.requested;
new.set_len(self.len);
ManuallyDrop::into_inner(new)
}
}
}
impl<O: TargetSize> Drop for AlignedBuf<O> {
fn drop(&mut self) {
unsafe {
if self.capacity != 0 {
let layout = Layout::from_size_align_unchecked(self.capacity, self.align);
alloc::dealloc(self.as_ptr_mut(), layout);
}
}
}
}
impl<O: TargetSize> BufMut for AlignedBuf<O> {
type TargetSize = O;
type StoreStruct<'a, T> = AlignedBufStoreStruct<'a, T, O> where T: ZeroCopy;
#[inline]
fn extend_from_slice(&mut self, bytes: &[u8]) -> Result<(), Error> {
AlignedBuf::extend_from_slice(self, bytes)
}
#[inline]
fn store<T>(&mut self, value: &T) -> Result<(), Error>
where
T: ZeroCopy,
{
AlignedBuf::store_inner(self, value)
}
#[inline]
fn store_struct<T>(&mut self, value: &T) -> Self::StoreStruct<'_, T>
where
T: ZeroCopy,
{
AlignedBuf::store_struct::<T>(self, value)
}
}
#[must_use = "For the writer to have an effect on `AlignedBuf` you must call `StoreStruct::finish`"]
pub struct AlignedBufStoreStruct<'a, T, O: TargetSize> {
buf: &'a mut AlignedBuf<O>,
len: usize,
_marker: PhantomData<T>,
}
impl<'a, T, O: TargetSize> AlignedBufStoreStruct<'a, T, O>
where
T: ZeroCopy,
{
pub(crate) fn new(buf: &'a mut AlignedBuf<O>, len: usize) -> Self {
Self {
buf,
len,
_marker: PhantomData,
}
}
fn zero_pad_align<F>(&mut self)
where
F: ZeroCopy,
{
let o = self.len.next_multiple_of(align_of::<F>());
if o > self.len {
if o <= self.buf.capacity() {
let start = self.buf.as_ptr_mut().wrapping_add(self.len);
unsafe {
ptr::write_bytes(start, 0, o - self.len);
}
}
self.len = o;
}
}
}
impl<'a, T, O: TargetSize> StoreStruct<T, O> for AlignedBufStoreStruct<'a, T, O>
where
T: ZeroCopy,
{
fn pad<F>(&mut self)
where
F: ZeroCopy,
{
self.zero_pad_align::<F>();
self.len = self.len.wrapping_add(size_of::<F>());
}
unsafe fn finish(mut self) -> Result<Ref<T, O>, Error> {
self.zero_pad_align::<T>();
let offset = self.buf.len();
if self.len > self.buf.capacity() {
return Err(Error::new(ErrorKind::BufferOverflow {
offset: self.len,
capacity: self.buf.capacity(),
}));
}
self.buf.set_len(self.len);
Ok(Ref::new(offset))
}
}