orx_split_vec/growth/doubling/
from.rs

1use core::{cmp::min, mem::MaybeUninit, ptr::copy_nonoverlapping};
2
3use super::constants::CUMULATIVE_CAPACITIES;
4use crate::{Doubling, Fragment, SplitVec, growth::doubling::constants::CAPACITIES};
5use alloc::vec::Vec;
6
7impl<T> From<Vec<T>> for SplitVec<T, Doubling> {
8    /// Converts a `Vec` into a `SplitVec`.
9    ///
10    /// # Examples
11    ///
12    /// ```
13    /// use orx_split_vec::*;
14    ///
15    /// let vec = vec!['a', 'b', 'c'];
16    /// let vec_capacity = vec.capacity();
17    ///
18    /// let split_vec: SplitVec<_, Doubling> = vec.into();
19    ///
20    /// assert_eq!(split_vec, &['a', 'b', 'c']);
21    /// assert_eq!(1, split_vec.fragments().len());
22    /// assert!(vec_capacity <= split_vec.capacity());
23    /// ```
24    fn from(mut value: Vec<T>) -> Self {
25        let len = value.len();
26        // Number of fragments to create
27        let f = CUMULATIVE_CAPACITIES
28            .iter()
29            .enumerate()
30            .find(|(_, cum_cap)| **cum_cap >= len)
31            .map(|(f, _)| f)
32            .expect("overflow");
33
34        let mut fragments = Vec::with_capacity(f + 1);
35        let fragments_init = fragments.spare_capacity_mut();
36        let mut remaining_len = len;
37        let mut curr_f = f;
38        while remaining_len > 0 {
39            curr_f -= 1;
40            let capacity = CAPACITIES[curr_f];
41            // for example, if the current fragment has a capacity of 8 but there are only 5 elements to copy,
42            // we want the copy length to only be 1
43            let copy_len = min(remaining_len - CUMULATIVE_CAPACITIES[curr_f], capacity);
44            remaining_len -= copy_len;
45
46            // This is adapted from Vec::split_off, with the difference that it
47            // reserves the full capacity first to avoid extra allocations
48            let mut fragment_data = Vec::with_capacity(capacity);
49            unsafe {
50                value.set_len(remaining_len);
51                fragment_data.set_len(copy_len);
52                copy_nonoverlapping(
53                    value.as_ptr().add(remaining_len),
54                    fragment_data.as_mut_ptr(),
55                    copy_len,
56                );
57            }
58            fragments_init[curr_f] = MaybeUninit::new(Fragment::from(fragment_data));
59        }
60        debug_assert_eq!(curr_f, 0);
61        unsafe { fragments.set_len(f) };
62
63        Self::from_raw_parts(len, fragments, Doubling)
64    }
65}