use super::constants::*;
use crate::growth::growth_trait::{Growth, GrowthWithConstantTimeAccess};
use crate::{Fragment, SplitVec};
use alloc::string::String;
use orx_pseudo_default::PseudoDefault;
#[derive(Debug, Default, Clone, PartialEq)]
pub struct Doubling;
impl PseudoDefault for Doubling {
fn pseudo_default() -> Self {
Default::default()
}
}
impl Growth for Doubling {
#[inline(always)]
fn new_fragment_capacity_from(
&self,
fragment_capacities: impl ExactSizeIterator<Item = usize>,
) -> usize {
fragment_capacities.last().map(|x| x * 2).unwrap_or(4)
}
#[inline(always)]
fn get_fragment_and_inner_indices<T>(
&self,
vec_len: usize,
_fragments: &[Fragment<T>],
element_index: usize,
) -> Option<(usize, usize)> {
match element_index < vec_len {
true => Some(self.get_fragment_and_inner_indices_unchecked(element_index)),
false => None,
}
}
#[inline(always)]
fn get_ptr<T>(&self, fragments: &[Fragment<T>], index: usize) -> Option<*const T> {
<Self as GrowthWithConstantTimeAccess>::get_ptr(self, fragments, index)
}
#[inline(always)]
fn get_ptr_mut<T>(&self, fragments: &mut [Fragment<T>], index: usize) -> Option<*mut T> {
<Self as GrowthWithConstantTimeAccess>::get_ptr_mut(self, fragments, index)
}
#[inline(always)]
fn get_ptr_mut_and_indices<T>(
&self,
fragments: &mut [Fragment<T>],
index: usize,
) -> Option<(*mut T, usize, usize)> {
<Self as GrowthWithConstantTimeAccess>::get_ptr_mut_and_indices(self, fragments, index)
}
fn maximum_concurrent_capacity<T>(
&self,
fragments: &[Fragment<T>],
fragments_capacity: usize,
) -> usize {
assert!(fragments_capacity >= fragments.len());
CUMULATIVE_CAPACITIES[fragments_capacity]
}
fn required_fragments_len<T>(
&self,
_: &[Fragment<T>],
maximum_capacity: usize,
) -> Result<usize, String> {
for (f, capacity) in CUMULATIVE_CAPACITIES.iter().enumerate() {
if maximum_capacity <= *capacity {
return Ok(f);
}
}
Err(alloc::format!(
"Maximum cumulative capacity that can be reached by the Doubling strategy is {}.",
CUMULATIVE_CAPACITIES[CUMULATIVE_CAPACITIES.len() - 1]
))
}
fn maximum_concurrent_capacity_bound<T>(&self, _: &[Fragment<T>], _: usize) -> usize {
*CUMULATIVE_CAPACITIES
.last()
.expect("cumulative capacities is not empty")
}
}
impl GrowthWithConstantTimeAccess for Doubling {
#[inline(always)]
fn get_fragment_and_inner_indices_unchecked(&self, element_index: usize) -> (usize, usize) {
let element_index_offset = element_index + FIRST_FRAGMENT_CAPACITY;
let leading_zeros = usize::leading_zeros(element_index_offset) as usize;
let f = OFFSET_FRAGMENT_IDX - leading_zeros;
(f, element_index - CUMULATIVE_CAPACITIES[f])
}
fn fragment_capacity_of(&self, fragment_index: usize) -> usize {
CAPACITIES[fragment_index]
}
}
impl<T> SplitVec<T, Doubling> {
pub fn with_doubling_growth() -> Self {
let fragments = Fragment::new_empty(FIRST_FRAGMENT_CAPACITY).into_fragments();
Self::from_raw_parts(0, fragments, Doubling)
}
pub fn with_doubling_growth_and_fragments_capacity(fragments_capacity: usize) -> Self {
assert!(
fragments_capacity > 0 && fragments_capacity <= CAPACITIES_LEN,
"fragments_capacity must be within 1..{CAPACITIES_LEN}; however, {fragments_capacity} is provided."
);
assert!(fragments_capacity > 0);
let fragments = Fragment::new_empty(FIRST_FRAGMENT_CAPACITY)
.into_fragments_with_capacity(fragments_capacity);
Self::from_raw_parts(0, fragments, Doubling)
}
pub fn with_doubling_growth_and_max_concurrent_capacity() -> Self {
let fragments = Fragment::new_empty(FIRST_FRAGMENT_CAPACITY)
.into_fragments_with_capacity(CAPACITIES_LEN);
Self::from_raw_parts(0, fragments, Doubling)
}
}