#![feature(unsafe_cell_access)]
#![feature(vec_into_raw_parts)]
#![feature(test)]
extern crate test;
use std::cell::UnsafeCell;
use std::mem::{replace, transmute};
use std::ptr::NonNull;
use pi_buckets::{Buckets, Location, BUCKETS};
use pi_vec_remain::VecRemain;
#[cfg(feature = "rc")]
pub type RawSlab = VecSlab;
#[cfg(not(feature = "rc"))]
pub type RawSlab = VBSlab;
pub struct VBSlab {
raw_size: usize, ptr: *mut u8,
capacity: usize, buckets: *mut Buckets<u8>,
}
unsafe impl Send for VBSlab {}
unsafe impl Sync for VBSlab {}
impl Default for VBSlab {
fn default() -> Self {
VBSlab::with_capacity(0, 0)
}
}
impl VBSlab {
pub fn with_capacity(raw_size: usize, capacity: usize) -> VBSlab {
if raw_size == 0 {
return VBSlab {
raw_size,
ptr: NonNull::<u8>::dangling().as_ptr(),
capacity: usize::MAX,
buckets: NonNull::<Buckets<u8>>::dangling().as_ptr(),
};
}
let ptr = if capacity == 0 {
NonNull::<u8>::dangling().as_ptr()
} else {
let vec = Vec::with_capacity(capacity * raw_size);
vec.into_raw_parts().0
};
let buckets = Box::into_raw(Box::new(Default::default()));
VBSlab {
raw_size,
ptr,
capacity,
buckets,
}
}
#[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)]
pub fn vec_capacity(&self) -> usize {
self.capacity
}
#[inline(always)]
fn buckets(&self) -> &Buckets<u8> {
unsafe { &*self.buckets }
}
#[inline]
pub fn get<T>(&self, index: usize) -> Option<&mut T> {
if index < self.vec_capacity() {
return Some(unsafe { transmute(&mut *self.ptr.add(index * self.raw_size)) });
}
let mut loc = Location::of(index - self.capacity);
loc.entry *= self.raw_size;
unsafe { transmute(self.buckets().load(&loc)) }
}
#[inline]
pub fn get_unchecked<T>(&self, index: usize) -> &mut T {
if index < self.vec_capacity() {
return unsafe { transmute(&mut *self.ptr.add(index * self.raw_size)) };
}
let mut loc = Location::of(index - self.capacity);
loc.entry *= self.raw_size;
unsafe { transmute(self.buckets().load_unchecked(&loc)) }
}
#[inline]
pub fn load_alloc<T>(&self, index: usize) -> &mut T {
if index < self.vec_capacity() {
return unsafe { transmute(&mut *self.ptr.add(index * self.raw_size)) };
}
let mut loc = Location::of(index - self.capacity);
loc.entry *= self.raw_size;
loc.len *= self.raw_size;
unsafe { transmute(self.buckets().load_alloc(&loc)) }
}
pub fn settle(&mut self, len: usize) {
if self.raw_size == 0 {
return;
}
if len <= self.capacity {
return;
}
let vec_len = self.capacity * self.raw_size;
let mut vec = unsafe { Vec::from_raw_parts(self.ptr, vec_len, vec_len) };
let mut arr = self.take_buckets();
let bucket_end = Location::bucket(len - self.capacity);
if vec.capacity() == 0 && bucket_end == 0 {
vec = replace(&mut arr[0], Vec::new());
self.capacity = vec.capacity() / self.raw_size;
self.ptr = vec.into_raw_parts().0;
return;
}
let mut start = vec.capacity();
let cap = (Location::bucket_capacity(bucket_end) + self.capacity) * self.raw_size;
if vec.capacity() < cap {
vec.reserve(cap - vec.capacity());
}
let end = len * self.raw_size;
for (i, v) in arr[0..bucket_end + 1].iter_mut().enumerate() {
let mut vlen = v.len();
if vlen > 0 {
v.remain_to(0..end - start, &mut vec);
} else {
vlen = Location::bucket_len(i) * self.raw_size;
}
start += vlen;
}
self.capacity = vec.capacity() / self.raw_size;
self.ptr = vec.into_raw_parts().0;
}
fn take_buckets(&mut self) -> [Vec<u8>; BUCKETS] {
let buckets = self.buckets().take();
buckets.map(|vec| {
let len = vec.len() * self.raw_size;
let ptr = vec.into_raw_parts().0;
unsafe { Vec::from_raw_parts(ptr, len, len) }
})
}
}
pub struct VecSlab {
raw_size: usize, ptr: UnsafeCell<*mut u8>,
capacity: UnsafeCell<usize>,
}
impl VecSlab {
pub fn with_capacity(raw_size: usize, capacity: usize) -> VecSlab {
if raw_size == 0 {
return Self {
raw_size,
ptr: NonNull::<u8>::dangling().as_ptr().into(),
capacity: usize::MAX.into(),
};
}
let ptr = if capacity == 0 {
NonNull::<u8>::dangling().as_ptr().into()
} else {
let vec: Vec<u8> = Vec::with_capacity(capacity * raw_size);
vec.into_raw_parts().0.into()
};
return VecSlab {
raw_size,
ptr,
capacity: capacity.into(),
};
}
#[inline(always)]
pub fn capacity(&self, _len: usize) -> usize {
self.vec_capacity()
}
#[inline(always)]
pub fn vec_capacity(&self) -> usize {
*unsafe { self.capacity.as_ref_unchecked() }
}
#[inline]
pub fn get<T>(&self, index: usize) -> Option<&mut T> {
if index < self.vec_capacity() {
return Some(unsafe { transmute(&mut *(*self.ptr.get()).add(index * self.raw_size)) });
}
None
}
#[inline]
pub fn get_unchecked<T>(&self, index: usize) -> &mut T {
debug_assert!(index < self.vec_capacity());
unsafe { transmute(&mut *(*self.ptr.get()).add(index * self.raw_size)) }
}
#[inline]
pub fn load_alloc<T>(&self, index: usize) -> &mut T {
let capacity = self.vec_capacity();
if index >= capacity {
let len = capacity * self.raw_size;
let vec = unsafe { Vec::from_raw_parts(*self.ptr.get(), len, len) };
self.reserve(vec, capacity, index - capacity + 1);
}
return unsafe { transmute(&mut *(*self.ptr.get()).add(index * self.raw_size)) };
}
pub fn settle(&mut self, _len: usize) {}
fn reserve(&self, mut vec: Vec<u8>, len: usize, mut additional: usize) {
additional = (len + additional).saturating_sub(self.vec_capacity());
if additional > 0 {
vec.reserve(additional * self.raw_size);
unsafe { self.capacity.replace(vec.capacity() / self.raw_size) };
}
unsafe { self.ptr.replace(vec.into_raw_parts().0) };
}
}
impl Default for VecSlab {
fn default() -> Self {
VecSlab::with_capacity(0, 0)
}
}
#[cfg(test)]
mod tests {
use pcg_rand::Pcg64;
use rand::{Rng, SeedableRng};
use crate::*;
#[test]
fn test3() {
let mut arr = RawSlab::with_capacity(size_of::<usize>(), 0);
let mut i = 0;
let mut rng = Pcg64::seed_from_u64(2);
for _ in 0..1000 {
let x = rng.gen_range(0..1000);
for _ in 0..x {
let r: &mut usize =
unsafe { transmute(arr.load_alloc::<usize>(i)) };
*r = i;
i += 1;
}
check3(&arr, i);
arr.settle(i);
check3(&arr, i);
if rng.gen_range(0..200) == 0 {
println!("reset ----------");
arr = RawSlab::with_capacity(size_of::<usize>(), 0);
i = 0;
}
}
}
fn check3(arr: &RawSlab, len: usize) {
for i in 0..len {
let r: &mut usize = unsafe { transmute(arr.get::<usize>(i)) };
assert_eq!(*r, i);
}
}
}