use crate::Growth;
#[derive(Default, Clone)]
pub struct Fragment<T> {
pub(crate) data: Vec<T>,
}
impl<T> Fragment<T> {
pub fn new_with_first_value(capacity: usize, first_value: T) -> Self {
let mut data = Vec::with_capacity(capacity);
data.push(first_value);
Self { data }
}
pub fn new(capacity: usize) -> Self {
Self {
data: Vec::with_capacity(capacity),
}
}
pub fn new_filled<F: Fn() -> T>(capacity: usize, f: F) -> Self {
let mut data = Vec::with_capacity(capacity);
for _ in 0..capacity {
data.push(f());
}
Self { data }
}
pub fn has_capacity_for_one(&self) -> bool {
self.data.len() < self.data.capacity()
}
pub fn room(&self) -> usize {
self.data.capacity() - self.data.len()
}
pub(crate) fn fragments_with_default_capacity() -> Vec<Fragment<T>> {
Vec::new()
}
pub(crate) fn into_fragments(self) -> Vec<Fragment<T>> {
let mut fragments = Self::fragments_with_default_capacity();
fragments.push(self);
fragments
}
pub(crate) fn fragments_with_capacity(fragments_capacity: usize) -> Vec<Fragment<T>> {
Vec::with_capacity(fragments_capacity)
}
pub(crate) fn into_fragments_with_capacity(
self,
fragments_capacity: usize,
) -> Vec<Fragment<T>> {
let mut fragments = Self::fragments_with_capacity(fragments_capacity);
fragments.push(self);
fragments
}
#[inline(always)]
pub(crate) unsafe fn zero(&mut self) {
let slice = std::slice::from_raw_parts_mut(self.data.as_mut_ptr(), self.capacity());
slice.iter_mut().for_each(|m| *m = std::mem::zeroed());
}
}
pub(crate) unsafe fn set_fragments_len<T>(fragments: &mut [Fragment<T>], len: usize) {
let mut remaining = len;
for fragment in fragments {
let capacity = fragment.capacity();
match remaining <= capacity {
true => {
fragment.set_len(remaining);
remaining = 0;
}
false => {
fragment.set_len(capacity);
remaining -= capacity;
}
}
}
}
pub(crate) fn maximum_concurrent_capacity<G: Growth, T>(
fragments: &[Fragment<T>],
fragments_capacity: usize,
growth: &G,
) -> usize {
assert!(fragments_capacity >= fragments.len());
match fragments_capacity == fragments.len() {
true => fragments.iter().map(|x| x.capacity()).sum(),
false => {
let mut capacities: Vec<_> = fragments.iter().map(|x| x.capacity()).collect();
for _ in fragments.len()..fragments_capacity {
let new_capacity = growth.new_fragment_capacity_from(capacities.iter().copied());
capacities.push(new_capacity);
}
capacities.iter().sum()
}
}
}
pub(crate) fn num_fragments_for_capacity<G: Growth, T>(
fragments: &[Fragment<T>],
growth: &G,
required_capacity: usize,
) -> (usize, usize) {
let current_capacity: usize = fragments.iter().map(|x| x.capacity()).sum();
match current_capacity >= required_capacity {
true => (fragments.len(), current_capacity),
false => {
let mut num_fragments = fragments.len();
let mut capacities: Vec<_> = fragments.iter().map(|x| x.capacity()).collect();
let mut capacity = current_capacity;
while capacity < required_capacity {
let new_capacity = growth.new_fragment_capacity_from(capacities.iter().copied());
capacities.push(new_capacity);
capacity += new_capacity;
num_fragments += 1;
}
(num_fragments, capacity)
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn zeroed() {
let mut fragment: Fragment<i32> = Fragment::new(4);
unsafe { fragment.zero() };
unsafe { fragment.set_len(4) };
let zero: i32 = unsafe { std::mem::zeroed() };
for i in 0..4 {
assert_eq!(fragment.get(i), Some(&zero));
}
}
}