use crate::{Doubling, Growth, fragment::fragment_struct::Fragment};
use alloc::string::String;
use alloc::vec::Vec;
pub struct SplitVec<T, G = Doubling>
where
G: Growth,
{
pub(crate) len: usize,
pub(crate) fragments: Vec<Fragment<T>>,
pub(crate) growth: G,
}
impl<T, G> SplitVec<T, G>
where
G: Growth,
{
pub(crate) fn from_raw_parts(len: usize, fragments: Vec<Fragment<T>>, growth: G) -> Self {
debug_assert_eq!(len, fragments.iter().map(|x| x.len()).sum::<usize>());
Self {
len,
fragments,
growth,
}
}
pub fn growth(&self) -> &G {
&self.growth
}
pub unsafe fn fragments_mut(&mut self) -> &mut Vec<Fragment<T>> {
&mut self.fragments
}
pub fn fragments(&self) -> &[Fragment<T>] {
&self.fragments
}
pub fn maximum_concurrent_capacity(&self) -> usize {
self.growth()
.maximum_concurrent_capacity(&self.fragments, self.fragments.capacity())
}
pub fn concurrent_reserve(&mut self, maximum_capacity: usize) -> Result<usize, String> {
let required_num_fragments = self
.growth
.required_fragments_len(&self.fragments, maximum_capacity)?;
let additional_fragments = match required_num_fragments > self.fragments.capacity() {
true => required_num_fragments - self.fragments.capacity(),
false => 0,
};
if additional_fragments > 0 {
let prior_fragments_capacity = self.fragments.capacity();
let num_fragments = self.fragments.len();
unsafe { self.fragments.set_len(prior_fragments_capacity) };
self.fragments.reserve(additional_fragments);
#[allow(clippy::uninit_vec)]
unsafe {
self.fragments.set_len(num_fragments)
};
}
Ok(self.maximum_concurrent_capacity())
}
#[inline(always)]
pub fn get_fragment_and_inner_indices(&self, index: usize) -> Option<(usize, usize)> {
self.growth
.get_fragment_and_inner_indices(self.len, &self.fragments, index)
}
#[inline(always)]
pub(crate) fn has_capacity_for_one(&self) -> bool {
self.fragments
.last()
.map(|f| f.has_capacity_for_one())
.unwrap_or(false)
}
#[inline(always)]
pub(crate) fn add_fragment(&mut self) -> usize {
self.add_fragment_get_fragment_capacity(false)
}
fn add_fragment_get_fragment_capacity(&mut self, zeroed: bool) -> usize {
let new_fragment_capacity = self.growth.new_fragment_capacity(&self.fragments);
let mut new_fragment = Fragment::new(new_fragment_capacity);
if zeroed {
unsafe { new_fragment.zero() };
}
self.fragments.push(new_fragment);
new_fragment_capacity
}
pub(crate) fn add_fragment_with_first_value(&mut self, first_value: T) {
let capacity = self.growth.new_fragment_capacity(&self.fragments);
let new_fragment = Fragment::new_with_first_value(capacity, first_value);
self.fragments.push(new_fragment);
}
pub(crate) fn drop_last_empty_fragment(&mut self) {
let drop_empty_last_fragment = self.fragments.last().map(|f| f.is_empty()).unwrap_or(false);
if drop_empty_last_fragment {
_ = self.fragments.pop();
}
}
#[inline(always)]
pub(crate) fn growth_get_ptr(&self, index: usize) -> Option<*const T> {
self.growth.get_ptr(&self.fragments, index)
}
#[inline(always)]
pub(crate) fn growth_get_ptr_mut(&mut self, index: usize) -> Option<*mut T> {
self.growth.get_ptr_mut(&mut self.fragments, index)
}
pub fn reserve_maximum_concurrent_capacity(&mut self, new_maximum_capacity: usize) -> usize {
let current_max = self.maximum_concurrent_capacity();
match current_max < new_maximum_capacity {
true => {
self.concurrent_reserve(new_maximum_capacity)
.expect("Failed to reserve maximum capacity");
self.maximum_concurrent_capacity()
}
false => self.maximum_concurrent_capacity(),
}
}
}
#[cfg(test)]
mod tests {
use crate::growth::growth_trait::GrowthWithConstantTimeAccess;
use crate::test_all_growth_types;
use crate::*;
use alloc::vec;
#[test]
fn fragments() {
fn test<G: Growth>(mut vec: SplitVec<usize, G>) {
for i in 0..42 {
vec.push(i);
}
let mut combined = vec![];
let mut combined_mut = vec![];
for fra in vec.fragments() {
combined.extend_from_slice(fra);
}
for fra in unsafe { vec.fragments_mut() } {
combined_mut.extend_from_slice(fra);
}
for i in 0..42 {
assert_eq!(i, vec[i]);
assert_eq!(i, combined[i]);
assert_eq!(i, combined_mut[i]);
}
}
test_all_growth_types!(test);
}
#[test]
fn get_fragment_and_inner_indices() {
#[cfg(not(miri))]
const LEN: usize = 432;
#[cfg(miri)]
const LEN: usize = 57;
fn test<G: Growth>(mut vec: SplitVec<usize, G>) {
for i in 0..LEN {
vec.push(i);
assert_eq!(None, vec.get_fragment_and_inner_indices(i + 1));
}
for i in 0..LEN {
let (f, ii) = vec.get_fragment_and_inner_indices(i).expect("is-some");
assert_eq!(vec[i], vec.fragments[f][ii]);
}
}
test_all_growth_types!(test);
}
#[test]
fn get_ptr_mut() {
fn test<G: GrowthWithConstantTimeAccess>(mut vec: SplitVec<usize, G>) {
for i in 0..65 {
vec.push(i);
}
for i in 0..64 {
let p = vec.get_ptr_mut(i).expect("is-some");
assert_eq!(i, unsafe { *p });
}
for i in 64..vec.capacity() {
let p = vec.get_ptr_mut(i);
assert!(p.is_some());
}
for i in vec.capacity()..(vec.capacity() * 2) {
let p = vec.get_ptr_mut(i);
assert!(p.is_none());
}
}
test(SplitVec::with_doubling_growth());
test(SplitVec::with_linear_growth(6));
}
#[test]
fn add_fragment() {
fn test<G: Growth>(mut vec: SplitVec<usize, G>) {
for _ in 0..10 {
let expected_new_fragment_cap = vec.growth.new_fragment_capacity(&vec.fragments);
let new_fragment_cap = vec.add_fragment();
assert_eq!(expected_new_fragment_cap, new_fragment_cap);
}
vec.clear();
let mut expected_capacity = vec.capacity();
for _ in 0..2 {
let expected_new_fragment_cap = vec.growth.new_fragment_capacity(&vec.fragments);
expected_capacity += expected_new_fragment_cap;
vec.add_fragment();
}
assert_eq!(expected_capacity, vec.capacity());
}
test_all_growth_types!(test);
}
}