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
use std::ops::Range;

use crate::SplitVec;

#[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> SplitVec<T> {
    /// 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::{FragmentGrowth, SplitVec, SplitVecSlice};
    ///
    /// let growth = FragmentGrowth::constant(4);
    /// let mut vec = SplitVec::with_growth(growth);
    ///
    /// 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(&self, range: Range<usize>) -> SplitVecSlice<T> {
        if let Some((sf, si)) = self.fragment_and_inner_index(range.start) {
            if let Some((ef, ei)) = self.fragment_and_inner_index(range.end - 1) {
                if sf == ef {
                    SplitVecSlice::Ok(&self.fragments[sf][si..=ei])
                } else {
                    SplitVecSlice::Fragmented(sf, ef)
                }
            } else {
                SplitVecSlice::OutOfBounds
            }
        } else {
            SplitVecSlice::OutOfBounds
        }
    }

    /// Returns the view on the required `range` as a vector of slices:
    ///
    /// * returns an empty vector if the range is out of bounds;
    /// * returns a vector with one slice if the range completely belongs to one fragment (in this case `try_get_slice` would return Ok),
    /// * returns an ordered vector of slices when chained forms the required range.
    ///
    /// # Examples
    ///
    /// ```
    /// use orx_split_vec::{FragmentGrowth, SplitVec, SplitVecSlice};
    ///
    /// let growth = FragmentGrowth::constant(4);
    /// let mut vec = SplitVec::with_growth(growth);
    ///
    /// 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]
    ///
    /// // single fragment
    /// assert_eq!(vec![&[0, 1, 2, 3]], vec.slice(0..4));
    /// assert_eq!(vec![&[5, 6]], vec.slice(5..7));
    /// assert_eq!(vec![&[8, 9]], vec.slice(8..10));
    ///
    /// // Fragmented
    /// assert_eq!(vec![&vec![3], &vec![4, 5]], vec.slice(3..6));
    /// assert_eq!(vec![&vec![3], &vec![4, 5, 6, 7], &vec![8]], vec.slice(3..9));
    /// assert_eq!(vec![&vec![7], &vec![8]], vec.slice(7..9));
    ///
    /// // OutOfBounds
    /// assert!(vec.slice(5..12).is_empty());
    /// assert!(vec.slice(10..11).is_empty());
    /// ```
    pub fn slice(&self, range: Range<usize>) -> Vec<&[T]> {
        if let Some((sf, si)) = self.fragment_and_inner_index(range.start) {
            if let Some((ef, ei)) = self.fragment_and_inner_index(range.end - 1) {
                if sf == ef {
                    vec![&self.fragments[sf][si..=ei]]
                } else {
                    let mut vec = Vec::with_capacity(ef - sf);
                    vec.push(&self.fragments[sf][si..]);
                    for f in sf + 1..ef {
                        vec.push(&self.fragments[f]);
                    }
                    vec.push(&self.fragments[ef][..=ei]);
                    vec
                }
            } else {
                vec![]
            }
        } else {
            vec![]
        }
    }
}