orx_split_vec/growth/linear/
linear_growth.rs1use crate::growth::growth_trait::{Growth, GrowthWithConstantTimeAccess};
2use crate::growth::linear::constants::FIXED_CAPACITIES;
3use crate::{Fragment, SplitVec};
4use alloc::string::String;
5use orx_pseudo_default::PseudoDefault;
6
7#[derive(Debug, Clone, PartialEq)]
42pub struct Linear {
43 constant_fragment_capacity_exponent: usize,
44 constant_fragment_capacity: usize,
45}
46
47impl Linear {
48 pub fn new(constant_fragment_capacity_exponent: usize) -> Self {
50 let constant_fragment_capacity = FIXED_CAPACITIES[constant_fragment_capacity_exponent];
51 Self {
52 constant_fragment_capacity_exponent,
53 constant_fragment_capacity,
54 }
55 }
56}
57
58impl PseudoDefault for Linear {
59 fn pseudo_default() -> Self {
60 Self::new(1)
61 }
62}
63
64impl Growth for Linear {
65 #[inline(always)]
66 fn new_fragment_capacity_from(
67 &self,
68 _fragment_capacities: impl ExactSizeIterator<Item = usize>,
69 ) -> usize {
70 self.constant_fragment_capacity
71 }
72
73 #[inline(always)]
74 fn get_fragment_and_inner_indices<T>(
75 &self,
76 vec_len: usize,
77 _fragments: &[Fragment<T>],
78 element_index: usize,
79 ) -> Option<(usize, usize)> {
80 match element_index < vec_len {
81 true => Some(self.get_fragment_and_inner_indices_unchecked(element_index)),
82 false => None,
83 }
84 }
85
86 #[inline(always)]
95 fn get_ptr<T>(&self, fragments: &[Fragment<T>], index: usize) -> Option<*const T> {
96 <Self as GrowthWithConstantTimeAccess>::get_ptr(self, fragments, index)
97 }
98
99 #[inline(always)]
108 fn get_ptr_mut<T>(&self, fragments: &mut [Fragment<T>], index: usize) -> Option<*mut T> {
109 <Self as GrowthWithConstantTimeAccess>::get_ptr_mut(self, fragments, index)
110 }
111
112 fn get_ptr_mut_and_indices<T>(
123 &self,
124 fragments: &mut [Fragment<T>],
125 index: usize,
126 ) -> Option<(*mut T, usize, usize)> {
127 <Self as GrowthWithConstantTimeAccess>::get_ptr_mut_and_indices(self, fragments, index)
128 }
129
130 fn maximum_concurrent_capacity<T>(
131 &self,
132 fragments: &[Fragment<T>],
133 fragments_capacity: usize,
134 ) -> usize {
135 assert!(fragments_capacity >= fragments.len());
136
137 fragments_capacity * self.constant_fragment_capacity
138 }
139
140 fn required_fragments_len<T>(
141 &self,
142 _: &[Fragment<T>],
143 maximum_capacity: usize,
144 ) -> Result<usize, String> {
145 let num_full_fragments = maximum_capacity / self.constant_fragment_capacity;
146 let remainder = maximum_capacity % self.constant_fragment_capacity;
147 let additional_fragment = if remainder > 0 { 1 } else { 0 };
148
149 Ok(num_full_fragments + additional_fragment)
150 }
151}
152
153impl GrowthWithConstantTimeAccess for Linear {
154 #[inline(always)]
155 fn get_fragment_and_inner_indices_unchecked(&self, element_index: usize) -> (usize, usize) {
156 let f = element_index >> self.constant_fragment_capacity_exponent;
157 let i = element_index % self.constant_fragment_capacity;
158 (f, i)
159 }
160
161 fn fragment_capacity_of(&self, _: usize) -> usize {
162 self.constant_fragment_capacity
163 }
164}
165
166impl<T> SplitVec<T, Linear> {
167 pub fn with_linear_growth(constant_fragment_capacity_exponent: usize) -> Self {
208 assert!(constant_fragment_capacity_exponent > 0 && constant_fragment_capacity_exponent < FIXED_CAPACITIES.len(),
209 "constant_fragment_capacity_exponent must be within 1..32 (1..29) for 64-bit (32-bit) platforms.");
210
211 let constant_fragment_capacity = FIXED_CAPACITIES[constant_fragment_capacity_exponent];
212 let fragments = Fragment::new(constant_fragment_capacity).into_fragments();
213 let growth = Linear::new(constant_fragment_capacity_exponent);
214 Self::from_raw_parts(0, fragments, growth)
215 }
216
217 pub fn with_linear_growth_and_fragments_capacity(
229 constant_fragment_capacity_exponent: usize,
230 fragments_capacity: usize,
231 ) -> Self {
232 assert!(constant_fragment_capacity_exponent > 0);
233 assert!(fragments_capacity > 0);
234
235 let constant_fragment_capacity = FIXED_CAPACITIES[constant_fragment_capacity_exponent];
236 let fragments = Fragment::new(constant_fragment_capacity)
237 .into_fragments_with_capacity(fragments_capacity);
238 let growth = Linear::new(constant_fragment_capacity_exponent);
239 Self::from_raw_parts(0, fragments, growth)
240 }
241}
242
243#[cfg(test)]
244mod tests {
245 use super::*;
246 use orx_pinned_vec::PinnedVec;
247
248 #[test]
249 fn get_fragment_and_inner_indices() {
250 let growth = Linear::new(2);
251
252 let get = |index| growth.get_fragment_and_inner_indices::<char>(usize::MAX, &[], index);
253 let get_none = |index| growth.get_fragment_and_inner_indices::<char>(index, &[], index);
254
255 assert_eq!((0, 0), growth.get_fragment_and_inner_indices_unchecked(0));
256 assert_eq!((0, 1), growth.get_fragment_and_inner_indices_unchecked(1));
257 assert_eq!((1, 0), growth.get_fragment_and_inner_indices_unchecked(4));
258 assert_eq!((2, 1), growth.get_fragment_and_inner_indices_unchecked(9));
259 assert_eq!((4, 0), growth.get_fragment_and_inner_indices_unchecked(16));
260
261 assert_eq!(Some((0, 0)), get(0));
262 assert_eq!(Some((0, 1)), get(1));
263 assert_eq!(Some((1, 0)), get(4));
264 assert_eq!(Some((2, 1)), get(9));
265 assert_eq!(Some((4, 0)), get(16));
266
267 assert_eq!(None, get_none(0));
268 assert_eq!(None, get_none(1));
269 assert_eq!(None, get_none(4));
270 assert_eq!(None, get_none(9));
271 assert_eq!(None, get_none(16));
272 }
273
274 #[test]
275 fn get_fragment_and_inner_indices_exhaustive() {
276 let growth = Linear::new(5);
277
278 let get = |index| growth.get_fragment_and_inner_indices::<char>(usize::MAX, &[], index);
279 let get_none = |index| growth.get_fragment_and_inner_indices::<char>(index, &[], index);
280
281 let curr_capacity = 32;
282
283 let mut f = 0;
284 let mut prev_cumulative_capacity = 0;
285 let mut cumulative_capacity = curr_capacity;
286
287 for index in 0..51_111 {
288 if index == cumulative_capacity {
289 prev_cumulative_capacity = cumulative_capacity;
290 cumulative_capacity += curr_capacity;
291 f += 1;
292 }
293
294 let (f, i) = (f, index - prev_cumulative_capacity);
295 assert_eq!(
296 (f, i),
297 growth.get_fragment_and_inner_indices_unchecked(index)
298 );
299 assert_eq!(Some((f, i)), get(index));
300 assert_eq!(None, get_none(index));
301 }
302 }
303
304 #[test]
305 fn maximum_concurrent_capacity() {
306 fn max_cap<T>(vec: &SplitVec<T, Linear>) -> usize {
307 vec.growth()
308 .maximum_concurrent_capacity(vec.fragments(), vec.fragments.capacity())
309 }
310
311 let mut vec: SplitVec<char, Linear> = SplitVec::with_linear_growth(5);
312 assert_eq!(max_cap(&vec), 4 * 2usize.pow(5));
313
314 let until = max_cap(&vec);
315 for _ in 0..until {
316 vec.push('x');
317 assert_eq!(max_cap(&vec), 4 * 2usize.pow(5));
318 }
319
320 vec.push('x');
322 assert_eq!(max_cap(&vec), 8 * 2usize.pow(5));
323 }
324
325 #[test]
326 fn with_linear_growth_and_fragments_capacity_normal_growth() {
327 let mut vec: SplitVec<char, _> = SplitVec::with_linear_growth_and_fragments_capacity(10, 1);
328
329 assert_eq!(1, vec.fragments.capacity());
330
331 for _ in 0..100_000 {
332 vec.push('x');
333 }
334
335 assert!(vec.fragments.capacity() > 4);
336 }
337
338 #[test]
339 #[should_panic]
340 fn with_linear_growth_and_fragments_capacity_zero() {
341 let _: SplitVec<char, _> = SplitVec::with_linear_growth_and_fragments_capacity(10, 0);
342 }
343
344 #[test]
345 fn required_fragments_len() {
346 let vec: SplitVec<char, Linear> = SplitVec::with_linear_growth(5);
347 let num_fragments = |max_cap| {
348 vec.growth()
349 .required_fragments_len(vec.fragments(), max_cap)
350 };
351
352 assert_eq!(num_fragments(0), Ok(0));
353 assert_eq!(num_fragments(1), Ok(1));
354 assert_eq!(num_fragments(2), Ok(1));
355 assert_eq!(num_fragments(32), Ok(1));
356 assert_eq!(num_fragments(33), Ok(2));
357 assert_eq!(num_fragments(32 * 7), Ok(7));
358 assert_eq!(num_fragments(32 * 7 + 1), Ok(8));
359 }
360}