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}