orx_split_vec/common_traits/
index.rs

1use crate::{Growth, SplitVec};
2use core::ops::{Index, IndexMut};
3
4impl<T, G> Index<usize> for SplitVec<T, G>
5where
6    G: Growth,
7{
8    type Output = T;
9
10    /// Returns a reference to the `index`-th item of the vector.
11    ///
12    /// # Panics
13    ///
14    /// Panics if `index` is out of bounds.
15    ///
16    /// # Examples
17    ///
18    /// ```
19    /// use orx_split_vec::*;
20    ///
21    /// let mut vec = SplitVec::with_linear_growth(4);
22    ///
23    /// vec.extend_from_slice(&[0, 1, 2, 3]);
24    ///
25    /// assert_eq!(&1, &vec[1]);
26    /// assert_eq!(&3, &vec[3]);
27    /// // let x = &vec[4]; // panics!
28    /// ```
29    fn index(&self, index: usize) -> &Self::Output {
30        let (f, i) = self
31            .get_fragment_and_inner_indices(index)
32            .expect("index is out of bounds");
33        &self.fragments[f][i]
34    }
35}
36
37impl<T, G> IndexMut<usize> for SplitVec<T, G>
38where
39    G: Growth,
40{
41    /// Returns a mutable reference to the `index`-th item of the vector.
42    ///
43    /// # Panics
44    ///
45    /// Panics if `index` is out of bounds.
46    ///
47    /// # Examples
48    ///
49    /// ```
50    /// use orx_split_vec::*;
51    ///
52    /// let mut vec = SplitVec::with_linear_growth(2);
53    ///
54    /// vec.extend_from_slice(&[0, 1, 2, 3]);
55    ///
56    /// let item2 = &mut vec[2];
57    /// *item2 = 42;
58    /// assert_eq!(vec, &[0, 1, 42, 3]);
59    ///
60    /// // let x = &mut vec[4]; // panics!
61    /// ```
62    fn index_mut(&mut self, index: usize) -> &mut Self::Output {
63        let (f, i) = self
64            .get_fragment_and_inner_indices(index)
65            .expect("index is out of bounds");
66        &mut self.fragments[f][i]
67    }
68}
69
70impl<T, G> Index<(usize, usize)> for SplitVec<T, G>
71where
72    G: Growth,
73{
74    type Output = T;
75
76    /// One can treat the split vector as a jagged array
77    /// and access an item with (fragment_index, inner_fragment_index)
78    /// if these numbers are known.
79    ///
80    /// # Panics
81    ///
82    /// Panics if:
83    ///
84    /// * `fragment_and_inner_index.0` is not a valid fragment index; i.e., not within `0..self.fragments().len()`, or
85    /// * `fragment_and_inner_index.1` is not a valid index for the corresponding fragment; i.e., not within `0..self.fragments()[fragment_and_inner_index.0].len()`.
86    ///
87    /// # Examples
88    ///
89    /// Assume that we create a split vector with a constant growth of N elements.
90    /// This means that each fraction will have a capacity and max-length of N.
91    ///
92    /// Then, the fragment and inner index of the element with index `i` can be computed as
93    /// `(i / N, i % N)`.
94    ///
95    /// ```
96    /// use orx_split_vec::*;
97    ///
98    /// let mut vec = SplitVec::with_linear_growth(2);
99    ///
100    /// for i in 0..10 {
101    ///     vec.push(i);
102    /// }
103    ///
104    /// // layout of the data will be as follows:
105    /// // fragment-0: [0, 1, 2, 3]
106    /// // fragment-1: [4, 5, 6, 7]
107    /// // fragment-2: [8, 9]
108    ///
109    /// assert_eq!(1, vec[(0, 1)]);
110    /// assert_eq!(7, vec[(1, 3)]);
111    /// assert_eq!(8, vec[(2, 0)]);
112    ///
113    /// // since we know the layout, we can define the index transformer for direct access
114    /// fn fragment_and_inner_idx(index: usize) -> (usize, usize) {
115    ///     (index / 4, index % 4)
116    /// }
117    ///
118    /// for index in 0..vec.len() {
119    ///     let split_access = &vec[index];
120    ///     let direct_access = &vec[fragment_and_inner_idx(index)];
121    ///     assert_eq!(split_access, direct_access);
122    /// }
123    ///
124    /// ```
125    fn index(&self, fragment_and_inner_index: (usize, usize)) -> &Self::Output {
126        &self.fragments[fragment_and_inner_index.0][fragment_and_inner_index.1]
127    }
128}
129impl<T, G> IndexMut<(usize, usize)> for SplitVec<T, G>
130where
131    G: Growth,
132{
133    /// One can treat the split vector as a jagged array
134    /// and access an item with (fragment_index, inner_fragment_index)
135    /// if these numbers are known.
136    ///
137    /// # Panics
138    ///
139    /// Panics if:
140    ///
141    /// * `fragment_and_inner_index.0` is not a valid fragment index; i.e., not within `0..self.fragments().len()`, or
142    /// * `fragment_and_inner_index.1` is not a valid index for the corresponding fragment; i.e., not within `0..self.fragments()[fragment_and_inner_index.0].len()`.
143    ///
144    /// # Examples
145    ///
146    /// Assume that we create a split vector with a constant growth of N elements.
147    /// This means that each fraction will have a capacity and max-length of N.
148    ///
149    /// Then, the fragment and inner index of the element with index `i` can be computed as
150    /// `(i / N, i % N)`.
151    ///
152    /// ```
153    /// use orx_split_vec::*;
154    ///
155    /// let mut vec = SplitVec::with_linear_growth(2);
156    ///
157    /// for i in 0..10 {
158    ///     vec.push(i);
159    /// }
160    ///
161    /// // layout of the data will be as follows:
162    /// // fragment-0: [0, 1, 2, 3]
163    /// // fragment-1: [4, 5, 6, 7]
164    /// // fragment-2: [8, 9]
165    ///
166    /// vec[(0, 1)] += 100; // 1 -> 101
167    /// vec[(1, 3)] += 100; // 7 -> 107
168    /// vec[(2, 0)] += 100; // 8 -> 108
169    /// assert_eq!(vec, &[0, 101, 2, 3, 4, 5, 6, 107, 108, 9]);
170    ///
171    /// // since we know the layout, we can define the index transformer for direct access
172    /// fn fragment_and_inner_idx(index: usize) -> (usize, usize) {
173    ///     (index / 4, index % 4)
174    /// }
175    ///
176    /// for index in 0..vec.len() {
177    ///     let direct_access = &mut vec[fragment_and_inner_idx(index)];
178    ///     if *direct_access < 100 {
179    ///         *direct_access += 100;
180    ///     }
181    /// }
182    /// assert_eq!(vec, &[100, 101, 102, 103, 104, 105, 106, 107, 108, 109]);
183    ///
184    /// ```
185    fn index_mut(&mut self, fragment_and_inner_index: (usize, usize)) -> &mut Self::Output {
186        &mut self.fragments[fragment_and_inner_index.0][fragment_and_inner_index.1]
187    }
188}
189
190#[cfg(test)]
191mod tests {
192    use crate::test_all_growth_types;
193    use crate::*;
194    use alloc::vec::Vec;
195
196    #[test]
197    fn index() {
198        fn test<G: Growth>(mut vec: SplitVec<usize, G>) {
199            vec.extend_from_slice(&(0..21).collect::<Vec<_>>());
200            vec.extend_from_slice(&(21..33).collect::<Vec<_>>());
201            vec.extend_from_slice(&(33..50).collect::<Vec<_>>());
202
203            assert_eq!(50, vec.len());
204            for i in 0..50 {
205                assert_eq!(i, vec[i]);
206                vec[i] += 50;
207            }
208            for i in 0..50 {
209                assert_eq!(50 + i, vec[i]);
210            }
211        }
212        test_all_growth_types!(test);
213    }
214
215    #[test]
216    fn double_indices() {
217        fn test<G: Growth>(mut vec: SplitVec<usize, G>) {
218            vec.extend_from_slice(&(0..21).collect::<Vec<_>>());
219            vec.extend_from_slice(&(21..33).collect::<Vec<_>>());
220            vec.extend_from_slice(&(33..50).collect::<Vec<_>>());
221
222            assert_eq!(50, vec.len());
223            for i in 0..50 {
224                let (f, j) = vec.get_fragment_and_inner_indices(i).expect("is-some");
225                assert_eq!(i, vec[(f, j)]);
226                vec[(f, j)] += 50;
227            }
228            for i in 0..50 {
229                let (f, j) = vec.get_fragment_and_inner_indices(i).expect("is-some");
230                assert_eq!(50 + i, vec[(f, j)]);
231            }
232        }
233        test_all_growth_types!(test);
234    }
235}