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
use crate::{
range_helpers::{range_end, range_start},
Growth, SplitVec,
};
use core::{cmp::Ordering, ops::RangeBounds};
use orx_pinned_vec::PinnedVec;
#[derive(PartialEq, Eq, Debug, Clone)]
/// Returns the result of trying to get a slice as a contagious memory from the split vector.
pub enum SplitVecSlice<'a, T> {
/// The desired range completely belongs to one fragment and the slice can be provided.
Ok(&'a [T]),
/// The desired range is split to at least two fragments.
/// The tuple contains indices of the fragments containing
/// the first and last element of the desired range.
Fragmented(usize, usize),
/// An error case where the desired range is out of bounds of the vector.
OutOfBounds,
}
impl<T, G: Growth> SplitVec<T, G> {
/// Returns the result of trying to return the required `range` as a contagious slice of data.
/// It might return Ok of the slice if the range belongs to one fragment.
///
/// Otherwise, one of the two failure cases will be returned:
/// * OutOfBounds if the range does not fit in the range of the entire split vector, or
/// * Fragmented if the range belongs to at least two fragments, additionally returns the fragment indices of the range.
///
/// # Examples
///
/// ```
/// use orx_split_vec::*;
///
/// let mut vec = SplitVec::with_linear_growth(2);
///
/// vec.extend_from_slice(&[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]);
///
/// assert_eq!(4, vec.fragments()[0].capacity());
/// assert_eq!(4, vec.fragments()[1].capacity());
/// assert_eq!(4, vec.fragments()[2].capacity());
///
/// assert_eq!(4, vec.fragments()[0].len()); // [0, 1, 2, 3]
/// assert_eq!(4, vec.fragments()[1].len()); // [4, 5, 6, 7]
/// assert_eq!(2, vec.fragments()[2].len()); // [8, 9]
///
/// // Ok
/// assert_eq!(SplitVecSlice::Ok(&[0, 1, 2, 3]), vec.try_get_slice(0..4));
/// assert_eq!(SplitVecSlice::Ok(&[5, 6]), vec.try_get_slice(5..7));
/// assert_eq!(SplitVecSlice::Ok(&[8, 9]), vec.try_get_slice(8..10));
///
/// // Fragmented
/// assert_eq!(SplitVecSlice::Fragmented(0, 1), vec.try_get_slice(3..6));
/// assert_eq!(SplitVecSlice::Fragmented(0, 2), vec.try_get_slice(3..9));
/// assert_eq!(SplitVecSlice::Fragmented(1, 2), vec.try_get_slice(7..9));
///
/// // OutOfBounds
/// assert_eq!(SplitVecSlice::OutOfBounds, vec.try_get_slice(5..12));
/// assert_eq!(SplitVecSlice::OutOfBounds, vec.try_get_slice(10..11));
/// ```
pub fn try_get_slice<R: RangeBounds<usize>>(&self, range: R) -> SplitVecSlice<T> {
let a = range_start(&range);
let b = range_end(&range, self.len());
match b.saturating_sub(a) {
0 => SplitVecSlice::Ok(&[]),
_ => match self.get_fragment_and_inner_indices(a) {
None => SplitVecSlice::OutOfBounds,
Some((sf, si)) => match self.get_fragment_and_inner_indices(b - 1) {
None => SplitVecSlice::OutOfBounds,
Some((ef, ei)) => match sf.cmp(&ef) {
Ordering::Equal => SplitVecSlice::Ok(&self.fragments[sf][si..=ei]),
_ => SplitVecSlice::Fragmented(sf, ef),
},
},
},
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::test_all_growth_types;
use crate::*;
#[test]
fn try_get_slice() {
fn test<G: Growth>(mut vec: SplitVec<usize, G>) {
for i in 0..42 {
assert_eq!(SplitVecSlice::OutOfBounds, vec.try_get_slice(0..(i + 1)));
assert_eq!(SplitVecSlice::OutOfBounds, vec.try_get_slice(i..(i + 1)));
vec.push(i);
}
for f in 0..vec.fragments.len() {
let begin: usize = vec.fragments.iter().take(f).map(|f| f.len()).sum();
let end = begin + vec.fragments[f].len();
let half = begin + vec.fragments[f].len() / 2;
// ok
let slice_full_fragment = vec.try_get_slice(begin..end);
assert_eq!(slice_full_fragment, SplitVecSlice::Ok(&vec.fragments[f]));
let slice_half_fragment = vec.try_get_slice(begin..half);
assert_eq!(
slice_half_fragment,
SplitVecSlice::Ok(&vec.fragments[f][0..vec.fragments[f].len() / 2])
);
let slice_half_fragment = vec.try_get_slice(half..end);
assert_eq!(
slice_half_fragment,
SplitVecSlice::Ok(
&vec.fragments[f][vec.fragments[f].len() / 2..vec.fragments[f].len()]
)
);
// fragmented
if f > 0 {
let prev_begin = begin - 1;
let slice = vec.try_get_slice(prev_begin..end);
assert_eq!(slice, SplitVecSlice::Fragmented(f - 1, f));
if f < vec.fragments.len() - 1 {
let next_end = end + 1;
let slice = vec.try_get_slice(begin..next_end);
assert_eq!(slice, SplitVecSlice::Fragmented(f, f + 1));
let slice = vec.try_get_slice(prev_begin..next_end);
assert_eq!(slice, SplitVecSlice::Fragmented(f - 1, f + 1));
}
}
}
}
test_all_growth_types!(test);
}
}