#[cfg(not(feature = "rc"))]
use pi_buckets::Location;
use pi_buckets::{Buckets, BUCKETS};
use std::cell::UnsafeCell;
use std::mem::replace;
use std::ptr::NonNull;
use std::ops::Range;
use pi_vec_remain::VecRemain;
use pi_null::Null;
#[cfg(feature = "rc")]
pub type Blob = VecBlob;
#[cfg(not(feature = "rc"))]
pub type Blob = BucketsBlob;
unsafe impl Send for Blob {}
unsafe impl Sync for Blob {}
impl Blob {
pub fn memsize(&self) -> usize {
let val = self.capacity(0);
if val >= std::usize::MAX - 1 {
24
} else {
val + 24
}
}
}
pub struct BucketsBlob {
ptr: *mut u8,
capacity: usize,
buckets: *mut Buckets<u8>,
}
#[cfg(not(feature = "rc"))]
impl Default for BucketsBlob {
fn default() -> Self {
let buckets = Box::into_raw(Box::new(Buckets::default()));
let ptr = NonNull::<u8>::dangling().as_ptr();
Self {
ptr,
capacity: usize::null(),
buckets,
}
}
}
#[cfg(not(feature = "rc"))]
impl BucketsBlob {
#[inline(always)]
pub fn vec_capacity(&self) -> usize {
self.capacity
}
#[inline(always)]
pub fn capacity(&self, len: usize) -> usize {
if len > self.capacity {
Location::bucket_capacity(Location::bucket(len - self.capacity)) + self.capacity
} else {
self.capacity
}
}
#[inline(always)]
fn buckets(&self) -> &Buckets<u8> {
unsafe { &*self.buckets }
}
#[inline(always)]
pub unsafe fn set_vec_capacity(&mut self, capacity: usize) {
self.capacity = capacity;
}
#[inline]
pub fn get_multiple(&self, index: usize, multiple: usize) -> Option<&mut u8> {
if index < self.vec_capacity() {
return Some(unsafe { &mut *self.ptr.add(index * multiple) });
}
let mut loc = Location::of(index - self.capacity);
loc.entry *= multiple;
self.buckets().load(&loc)
}
#[inline]
pub fn get_multiple_unchecked(&self, index: usize, multiple: usize) -> &mut u8 {
if index < self.vec_capacity() {
return unsafe { &mut *self.ptr.add(index * multiple) };
}
let mut loc = Location::of(index - self.capacity);
loc.entry *= multiple;
unsafe { self.buckets().load_unchecked(&loc) }
}
#[inline]
pub fn load_alloc_multiple(&self, index: usize, multiple: usize) -> &mut u8 {
if index < self.vec_capacity() {
return unsafe { &mut *self.ptr.add(index * multiple) };
}
let mut loc = Location::of(index - self.capacity);
loc.entry *= multiple;
loc.len *= multiple;
self.buckets().load_alloc(&loc)
}
pub fn settle(&mut self, len: usize, additional: usize, multiple: usize) {
self.remain_settle(0..len, len, additional, multiple);
}
fn reset_vec(buckets: [Vec<u8>; BUCKETS], multiple: usize) -> [Vec<u8>; BUCKETS] {
buckets.map(|vec| {
let len = vec.len() * multiple;
let ptr = vec.into_raw_parts().0;
to_vec(ptr, len)
})
}
fn reserve(&mut self, mut vec: Vec<u8>, len: usize, mut additional: usize, multiple: usize) {
additional = (len + additional).saturating_sub(self.capacity);
if additional > 0 {
vec.reserve(additional * multiple);
vec.resize_with(vec.capacity(), || u8::default());
self.capacity = vec.capacity() / multiple;
}
self.ptr = vec.into_raw_parts().0;
}
fn take_buckets(&mut self, multiple: usize) -> [Vec<u8>; BUCKETS] {
let mut arr = self.buckets().take();
if multiple > 1 {
arr = Self::reset_vec(arr, multiple);
}
arr
}
pub fn remain_settle(
&mut self,
range: Range<usize>,
len: usize,
additional: usize,
multiple: usize
) {
debug_assert!(len >= range.end);
debug_assert!(range.end >= range.start);
let mut vec = to_vec(self.ptr, self.capacity * multiple);
if range.end <= self.capacity {
vec.remain(range.start * multiple..range.end * multiple);
if len > self.capacity {
self.take_buckets(multiple);
}
return self.reserve(vec, range.len(), additional, multiple);
}
let arr = self.take_buckets(multiple);
let cap = Location::bucket_capacity(Location::bucket(range.len() + additional)) * multiple;
let mut start = range.start * multiple;
let end = range.end * multiple;
let mut index = vec.capacity();
if vec.capacity() >= cap {
start += vec.remain(start..end);
} else if vec.capacity() > 0 {
let mut new = Vec::with_capacity(cap);
start += vec.remain_to(start..end, &mut new);
vec = new;
}
for (i, mut v) in arr.into_iter().enumerate() {
if start >= end {
break;
}
let mut vlen = v.len();
if vlen > 0 {
if start >= index + vlen {
index += vlen;
continue;
}
if vec.capacity() == 0 {
if v.capacity() >= cap {
_ = replace(&mut vec, v);
vec.remain(start - index..end - index);
} else {
vec.reserve(cap);
v.remain_to(start - index..end - index, &mut vec);
}
} else {
v.remain_to(start - index..end - index, &mut vec);
}
} else {
vlen = Location::bucket_len(i) * multiple;
if start >= index + vlen {
index += vlen;
continue;
}
if vec.capacity() == 0 {
vec.reserve(cap);
}
vec.resize_with(vec.len() + index + vlen - start, || u8::default());
}
index += vlen;
start = index;
}
vec.resize_with(vec.capacity(), || u8::default());
self.capacity = vec.capacity() / multiple;
self.ptr = vec.into_raw_parts().0;
}
}
#[cfg(not(feature = "rc"))]
impl Drop for BucketsBlob {
fn drop(&mut self) {
if self.vec_capacity().is_null() {
unsafe { self.set_vec_capacity(0) };
}
to_vec(self.ptr, self.capacity);
unsafe { drop(Box::from_raw(self.buckets)) };
}
}
pub struct VecBlob {
ptr: UnsafeCell<*mut u8>,
capacity: UnsafeCell<usize>,
}
impl Default for VecBlob {
fn default() -> Self {
Self {
ptr: NonNull::<u8>::dangling().as_ptr().into(),
capacity: usize::null().into(),
}
}
}
impl VecBlob {
#[inline(always)]
pub fn capacity(&self, _len: usize) -> usize {
*unsafe { self.capacity.as_ref_unchecked() }
}
#[inline(always)]
pub unsafe fn set_vec_capacity(&mut self, capacity: usize) {
self.capacity = capacity.into();
}
#[inline(always)]
pub fn vec_capacity(&self) -> usize {
if size_of::<u8>() == 0 {
usize::MAX
} else {
*unsafe { self.capacity.as_ref_unchecked() }
}
}
#[inline]
pub fn get_multiple(&self, index: usize, multiple: usize) -> Option<&mut u8> {
if index < self.vec_capacity() {
return Some(unsafe { &mut *(*self.ptr.get()).add(index * multiple) });
}
None
}
#[inline]
pub fn get_multiple_unchecked(&self, index: usize, multiple: usize) -> &mut u8 {
debug_assert!(index < self.vec_capacity());
unsafe { &mut *(*self.ptr.get()).add(index * multiple) }
}
#[inline]
pub fn load_alloc_multiple(&self, index: usize, multiple: usize) -> &mut u8 {
if index >= self.vec_capacity() {
let vec = to_vec(unsafe { *self.ptr.get() }, self.vec_capacity() * multiple);
self.reserve(
vec,
self.vec_capacity(),
index - self.vec_capacity() + 1,
multiple,
);
}
return unsafe { &mut *(*self.ptr.get()).add(index * multiple) };
}
pub fn settle(&mut self, _len: usize, _additional: usize, _multiple: usize) {}
fn reserve(&self, mut vec: Vec<u8>, len: usize, mut additional: usize, multiple: usize) {
additional = (len + additional).saturating_sub(self.vec_capacity());
if additional > 0 {
vec.reserve(additional * multiple);
vec.resize_with(vec.capacity(), || u8::default());
unsafe { self.capacity.replace(vec.capacity() / multiple) };
}
unsafe { self.ptr.replace(vec.into_raw_parts().0) };
}
}
impl Drop for VecBlob {
fn drop(&mut self) {
if self.vec_capacity().is_null() {
unsafe { self.set_vec_capacity(0) };
}
let len = unsafe {
*self.capacity.as_ref_unchecked()
};
if len == usize::MAX {
return;
}
to_vec(unsafe { *self.ptr.get() }, len);
}
}
pub fn to_vec<T>(ptr: *mut T, len: usize) -> Vec<T> {
unsafe { Vec::from_raw_parts(ptr, len, len) }
}