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 fn maximum_concurrent_capacity_bound<T>(&self, _: &[Fragment<T>], _: usize) -> usize {
165 *CUMULATIVE_CAPACITIES
166 .last()
167 .expect("cumulative capacities is not empty")
168 }
169}
170
171impl GrowthWithConstantTimeAccess for Doubling {
172 #[inline(always)]
173 fn get_fragment_and_inner_indices_unchecked(&self, element_index: usize) -> (usize, usize) {
174 let element_index_offset = element_index + FIRST_FRAGMENT_CAPACITY;
175 let leading_zeros = usize::leading_zeros(element_index_offset) as usize;
176 let f = OFFSET_FRAGMENT_IDX - leading_zeros;
177 (f, element_index - CUMULATIVE_CAPACITIES[f])
178 }
179
180 fn fragment_capacity_of(&self, fragment_index: usize) -> usize {
181 CAPACITIES[fragment_index]
182 }
183}
184
185impl<T> SplitVec<T, Doubling> {
186 pub fn with_doubling_growth() -> Self {
237 let fragments = Fragment::new(FIRST_FRAGMENT_CAPACITY).into_fragments();
238 Self::from_raw_parts(0, fragments, Doubling)
239 }
240
241 pub fn with_doubling_growth_and_fragments_capacity(fragments_capacity: usize) -> Self {
260 assert!(
261 fragments_capacity > 0 && fragments_capacity <= CAPACITIES_LEN,
262 "fragments_capacity must be within 1..{CAPACITIES_LEN}; however, {fragments_capacity} is provided."
263 );
264 assert!(fragments_capacity > 0);
265 let fragments =
266 Fragment::new(FIRST_FRAGMENT_CAPACITY).into_fragments_with_capacity(fragments_capacity);
267 Self::from_raw_parts(0, fragments, Doubling)
268 }
269
270 pub fn with_doubling_growth_and_max_concurrent_capacity() -> Self {
276 let fragments =
277 Fragment::new(FIRST_FRAGMENT_CAPACITY).into_fragments_with_capacity(CAPACITIES_LEN);
278 Self::from_raw_parts(0, fragments, Doubling)
279 }
280}
281
282#[cfg(test)]
283mod tests {
284 use super::*;
285 use orx_pinned_vec::PinnedVec;
286
287 #[test]
288 fn get_fragment_and_inner_indices() {
289 let growth = Doubling;
290
291 let get = |index| growth.get_fragment_and_inner_indices::<char>(usize::MAX, &[], index);
292 let get_none = |index| growth.get_fragment_and_inner_indices::<char>(index, &[], index);
293
294 assert_eq!((0, 0), growth.get_fragment_and_inner_indices_unchecked(0));
295 assert_eq!((0, 1), growth.get_fragment_and_inner_indices_unchecked(1));
296 assert_eq!((1, 0), growth.get_fragment_and_inner_indices_unchecked(4));
297 assert_eq!((1, 5), growth.get_fragment_and_inner_indices_unchecked(9));
298 assert_eq!((2, 0), growth.get_fragment_and_inner_indices_unchecked(12));
299
300 assert_eq!(Some((0, 0)), get(0));
301 assert_eq!(Some((0, 1)), get(1));
302 assert_eq!(Some((1, 0)), get(4));
303 assert_eq!(Some((1, 5)), get(9));
304 assert_eq!(Some((2, 0)), get(12));
305
306 assert_eq!(None, get_none(0));
307 assert_eq!(None, get_none(1));
308 assert_eq!(None, get_none(4));
309 assert_eq!(None, get_none(9));
310 assert_eq!(None, get_none(12));
311 }
312
313 #[test]
314 fn get_fragment_and_inner_indices_exhaustive() {
315 let growth = Doubling;
316
317 let get = |index| growth.get_fragment_and_inner_indices::<char>(usize::MAX, &[], index);
318 let get_none = |index| growth.get_fragment_and_inner_indices::<char>(index, &[], index);
319
320 let mut f = 0;
321 let mut prev_cumulative_capacity = 0;
322 let mut curr_capacity = 4;
323 let mut cumulative_capacity = 4;
324
325 for index in 0..51_111 {
326 if index == cumulative_capacity {
327 prev_cumulative_capacity = cumulative_capacity;
328 curr_capacity *= 2;
329 cumulative_capacity += curr_capacity;
330 f += 1;
331 }
332
333 let (f, i) = (f, index - prev_cumulative_capacity);
334 assert_eq!(
335 (f, i),
336 growth.get_fragment_and_inner_indices_unchecked(index)
337 );
338 assert_eq!(Some((f, i)), get(index));
339 assert_eq!(None, get_none(index));
340 }
341 }
342
343 #[test]
344 fn maximum_concurrent_capacity() {
345 fn max_cap<T>(vec: &SplitVec<T, Doubling>) -> usize {
346 vec.growth()
347 .maximum_concurrent_capacity(vec.fragments(), vec.fragments.capacity())
348 }
349
350 let mut vec: SplitVec<char, Doubling> = SplitVec::with_doubling_growth();
351 assert_eq!(max_cap(&vec), 4 + 8 + 16 + 32);
352
353 let until = max_cap(&vec);
354 for _ in 0..until {
355 vec.push('x');
356 assert_eq!(max_cap(&vec), 4 + 8 + 16 + 32);
357 }
358
359 vec.push('x');
361 assert_eq!(max_cap(&vec), 4 + 8 + 16 + 32 + 64 + 128 + 256 + 512);
362 }
363
364 #[test]
365 fn with_doubling_growth_and_fragments_capacity_normal_growth() {
366 let mut vec: SplitVec<char, _> = SplitVec::with_doubling_growth_and_fragments_capacity(1);
367
368 assert_eq!(1, vec.fragments.capacity());
369
370 #[cfg(not(miri))]
371 let n = 100_000;
372 #[cfg(miri)]
373 let n = 44;
374
375 for _ in 0..n {
376 vec.push('x');
377 }
378
379 #[cfg(not(miri))]
380 assert!(vec.fragments.capacity() > 4);
381 }
382
383 #[test]
384 #[should_panic]
385 fn with_doubling_growth_and_fragments_capacity_zero() {
386 let _: SplitVec<char, _> = SplitVec::with_doubling_growth_and_fragments_capacity(0);
387 }
388
389 #[test]
390 fn with_doubling_growth_and_fragments_capacity_with_max_fragments_capacity() {
391 let vec: SplitVec<char, _> =
392 SplitVec::with_doubling_growth_and_fragments_capacity(CAPACITIES_LEN);
393 assert_eq!(
394 vec.maximum_concurrent_capacity(),
395 (1 << (CAPACITIES_LEN + 2)) - FIRST_FRAGMENT_CAPACITY
396 );
397 }
398
399 #[test]
400 #[should_panic]
401 fn with_doubling_growth_and_fragments_capacity_too_large_fragments_capacity() {
402 let _: SplitVec<char, _> =
403 SplitVec::with_doubling_growth_and_fragments_capacity(CAPACITIES_LEN + 1);
404 }
405
406 #[test]
407 fn with_doubling_growth_and_max_concurrent_capacity() {
408 let vec: SplitVec<char, _> = SplitVec::with_doubling_growth_and_max_concurrent_capacity();
409 assert_eq!(
410 vec.maximum_concurrent_capacity(),
411 (1 << (CAPACITIES_LEN + 2)) - FIRST_FRAGMENT_CAPACITY
412 );
413 }
414
415 #[test]
416 fn required_fragments_len() {
417 let vec: SplitVec<char, Doubling> = SplitVec::with_doubling_growth();
418 let num_fragments = |max_cap| {
419 vec.growth()
420 .required_fragments_len(vec.fragments(), max_cap)
421 };
422
423 assert_eq!(num_fragments(0), Ok(0));
425 assert_eq!(num_fragments(1), Ok(1));
426 assert_eq!(num_fragments(4), Ok(1));
427 assert_eq!(num_fragments(5), Ok(2));
428 assert_eq!(num_fragments(12), Ok(2));
429 assert_eq!(num_fragments(13), Ok(3));
430 assert_eq!(num_fragments(36), Ok(4));
431 assert_eq!(num_fragments(67), Ok(5));
432 assert_eq!(num_fragments(136), Ok(6));
433 }
434
435 #[test]
436 fn required_fragments_len_at_max() {
437 let vec: SplitVec<char, Doubling> = SplitVec::with_doubling_growth();
438 let num_fragments = |max_cap| {
439 vec.growth()
440 .required_fragments_len(vec.fragments(), max_cap)
441 };
442
443 let maximum_possible_capacity = *CUMULATIVE_CAPACITIES.last().expect("is not empty");
444 #[cfg(target_pointer_width = "32")]
445 assert_eq!(num_fragments(maximum_possible_capacity), Ok(29));
446 #[cfg(target_pointer_width = "64")]
447 assert_eq!(num_fragments(maximum_possible_capacity), Ok(32));
448 }
449
450 #[test]
451 fn required_fragments_len_more_than_max() {
452 let vec: SplitVec<char, Doubling> = SplitVec::with_doubling_growth();
453 let num_fragments = |max_cap| {
454 vec.growth()
455 .required_fragments_len(vec.fragments(), max_cap)
456 };
457
458 let more_than_max_possible_capacity =
459 *CUMULATIVE_CAPACITIES.last().expect("is not empty") + 1;
460 assert!(num_fragments(more_than_max_possible_capacity).is_err());
461 }
462}