1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178
use crate::{fragment::fragment_struct::Fragment, Doubling, Growth};
/// A split vector; i.e., a vector of fragments, with the following features:
///
/// * Flexible in growth strategies; custom strategies can be defined.
/// * Growth does not cause any memory copies.
/// * Capacity of an already created fragment is never changed.
/// * The above feature allows the data to stay pinned in place. Memory location of an item added to the split vector will never change unless it is removed from the vector or the vector is dropped.
pub struct SplitVec<T, G = Doubling>
where
G: Growth,
{
pub(crate) len: usize,
pub(crate) fragments: Vec<Fragment<T>>,
/// Growth strategy of the split vector.
///
/// Note that allocated data of split vector is pinned and allocated in fragments.
/// Therefore, growth does not require copying data.
///
/// The growth stratety determines the capacity of each fragment
/// that will be added to the split vector when needed.
///
/// Furthermore, it has an impact on index-access to the elements.
/// See below for the complexities:
///
/// * `LinearGrowth` (`SplitVec::with_linear_growth`) -> O(1)
/// * `DoublingGrowth` (`SplitVec::with_doubling_growth`) -> O(1), however slower than linear
/// * `ExponentialGrowth` (`SplitVec::with_exponential_growth`) -> O(f) where f is the number of fragments
/// * `CustomGrowth` (`SplitVec::with_custom_growth`) -> O(f) where f is the number of fragments
pub growth: G,
}
impl<T, G> SplitVec<T, G>
where
G: Growth,
{
/// Returns a mutable reference to the vector of fragments.
///
/// # Safety
///
/// Fragments of the split vector maintain the following structure:
/// * the fragments vector is never empty, it has at least one fragment;
/// * all fragments have a positive capacity;
/// * capacity of fragment f is equal to `self.growth.get_capacity(f)`.
/// * if there exist F fragments in the vector:
/// * none of the fragments with indices `0..F-2` has capacity; i.e., len==capacity,
/// * the last fragment at position `F-1` might or might not have capacity.
///
/// Breaking this structure invalidates the `SplitVec` struct,
/// and its methods lead to UB.
pub unsafe fn fragments_mut(&mut self) -> &mut Vec<Fragment<T>> {
&mut self.fragments
}
/// Returns the fragments of the split vector.
///
/// The fragments of the split vector satisfy the following structure:
/// * the fragments vector is never empty, it has at least one fragment;
/// * all fragments have a positive capacity;
/// * capacity of fragment f is equal to `self.growth.get_capacity(f)`.
/// * if there exist F fragments in the vector:
/// * none of the fragments with indices `0..F-2` has capacity; i.e., len==capacity,
/// * the last fragment at position `F-1` might or might not have capacity.
///
/// # Examples
///
/// ```
/// use orx_split_vec::prelude::*;
///
/// let mut vec = SplitVec::with_linear_growth(2);
///
/// for i in 0..6 {
/// vec.push(i);
/// }
///
/// assert_eq!(2, vec.fragments().len());
/// assert_eq!(&[0, 1, 2, 3], vec.fragments()[0].as_slice());
/// assert_eq!(&[4, 5], vec.fragments()[1].as_slice());
///
/// ```
pub fn fragments(&self) -> &[Fragment<T>] {
&self.fragments
}
/// Returns the fragment index and the index within fragment of the item with the given `index`;
/// None if the index is out of bounds.
///
/// # Examples
///
/// ```
/// use orx_split_vec::prelude::*;
///
/// let mut vec = SplitVec::with_linear_growth(2);
///
/// for i in 0..6 {
/// vec.push(i);
/// }
///
/// assert_eq!(&[0, 1, 2, 3], vec.fragments()[0].as_slice());
/// assert_eq!(&[4, 5], vec.fragments()[1].as_slice());
///
/// // first fragment
/// assert_eq!(Some((0, 0)), vec.get_fragment_and_inner_indices(0));
/// assert_eq!(Some((0, 1)), vec.get_fragment_and_inner_indices(1));
/// assert_eq!(Some((0, 2)), vec.get_fragment_and_inner_indices(2));
/// assert_eq!(Some((0, 3)), vec.get_fragment_and_inner_indices(3));
///
/// // second fragment
/// assert_eq!(Some((1, 0)), vec.get_fragment_and_inner_indices(4));
/// assert_eq!(Some((1, 1)), vec.get_fragment_and_inner_indices(5));
///
/// // out of bounds
/// assert_eq!(None, vec.get_fragment_and_inner_indices(6));
/// ```
#[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)
}
// helpers
pub(crate) fn has_capacity_for_one(&self) -> bool {
self.fragments
.last()
.map(|f| f.has_capacity_for_one())
.unwrap_or(false)
}
pub(crate) fn add_fragment(&mut self) {
let capacity = self.growth.new_fragment_capacity(&self.fragments);
let new_fragment = Fragment::new(capacity);
self.fragments.push(new_fragment);
}
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);
}
}
#[cfg(test)]
mod tests {
use crate::prelude::*;
use crate::test_all_growth_types;
#[test]
fn fragments() {
fn test<G: Growth>(mut vec: SplitVec<usize, G>) {
for i in 0..42 {
vec.push(i);
}
let mut combined = vec![];
for fra in vec.fragments() {
combined.extend_from_slice(fra);
}
for i in 0..42 {
assert_eq!(i, vec[i]);
assert_eq!(i, combined[i]);
}
}
test_all_growth_types!(test);
}
#[test]
fn get_fragment_and_inner_indices() {
fn test<G: Growth>(mut vec: SplitVec<usize, G>) {
for i in 0..432 {
vec.push(i);
assert_eq!(None, vec.get_fragment_and_inner_indices(i + 1));
}
for i in 0..432 {
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);
}
}