orx_split_vec/
slice.rs

1use crate::{
2    Growth, SplitVec,
3    range_helpers::{range_end, range_start},
4};
5use core::{cmp::Ordering, ops::RangeBounds};
6use orx_pinned_vec::PinnedVec;
7
8#[derive(PartialEq, Eq, Debug, Clone)]
9/// Returns the result of trying to get a slice as a contiguous memory from the split vector.
10pub enum SplitVecSlice<'a, T> {
11    /// The desired range completely belongs to one fragment and the slice can be provided.
12    Ok(&'a [T]),
13    /// The desired range is split to at least two fragments.
14    /// The tuple contains indices of the fragments containing
15    /// the first and last element of the desired range.
16    Fragmented(usize, usize),
17    /// An error case where the desired range is out of bounds of the vector.
18    OutOfBounds,
19}
20
21impl<T, G: Growth> SplitVec<T, G> {
22    /// Returns the result of trying to return the required `range` as a contiguous slice of data.
23    /// It might return Ok of the slice if the range belongs to one fragment.
24    ///
25    /// Otherwise, one of the two failure cases will be returned:
26    /// * OutOfBounds if the range does not fit in the range of the entire split vector, or
27    /// * Fragmented if the range belongs to at least two fragments, additionally returns the fragment indices of the range.
28    ///
29    /// # Examples
30    ///
31    /// ```
32    /// use orx_split_vec::*;
33    ///
34    /// let mut vec = SplitVec::with_linear_growth(2);
35    ///
36    /// vec.extend_from_slice(&[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]);
37    ///
38    /// assert_eq!(4, vec.fragments()[0].capacity());
39    /// assert_eq!(4, vec.fragments()[1].capacity());
40    /// assert_eq!(4, vec.fragments()[2].capacity());
41    ///
42    /// assert_eq!(4, vec.fragments()[0].len()); // [0, 1, 2, 3]
43    /// assert_eq!(4, vec.fragments()[1].len()); // [4, 5, 6, 7]
44    /// assert_eq!(2, vec.fragments()[2].len()); // [8, 9]
45    ///
46    /// // Ok
47    /// assert_eq!(SplitVecSlice::Ok(&[0, 1, 2, 3]), vec.try_get_slice(0..4));
48    /// assert_eq!(SplitVecSlice::Ok(&[5, 6]), vec.try_get_slice(5..7));
49    /// assert_eq!(SplitVecSlice::Ok(&[8, 9]), vec.try_get_slice(8..10));
50    ///
51    /// // Fragmented
52    /// assert_eq!(SplitVecSlice::Fragmented(0, 1), vec.try_get_slice(3..6));
53    /// assert_eq!(SplitVecSlice::Fragmented(0, 2), vec.try_get_slice(3..9));
54    /// assert_eq!(SplitVecSlice::Fragmented(1, 2), vec.try_get_slice(7..9));
55    ///
56    /// // OutOfBounds
57    /// assert_eq!(SplitVecSlice::OutOfBounds, vec.try_get_slice(5..12));
58    /// assert_eq!(SplitVecSlice::OutOfBounds, vec.try_get_slice(10..11));
59    /// ```
60    pub fn try_get_slice<R: RangeBounds<usize>>(&self, range: R) -> SplitVecSlice<'_, T> {
61        let a = range_start(&range);
62        let b = range_end(&range, self.len());
63
64        match b.saturating_sub(a) {
65            0 => SplitVecSlice::Ok(&[]),
66            _ => match self.get_fragment_and_inner_indices(a) {
67                None => SplitVecSlice::OutOfBounds,
68                Some((sf, si)) => match self.get_fragment_and_inner_indices(b - 1) {
69                    None => SplitVecSlice::OutOfBounds,
70                    Some((ef, ei)) => match sf.cmp(&ef) {
71                        Ordering::Equal => SplitVecSlice::Ok(&self.fragments[sf][si..=ei]),
72                        _ => SplitVecSlice::Fragmented(sf, ef),
73                    },
74                },
75            },
76        }
77    }
78}
79
80#[cfg(test)]
81mod tests {
82
83    use super::*;
84    use crate::test_all_growth_types;
85    use crate::*;
86
87    #[test]
88    fn try_get_slice() {
89        fn test<G: Growth>(mut vec: SplitVec<usize, G>) {
90            for i in 0..42 {
91                assert_eq!(SplitVecSlice::OutOfBounds, vec.try_get_slice(0..(i + 1)));
92                assert_eq!(SplitVecSlice::OutOfBounds, vec.try_get_slice(i..(i + 1)));
93                vec.push(i);
94            }
95
96            for f in 0..vec.fragments.len() {
97                let begin: usize = vec.fragments.iter().take(f).map(|f| f.len()).sum();
98                let end = begin + vec.fragments[f].len();
99                let half = begin + vec.fragments[f].len() / 2;
100
101                // ok
102                let slice_full_fragment = vec.try_get_slice(begin..end);
103                assert_eq!(slice_full_fragment, SplitVecSlice::Ok(&vec.fragments[f]));
104
105                let slice_half_fragment = vec.try_get_slice(begin..half);
106                assert_eq!(
107                    slice_half_fragment,
108                    SplitVecSlice::Ok(&vec.fragments[f][0..vec.fragments[f].len() / 2])
109                );
110
111                let slice_half_fragment = vec.try_get_slice(half..end);
112                assert_eq!(
113                    slice_half_fragment,
114                    SplitVecSlice::Ok(
115                        &vec.fragments[f][vec.fragments[f].len() / 2..vec.fragments[f].len()]
116                    )
117                );
118
119                // fragmented
120                if f > 0 {
121                    let prev_begin = begin - 1;
122                    let slice = vec.try_get_slice(prev_begin..end);
123                    assert_eq!(slice, SplitVecSlice::Fragmented(f - 1, f));
124                    if f < vec.fragments.len() - 1 {
125                        let next_end = end + 1;
126
127                        let slice = vec.try_get_slice(begin..next_end);
128                        assert_eq!(slice, SplitVecSlice::Fragmented(f, f + 1));
129
130                        let slice = vec.try_get_slice(prev_begin..next_end);
131                        assert_eq!(slice, SplitVecSlice::Fragmented(f - 1, f + 1));
132                    }
133                }
134            }
135        }
136        test_all_growth_types!(test);
137    }
138}