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
use crate::{Fragment, Growth, SplitVec};

impl<T> SplitVec<T> {
    /// Creates an empty split vector with default growth strategy.
    ///
    /// Default growth strategy is `Doubling` with initial capacity of 4.
    ///
    /// # Examples
    ///
    /// ```
    /// use orx_split_vec::*;
    ///
    /// let vec: SplitVec<f32> = SplitVec::new();
    ///
    /// assert_eq!(1, vec.fragments().len());
    /// assert_eq!(4, vec.fragments()[0].capacity());
    /// ```
    pub fn new() -> Self {
        Self::with_doubling_growth()
    }
}

impl<T, G> SplitVec<T, G>
where
    G: Growth,
{
    /// Creates an empty split vector with the given `growth` strategy.
    ///
    /// This constructor is especially useful to define custom growth strategies.
    ///
    /// # Examples
    ///
    /// ```
    /// use orx_split_vec::*;
    ///
    /// #[derive(Clone)]
    /// pub struct DoubleEverySecondFragment(usize); // any custom growth strategy
    ///
    /// impl PseudoDefault for DoubleEverySecondFragment {
    ///     fn pseudo_default() -> Self {
    ///         DoubleEverySecondFragment(1)
    ///     }
    /// }
    ///
    /// impl Growth for DoubleEverySecondFragment {
    ///     fn new_fragment_capacity_from(&self, fragment_capacities: impl ExactSizeIterator<Item = usize>) -> usize {
    ///         let num_fragments = fragment_capacities.len();
    ///         fragment_capacities
    ///             .last()
    ///             .map(|f| {
    ///                 let do_double = num_fragments % 2 == 0;
    ///                 if do_double {
    ///                     f * 2
    ///                 } else {
    ///                     f
    ///                 }
    ///             })
    ///             .unwrap_or(self.0)
    ///     }
    /// }
    /// let mut vec = SplitVec::with_growth(DoubleEverySecondFragment(8));
    /// for i in 0..17 {
    ///     vec.push(i);
    /// }
    ///
    /// assert_eq!(3, vec.fragments().len());
    ///
    /// assert_eq!(8, vec.fragments()[0].capacity());
    /// assert_eq!(8, vec.fragments()[0].len());
    ///
    /// assert_eq!(8, vec.fragments()[1].capacity());
    /// assert_eq!(8, vec.fragments()[1].len());
    ///
    /// assert_eq!(16, vec.fragments()[2].capacity());
    /// assert_eq!(1, vec.fragments()[2].len());
    /// ```
    pub fn with_growth(growth: G) -> Self {
        let capacity = Growth::new_fragment_capacity::<T>(&growth, &[]);
        let fragment = Fragment::new(capacity);
        let fragments = alloc::vec![fragment];
        SplitVec::from_raw_parts(0, fragments, growth)
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use crate::{Doubling, Linear};

    #[test]
    fn new() {
        let vec: SplitVec<usize> = SplitVec::new();
        let vec: SplitVec<usize, Doubling> = vec;

        assert_eq!(1, vec.fragments().len());
        assert_eq!(4, vec.fragments()[0].capacity());
    }

    #[test]
    fn with_initial_capacity() {
        let vec: SplitVec<usize> = SplitVec::new();
        let vec: SplitVec<usize, Doubling> = vec;

        assert_eq!(1, vec.fragments().len());
        assert_eq!(4, vec.fragments()[0].capacity());
    }

    #[test]
    fn with_growth() {
        let vec: SplitVec<char, Linear> = SplitVec::with_growth(Linear::new(3));
        assert_eq!(1, vec.fragments().len());
        assert_eq!(8, vec.fragments()[0].capacity());

        let vec: SplitVec<char, Doubling> = SplitVec::with_growth(Doubling);
        assert_eq!(1, vec.fragments().len());
        assert_eq!(4, vec.fragments()[0].capacity());
    }
}