orx_split_vec/growth/doubling/
doubling_growth.rs1use super::constants::*;
2use crate::growth::growth_trait::{Growth, GrowthWithConstantTimeAccess};
3use crate::{Fragment, SplitVec};
4use alloc::string::String;
5use orx_pseudo_default::PseudoDefault;
6
7#[derive(Debug, Default, Clone, PartialEq)]
55pub struct Doubling;
56
57impl PseudoDefault for Doubling {
58 fn pseudo_default() -> Self {
59 Default::default()
60 }
61}
62
63impl Growth for Doubling {
64 #[inline(always)]
65 fn new_fragment_capacity_from(
66 &self,
67 fragment_capacities: impl ExactSizeIterator<Item = usize>,
68 ) -> usize {
69 fragment_capacities.last().map(|x| x * 2).unwrap_or(4)
70 }
71
72 #[inline(always)]
73 fn get_fragment_and_inner_indices<T>(
74 &self,
75 vec_len: usize,
76 _fragments: &[Fragment<T>],
77 element_index: usize,
78 ) -> Option<(usize, usize)> {
79 match element_index < vec_len {
80 true => Some(self.get_fragment_and_inner_indices_unchecked(element_index)),
81 false => None,
82 }
83 }
84
85 #[inline(always)]
94 fn get_ptr<T>(&self, fragments: &[Fragment<T>], index: usize) -> Option<*const T> {
95 <Self as GrowthWithConstantTimeAccess>::get_ptr(self, fragments, index)
96 }
97
98 #[inline(always)]
107 fn get_ptr_mut<T>(&self, fragments: &mut [Fragment<T>], index: usize) -> Option<*mut T> {
108 <Self as GrowthWithConstantTimeAccess>::get_ptr_mut(self, fragments, index)
109 }
110
111 #[inline(always)]
122 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 CUMULATIVE_CAPACITIES[fragments_capacity]
138 }
139
140 fn required_fragments_len<T>(
148 &self,
149 _: &[Fragment<T>],
150 maximum_capacity: usize,
151 ) -> Result<usize, String> {
152 for (f, capacity) in CUMULATIVE_CAPACITIES.iter().enumerate() {
153 if maximum_capacity <= *capacity {
154 return Ok(f);
155 }
156 }
157
158 Err(alloc::format!(
159 "Maximum cumulative capacity that can be reached by the Doubling strategy is {}.",
160 CUMULATIVE_CAPACITIES[CUMULATIVE_CAPACITIES.len() - 1]
161 ))
162 }
163}
164
165impl GrowthWithConstantTimeAccess for Doubling {
166 #[inline(always)]
167 fn get_fragment_and_inner_indices_unchecked(&self, element_index: usize) -> (usize, usize) {
168 let element_index_offset = element_index + FIRST_FRAGMENT_CAPACITY;
169 let leading_zeros = usize::leading_zeros(element_index_offset) as usize;
170 let f = OFFSET_FRAGMENT_IDX - leading_zeros;
171 (f, element_index - CUMULATIVE_CAPACITIES[f])
172 }
173
174 fn fragment_capacity_of(&self, fragment_index: usize) -> usize {
175 CAPACITIES[fragment_index]
176 }
177}
178
179impl<T> SplitVec<T, Doubling> {
180 pub fn with_doubling_growth() -> Self {
231 let fragments = Fragment::new(FIRST_FRAGMENT_CAPACITY).into_fragments();
232 Self::from_raw_parts(0, fragments, Doubling)
233 }
234
235 pub fn with_doubling_growth_and_fragments_capacity(fragments_capacity: usize) -> Self {
247 assert!(fragments_capacity > 0);
248 let fragments =
249 Fragment::new(FIRST_FRAGMENT_CAPACITY).into_fragments_with_capacity(fragments_capacity);
250 Self::from_raw_parts(0, fragments, Doubling)
251 }
252}
253
254#[cfg(test)]
255mod tests {
256 use super::*;
257 use orx_pinned_vec::PinnedVec;
258
259 #[test]
260 fn get_fragment_and_inner_indices() {
261 let growth = Doubling;
262
263 let get = |index| growth.get_fragment_and_inner_indices::<char>(usize::MAX, &[], index);
264 let get_none = |index| growth.get_fragment_and_inner_indices::<char>(index, &[], index);
265
266 assert_eq!((0, 0), growth.get_fragment_and_inner_indices_unchecked(0));
267 assert_eq!((0, 1), growth.get_fragment_and_inner_indices_unchecked(1));
268 assert_eq!((1, 0), growth.get_fragment_and_inner_indices_unchecked(4));
269 assert_eq!((1, 5), growth.get_fragment_and_inner_indices_unchecked(9));
270 assert_eq!((2, 0), growth.get_fragment_and_inner_indices_unchecked(12));
271
272 assert_eq!(Some((0, 0)), get(0));
273 assert_eq!(Some((0, 1)), get(1));
274 assert_eq!(Some((1, 0)), get(4));
275 assert_eq!(Some((1, 5)), get(9));
276 assert_eq!(Some((2, 0)), get(12));
277
278 assert_eq!(None, get_none(0));
279 assert_eq!(None, get_none(1));
280 assert_eq!(None, get_none(4));
281 assert_eq!(None, get_none(9));
282 assert_eq!(None, get_none(12));
283 }
284
285 #[test]
286 fn get_fragment_and_inner_indices_exhaustive() {
287 let growth = Doubling;
288
289 let get = |index| growth.get_fragment_and_inner_indices::<char>(usize::MAX, &[], index);
290 let get_none = |index| growth.get_fragment_and_inner_indices::<char>(index, &[], index);
291
292 let mut f = 0;
293 let mut prev_cumulative_capacity = 0;
294 let mut curr_capacity = 4;
295 let mut cumulative_capacity = 4;
296
297 for index in 0..51_111 {
298 if index == cumulative_capacity {
299 prev_cumulative_capacity = cumulative_capacity;
300 curr_capacity *= 2;
301 cumulative_capacity += curr_capacity;
302 f += 1;
303 }
304
305 let (f, i) = (f, index - prev_cumulative_capacity);
306 assert_eq!(
307 (f, i),
308 growth.get_fragment_and_inner_indices_unchecked(index)
309 );
310 assert_eq!(Some((f, i)), get(index));
311 assert_eq!(None, get_none(index));
312 }
313 }
314
315 #[test]
316 fn maximum_concurrent_capacity() {
317 fn max_cap<T>(vec: &SplitVec<T, Doubling>) -> usize {
318 vec.growth()
319 .maximum_concurrent_capacity(vec.fragments(), vec.fragments.capacity())
320 }
321
322 let mut vec: SplitVec<char, Doubling> = SplitVec::with_doubling_growth();
323 assert_eq!(max_cap(&vec), 4 + 8 + 16 + 32);
324
325 let until = max_cap(&vec);
326 for _ in 0..until {
327 vec.push('x');
328 assert_eq!(max_cap(&vec), 4 + 8 + 16 + 32);
329 }
330
331 vec.push('x');
333 assert_eq!(max_cap(&vec), 4 + 8 + 16 + 32 + 64 + 128 + 256 + 512);
334 }
335
336 #[test]
337 fn with_doubling_growth_and_fragments_capacity_normal_growth() {
338 let mut vec: SplitVec<char, _> = SplitVec::with_doubling_growth_and_fragments_capacity(1);
339
340 assert_eq!(1, vec.fragments.capacity());
341
342 for _ in 0..100_000 {
343 vec.push('x');
344 }
345
346 assert!(vec.fragments.capacity() > 4);
347 }
348
349 #[test]
350 #[should_panic]
351 fn with_doubling_growth_and_fragments_capacity_zero() {
352 let _: SplitVec<char, _> = SplitVec::with_doubling_growth_and_fragments_capacity(0);
353 }
354
355 #[test]
356 fn required_fragments_len() {
357 let vec: SplitVec<char, Doubling> = SplitVec::with_doubling_growth();
358 let num_fragments = |max_cap| {
359 vec.growth()
360 .required_fragments_len(vec.fragments(), max_cap)
361 };
362
363 assert_eq!(num_fragments(0), Ok(0));
365 assert_eq!(num_fragments(1), Ok(1));
366 assert_eq!(num_fragments(4), Ok(1));
367 assert_eq!(num_fragments(5), Ok(2));
368 assert_eq!(num_fragments(12), Ok(2));
369 assert_eq!(num_fragments(13), Ok(3));
370 assert_eq!(num_fragments(36), Ok(4));
371 assert_eq!(num_fragments(67), Ok(5));
372 assert_eq!(num_fragments(136), Ok(6));
373 }
374
375 #[test]
376 fn required_fragments_len_at_max() {
377 let vec: SplitVec<char, Doubling> = SplitVec::with_doubling_growth();
378 let num_fragments = |max_cap| {
379 vec.growth()
380 .required_fragments_len(vec.fragments(), max_cap)
381 };
382
383 let maximum_possible_capacity = *CUMULATIVE_CAPACITIES.last().expect("is not empty");
384 #[cfg(target_pointer_width = "32")]
385 assert_eq!(num_fragments(maximum_possible_capacity), Ok(29));
386 #[cfg(target_pointer_width = "64")]
387 assert_eq!(num_fragments(maximum_possible_capacity), Ok(32));
388 }
389
390 #[test]
391 fn required_fragments_len_more_than_max() {
392 let vec: SplitVec<char, Doubling> = SplitVec::with_doubling_growth();
393 let num_fragments = |max_cap| {
394 vec.growth()
395 .required_fragments_len(vec.fragments(), max_cap)
396 };
397
398 let more_than_max_possible_capacity =
399 *CUMULATIVE_CAPACITIES.last().expect("is not empty") + 1;
400 assert!(num_fragments(more_than_max_possible_capacity).is_err());
401 }
402}