segment_array/
lib.rs

1//
2// Copyright (c) 2025 Nathan Fiedler
3//
4
5//! An append-only (no insert or remove) growable array as described in the
6//! [blog post](https://danielchasehooper.com/posts/segment_array/) by Daniel
7//! Hooper.
8//!
9//! From the blog post:
10//!
11//! > A data structure with constant time indexing, stable pointers, and works
12//! > well with arena allocators. ... The idea is straight forward: the
13//! > structure contains a fixed sized array of pointers to segments. Each
14//! > segment is twice the size of its predecessor. New segments are allocated
15//! > as needed. ... Unlike standard arrays, pointers to a segment array’s items
16//! > are always valid because items are never moved. Leaving items in place
17//! > also means it never leaves "holes" of abandoned memory in arena
18//! > allocators. The layout also allows us to access any index in constant
19//! > time.
20//!
21//! The behavior, memory layout, and performance of this implementation should
22//! be identical to that of the C implementation. To summarize:
23//!
24//! * Fixed number of segments (26)
25//! * First segment has a capacity of 64
26//! * Each segment is double the size of its predecessor
27//! * Total capacity of 4,294,967,232 items
28//!
29//! This data structure is meant to hold an unknown, though likely large, number
30//! of elements, otherwise `Vec` would be more appropriate. An empty array will
31//! have a hefty size of around 224 bytes.
32//!
33//! # Safety
34//!
35//! Because this data structure is allocating memory, copying bytes using
36//! pointers, and de-allocating memory as needed, there are many `unsafe` blocks
37//! throughout the code.
38
39use std::alloc::{Layout, alloc, dealloc, handle_alloc_error};
40use std::fmt;
41use std::iter::{FromIterator, Iterator};
42use std::ops::{Index, IndexMut};
43
44//
45// An individual segment can never be larger than 9,223,372,036,854,775,807
46// bytes due to the mechanics of the Rust memory allocator.
47//
48// 26 segments with 6 skipped segments with each segment doubling in size
49// results in the last segment having 2,147,483,648 items
50//
51// 9,223,372,036,854,775,807 bytes divided by 2,147,483,648 items yields a
52// maximum item size of 4,294,967,296 bytes
53//
54const MAX_SEGMENT_COUNT: usize = 26;
55
56// Segments of size 1, 2, 4, 8, 16, and 32 are not used at all (that is, the
57// smallest (first) segment is 64 elements in size) to avoid the overhead of
58// such tiny arrays.
59const SMALL_SEGMENTS_TO_SKIP: usize = 6;
60const SMALL_SEGMENTS_CAPACITY: usize = 1 << SMALL_SEGMENTS_TO_SKIP;
61
62// Calculates the number of elements that will fit into the given segment.
63#[inline]
64fn slots_in_segment(segment: usize) -> usize {
65    SMALL_SEGMENTS_CAPACITY << segment
66}
67
68// Calculates the overall capacity for all segments up to the given segment.
69#[inline]
70fn capacity_for_segment_count(segment: usize) -> usize {
71    (SMALL_SEGMENTS_CAPACITY << segment) - SMALL_SEGMENTS_CAPACITY
72}
73
74///
75/// Append-only growable array that uses a list of progressivly larger segments
76/// to avoid the allocate-and-copy that many growable data structures typically
77/// employ.
78///
79pub struct SegmentArray<T> {
80    // number of elements stored in the array
81    count: usize,
82    // number of allocated segments
83    used_segments: usize,
84    // pointers to allocated segments (0 to used_segments-1)
85    segments: [*mut T; MAX_SEGMENT_COUNT],
86}
87
88impl<T> SegmentArray<T> {
89    /// Return an empty segment array with zero capacity.
90    ///
91    /// Note that pre-allocating capacity has no benefit with this data
92    /// structure since append operations are always constant time and
93    /// no reallocation and copy is ever performed.
94    pub fn new() -> Self {
95        Self {
96            count: 0,
97            used_segments: 0,
98            segments: [std::ptr::null_mut::<T>(); MAX_SEGMENT_COUNT],
99        }
100    }
101
102    /// Appends an element to the back of a collection.
103    ///
104    /// # Panics
105    ///
106    /// Panics if a new segment is allocated that would exceed `isize::MAX` _bytes_.
107    ///
108    /// # Time complexity
109    ///
110    /// Constant time.
111    pub fn push(&mut self, value: T) {
112        if self.count >= capacity_for_segment_count(self.used_segments) {
113            assert!(
114                self.used_segments < MAX_SEGMENT_COUNT,
115                "maximum number of segments exceeded"
116            );
117            let segment_len = slots_in_segment(self.used_segments);
118            // overflowing the allocator is very unlikely as the item size would
119            // have to be very large
120            let layout = Layout::array::<T>(segment_len).expect("unexpected overflow");
121            unsafe {
122                let ptr = alloc(layout).cast::<T>();
123                if ptr.is_null() {
124                    handle_alloc_error(layout);
125                }
126                self.segments[self.used_segments] = ptr;
127            }
128            self.used_segments += 1;
129        }
130
131        let segment = ((self.count >> SMALL_SEGMENTS_TO_SKIP) + 1).ilog2() as usize;
132        let slot = self.count - capacity_for_segment_count(segment);
133        unsafe {
134            std::ptr::write(self.segments[segment].add(slot), value);
135        }
136        self.count += 1;
137    }
138
139    /// Appends an element if there is sufficient spare capacity, otherwise an
140    /// error is returned with the element.
141    ///
142    /// # Time complexity
143    ///
144    /// Constant time.
145    pub fn push_within_capacity(&mut self, value: T) -> Result<(), T> {
146        if self.count >= capacity_for_segment_count(self.used_segments) {
147            Err(value)
148        } else {
149            self.push(value);
150            Ok(())
151        }
152    }
153
154    /// Removes the last element from a vector and returns it, or `None` if it
155    /// is empty.
156    ///
157    /// # Time complexity
158    ///
159    /// Constant time.
160    pub fn pop(&mut self) -> Option<T> {
161        if self.count > 0 {
162            self.count -= 1;
163            let segment = ((self.count >> SMALL_SEGMENTS_TO_SKIP) + 1).ilog2() as usize;
164            let slot = self.count - capacity_for_segment_count(segment);
165            unsafe { Some((self.segments[segment].add(slot)).read()) }
166        } else {
167            None
168        }
169    }
170
171    /// Removes and returns the last element from a vector if the predicate
172    /// returns true, or None if the predicate returns false or the vector is
173    /// empty (the predicate will not be called in that case).
174    ///
175    /// # Time complexity
176    ///
177    /// Constant time.
178    pub fn pop_if(&mut self, predicate: impl FnOnce(&mut T) -> bool) -> Option<T> {
179        if self.count == 0 {
180            None
181        } else if let Some(last) = self.get_mut(self.count - 1) {
182            if predicate(last) { self.pop() } else { None }
183        } else {
184            None
185        }
186    }
187
188    /// Return the number of elements in the array.
189    ///
190    /// # Time complexity
191    ///
192    /// Constant time.
193    pub fn len(&self) -> usize {
194        self.count
195    }
196
197    /// Returns the total number of elements the segment array can hold
198    /// without reallocating.
199    ///
200    /// # Time complexity
201    ///
202    /// Constant time.
203    pub fn capacity(&self) -> usize {
204        capacity_for_segment_count(self.used_segments)
205    }
206
207    /// Returns true if the array has a length of 0.
208    ///
209    /// # Time complexity
210    ///
211    /// Constant time.
212    pub fn is_empty(&self) -> bool {
213        self.count == 0
214    }
215
216    /// Retrieve a reference to the element at the given offset.
217    ///
218    /// # Time complexity
219    ///
220    /// Constant time.
221    pub fn get(&self, index: usize) -> Option<&T> {
222        if index >= self.count {
223            None
224        } else {
225            let segment = ((index >> SMALL_SEGMENTS_TO_SKIP) + 1).ilog2() as usize;
226            let slot = index - capacity_for_segment_count(segment);
227            unsafe { (self.segments[segment].add(slot)).as_ref() }
228        }
229    }
230
231    /// Returns a mutable reference to an element.
232    ///
233    /// # Time complexity
234    ///
235    /// Constant time.
236    pub fn get_mut(&mut self, index: usize) -> Option<&mut T> {
237        if index >= self.count {
238            None
239        } else {
240            let segment = ((index >> SMALL_SEGMENTS_TO_SKIP) + 1).ilog2() as usize;
241            let slot = index - capacity_for_segment_count(segment);
242            unsafe { (self.segments[segment].add(slot)).as_mut() }
243        }
244    }
245
246    /// Removes an element from the vector and returns it.
247    ///
248    /// The removed element is replaced by the last element of the vector.
249    ///
250    /// This does not preserve ordering of the remaining elements.
251    ///
252    /// # Time complexity
253    ///
254    /// Constant time.
255    pub fn swap_remove(&mut self, index: usize) -> T {
256        if index >= self.count {
257            panic!(
258                "swap_remove index (is {index}) should be < len (is {})",
259                self.count
260            );
261        }
262        // retreive the value at index before overwriting
263        let segment = ((index >> SMALL_SEGMENTS_TO_SKIP) + 1).ilog2() as usize;
264        let slot = index - capacity_for_segment_count(segment);
265        unsafe {
266            let index_ptr = self.segments[segment].add(slot);
267            let value = index_ptr.read();
268            // find the pointer of the last element and copy to index pointer
269            self.count -= 1;
270            let segment = ((self.count >> SMALL_SEGMENTS_TO_SKIP) + 1).ilog2() as usize;
271            let slot = self.count - capacity_for_segment_count(segment);
272            let last_ptr = self.segments[segment].add(slot);
273            std::ptr::copy(last_ptr, index_ptr, 1);
274            value
275        }
276    }
277
278    /// Returns an iterator over the segment array.
279    ///
280    /// The iterator yields all items from start to end.
281    pub fn iter(&self) -> SegArrayIter<'_, T> {
282        SegArrayIter {
283            array: self,
284            index: 0,
285        }
286    }
287
288    /// Clears the segment array, removing and dropping all values.
289    ///
290    /// Note that this method has no effect on the allocated capacity of the
291    /// segment array.
292    pub fn clear(&mut self) {
293        if self.count > 0 {
294            if std::mem::needs_drop::<T>() {
295                // find the last segment that contains values
296                let last_segment = ((self.count >> SMALL_SEGMENTS_TO_SKIP) + 1).ilog2() as usize;
297                let last_slot = self.count - capacity_for_segment_count(last_segment);
298                unsafe {
299                    std::ptr::drop_in_place(std::ptr::slice_from_raw_parts_mut(
300                        self.segments[last_segment],
301                        last_slot,
302                    ));
303                }
304                // now drop the values in all of the preceding segments
305                for segment in 0..last_segment {
306                    let segment_len = slots_in_segment(segment);
307                    unsafe {
308                        std::ptr::drop_in_place(std::ptr::slice_from_raw_parts_mut(
309                            self.segments[segment],
310                            segment_len,
311                        ));
312                    }
313                }
314            }
315            self.count = 0;
316        }
317    }
318}
319
320impl<T> Default for SegmentArray<T> {
321    fn default() -> Self {
322        Self::new()
323    }
324}
325
326impl<T> fmt::Display for SegmentArray<T> {
327    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
328        let longest_segment = if self.used_segments > 0 {
329            slots_in_segment(self.used_segments - 1)
330        } else {
331            0
332        };
333        write!(
334            f,
335            "SegmentArray(count: {}, used_segments: {}, longest segment: {})",
336            self.count, self.used_segments, longest_segment
337        )
338    }
339}
340
341impl<T> Drop for SegmentArray<T> {
342    fn drop(&mut self) {
343        // perform the drop_in_place() for all of the values
344        self.clear();
345        // deallocate the segments themselves and clear everything
346        for segment in 0..self.used_segments {
347            if !self.segments[segment].is_null() {
348                let segment_len = slots_in_segment(segment);
349                let layout = Layout::array::<T>(segment_len).expect("unexpected overflow");
350                unsafe {
351                    dealloc(self.segments[segment] as *mut u8, layout);
352                }
353                self.segments[segment] = std::ptr::null_mut();
354            }
355        }
356        self.used_segments = 0;
357    }
358}
359
360impl<T> Index<usize> for SegmentArray<T> {
361    type Output = T;
362
363    fn index(&self, index: usize) -> &Self::Output {
364        let Some(item) = self.get(index) else {
365            panic!("index out of bounds: {}", index);
366        };
367        item
368    }
369}
370
371impl<T> IndexMut<usize> for SegmentArray<T> {
372    fn index_mut(&mut self, index: usize) -> &mut Self::Output {
373        let Some(item) = self.get_mut(index) else {
374            panic!("index out of bounds: {}", index);
375        };
376        item
377    }
378}
379
380impl<A> FromIterator<A> for SegmentArray<A> {
381    fn from_iter<T: IntoIterator<Item = A>>(iter: T) -> Self {
382        let mut arr: SegmentArray<A> = SegmentArray::new();
383        for value in iter {
384            arr.push(value)
385        }
386        arr
387    }
388}
389
390/// Immutable segment array iterator.
391pub struct SegArrayIter<'a, T> {
392    array: &'a SegmentArray<T>,
393    index: usize,
394}
395
396impl<'a, T> Iterator for SegArrayIter<'a, T> {
397    type Item = &'a T;
398
399    fn next(&mut self) -> Option<Self::Item> {
400        let value = self.array.get(self.index);
401        self.index += 1;
402        value
403    }
404}
405
406/// An iterator that moves out of a segment array.
407pub struct SegArrayIntoIter<T> {
408    index: usize,
409    count: usize,
410    used_segments: usize,
411    segments: [*mut T; MAX_SEGMENT_COUNT],
412}
413
414impl<T> Iterator for SegArrayIntoIter<T> {
415    type Item = T;
416
417    fn next(&mut self) -> Option<Self::Item> {
418        if self.index < self.count {
419            let segment = ((self.index >> SMALL_SEGMENTS_TO_SKIP) + 1).ilog2() as usize;
420            let slot = self.index - capacity_for_segment_count(segment);
421            self.index += 1;
422            unsafe { Some((self.segments[segment].add(slot)).read()) }
423        } else {
424            None
425        }
426    }
427}
428
429impl<T> Drop for SegArrayIntoIter<T> {
430    fn drop(&mut self) {
431        if std::mem::needs_drop::<T>() {
432            let first_segment = ((self.index >> SMALL_SEGMENTS_TO_SKIP) + 1).ilog2() as usize;
433            let last_segment = (((self.count - 1) >> SMALL_SEGMENTS_TO_SKIP) + 1).ilog2() as usize;
434            if first_segment == last_segment {
435                // special-case, remaining values are in only one segment
436                let first = self.index - capacity_for_segment_count(first_segment);
437                let last = self.count - capacity_for_segment_count(first_segment);
438                if first < last {
439                    let len = last - first;
440                    unsafe {
441                        let first: *mut T = self.segments[first_segment].add(first);
442                        std::ptr::drop_in_place(std::ptr::slice_from_raw_parts_mut(first, len));
443                    }
444                }
445            } else {
446                // drop values in the first segment that still has values to be
447                // visited
448                let first = self.index - capacity_for_segment_count(first_segment);
449                let segment_len = slots_in_segment(first_segment);
450                if segment_len < self.count {
451                    unsafe {
452                        let ptr: *mut T = self.segments[first_segment].add(first);
453                        let len = segment_len - first;
454                        std::ptr::drop_in_place(std::ptr::slice_from_raw_parts_mut(ptr, len));
455                    }
456                }
457
458                // drop the values in the last segment
459                let last_slot = self.count - capacity_for_segment_count(last_segment);
460                unsafe {
461                    std::ptr::drop_in_place(std::ptr::slice_from_raw_parts_mut(
462                        self.segments[last_segment],
463                        last_slot,
464                    ));
465                }
466
467                // now drop the values in all of the other segments
468                for segment in first_segment + 1..last_segment {
469                    let segment_len = slots_in_segment(segment);
470                    unsafe {
471                        std::ptr::drop_in_place(std::ptr::slice_from_raw_parts_mut(
472                            self.segments[segment],
473                            segment_len,
474                        ));
475                    }
476                }
477            }
478        }
479
480        // deallocate the segments themselves and clear everything
481        for segment in 0..self.used_segments {
482            if !self.segments[segment].is_null() {
483                let segment_len = slots_in_segment(segment);
484                let layout = Layout::array::<T>(segment_len).expect("unexpected overflow");
485                unsafe {
486                    dealloc(self.segments[segment] as *mut u8, layout);
487                }
488                self.segments[segment] = std::ptr::null_mut();
489            }
490        }
491        self.index = 0;
492        self.count = 0;
493        self.used_segments = 0;
494    }
495}
496
497impl<T> IntoIterator for SegmentArray<T> {
498    type Item = T;
499    type IntoIter = SegArrayIntoIter<Self::Item>;
500
501    fn into_iter(self) -> Self::IntoIter {
502        let me = std::mem::ManuallyDrop::new(self);
503        SegArrayIntoIter {
504            index: 0,
505            count: me.count,
506            used_segments: me.used_segments,
507            segments: me.segments,
508        }
509    }
510}
511
512#[cfg(test)]
513mod tests {
514    use super::*;
515
516    #[test]
517    fn test_slots_in_segment() {
518        // values are simply capacity_for_segment_count() plus 64 but there
519        // should be a test for this function regardless of its simplicity
520        let expected_values = [
521            64, 128, 256, 512, 1024, 2048, 4096, 8192, 16384, 32768, 65536, 131072, 262144, 524288,
522            1048576, 2097152, 4194304, 8388608, 16777216, 33554432, 67108864, 134217728, 268435456,
523            536870912, 1073741824, 2147483648,
524        ];
525        assert_eq!(expected_values.len(), MAX_SEGMENT_COUNT);
526        for (segment, item) in expected_values.iter().enumerate() {
527            assert_eq!(*item, slots_in_segment(segment));
528        }
529    }
530
531    #[test]
532    fn test_capacity_for_segment_count() {
533        //
534        // from https://danielchasehooper.com/posts/segment_array/segment_array.h:
535        //
536        // 26 segments with 6 skipped segments can hold 4,294,967,232 items, aka
537        // capacity_for_segment_count(26)
538        //
539        let expected_values = [
540            0, 64, 192, 448, 960, 1984, 4032, 8128, 16320, 32704, 65472, 131008, 262080, 524224,
541            1048512, 2097088, 4194240, 8388544, 16777152, 33554368, 67108800, 134217664, 268435392,
542            536870848, 1073741760, 2147483584, 4294967232,
543        ];
544        assert_eq!(expected_values.len(), MAX_SEGMENT_COUNT + 1);
545        for (count, item) in expected_values.iter().enumerate() {
546            assert_eq!(*item, capacity_for_segment_count(count));
547        }
548    }
549
550    #[test]
551    fn test_push_within_capacity() {
552        // empty array has no allocated space
553        let mut sut: SegmentArray<u32> = SegmentArray::new();
554        assert_eq!(sut.push_within_capacity(101), Err(101));
555        sut.push(10);
556        assert_eq!(sut.push_within_capacity(101), Ok(()));
557
558        // edge case (first segment is 64 elements long)
559        let mut sut: SegmentArray<u32> = SegmentArray::new();
560        for value in 1..64 {
561            sut.push(value);
562        }
563        assert_eq!(sut.push_within_capacity(64), Ok(()));
564        assert_eq!(sut.push_within_capacity(65), Err(65));
565    }
566
567    #[test]
568    fn test_push_get_one_item() {
569        let item = String::from("hello world");
570        let mut sut: SegmentArray<String> = SegmentArray::new();
571        assert_eq!(sut.len(), 0);
572        assert!(sut.is_empty());
573        sut.push(item);
574        assert_eq!(sut.len(), 1);
575        assert!(!sut.is_empty());
576        let maybe = sut.get(0);
577        assert!(maybe.is_some());
578        let actual = maybe.unwrap();
579        assert_eq!("hello world", actual);
580        let missing = sut.get(10);
581        assert!(missing.is_none());
582    }
583
584    #[test]
585    fn test_push_get_several_strings() {
586        let inputs = [
587            "one", "two", "three", "four", "five", "six", "seven", "eight", "nine",
588        ];
589        let mut sut: SegmentArray<String> = SegmentArray::new();
590        for item in inputs {
591            sut.push(item.to_owned());
592        }
593        assert_eq!(sut.len(), 9);
594        for (idx, item) in inputs.iter().enumerate() {
595            let maybe = sut.get(idx);
596            assert!(maybe.is_some(), "{idx} is none");
597            let actual = maybe.unwrap();
598            assert_eq!(item, actual);
599        }
600        let maybe = sut.get(10);
601        assert!(maybe.is_none());
602        assert_eq!(sut[3], "four");
603    }
604
605    #[test]
606    fn test_get_mut_index_mut() {
607        let mut sut: SegmentArray<String> = SegmentArray::new();
608        sut.push(String::from("first"));
609        sut.push(String::from("second"));
610        sut.push(String::from("third"));
611        if let Some(value) = sut.get_mut(1) {
612            value.push_str(" place");
613        } else {
614            panic!("get_mut() returned None")
615        }
616        assert_eq!(sut[1], "second place");
617        sut[2] = "third planet".into();
618        assert_eq!(sut[2], "third planet");
619    }
620
621    #[test]
622    #[should_panic(expected = "index out of bounds:")]
623    fn test_index_out_of_bounds() {
624        let mut sut: SegmentArray<i32> = SegmentArray::new();
625        sut.push(10);
626        sut.push(20);
627        let _ = sut[2];
628    }
629
630    #[test]
631    #[should_panic(expected = "index out of bounds:")]
632    fn test_index_mut_out_of_bounds() {
633        let mut sut: SegmentArray<i32> = SegmentArray::new();
634        sut.push(10);
635        sut.push(20);
636        sut[2] = 30;
637    }
638
639    #[test]
640    fn test_push_and_pop() {
641        let inputs = [
642            "one", "two", "three", "four", "five", "six", "seven", "eight", "nine",
643        ];
644        let mut sut: SegmentArray<String> = SegmentArray::new();
645        assert!(sut.pop().is_none());
646        for item in inputs {
647            sut.push(item.to_owned());
648        }
649        assert_eq!(sut.len(), 9);
650        for (idx, elem) in sut.iter().enumerate() {
651            assert_eq!(inputs[idx], elem);
652        }
653        let maybe = sut.pop();
654        assert!(maybe.is_some());
655        let value = maybe.unwrap();
656        assert_eq!(value, "nine");
657        assert_eq!(sut.len(), 8);
658        sut.push(String::from("nine"));
659        assert_eq!(sut.len(), 9);
660        for (idx, elem) in sut.iter().enumerate() {
661            assert_eq!(inputs[idx], elem);
662        }
663
664        // pop everything and add back again
665        while !sut.is_empty() {
666            sut.pop();
667        }
668        assert_eq!(sut.len(), 0);
669        for item in inputs {
670            sut.push(item.to_owned());
671        }
672        assert_eq!(sut.len(), 9);
673        for (idx, elem) in sut.iter().enumerate() {
674            assert_eq!(inputs[idx], elem);
675        }
676    }
677
678    #[test]
679    fn test_pop_if() {
680        let mut sut: SegmentArray<u32> = SegmentArray::new();
681        assert!(sut.pop_if(|_| panic!("should not be called")).is_none());
682        for value in 0..10 {
683            sut.push(value);
684        }
685        assert!(sut.pop_if(|_| false).is_none());
686        let maybe = sut.pop_if(|v| *v == 9);
687        assert_eq!(maybe.unwrap(), 9);
688        assert!(sut.pop_if(|v| *v == 9).is_none());
689    }
690
691    #[test]
692    fn test_swap_remove_single_segment() {
693        let mut sut: SegmentArray<u32> = SegmentArray::new();
694        for value in 0..10 {
695            sut.push(value);
696        }
697        assert_eq!(sut.len(), 10);
698        let five = sut.swap_remove(5);
699        assert_eq!(five, 5);
700        assert_eq!(sut.pop(), Some(8));
701        assert_eq!(sut[5], 9);
702    }
703
704    #[test]
705    fn test_swap_remove_multiple_segments() {
706        let mut sut: SegmentArray<u32> = SegmentArray::new();
707        for value in 0..512 {
708            sut.push(value);
709        }
710        assert_eq!(sut.len(), 512);
711        let eighty = sut.swap_remove(80);
712        assert_eq!(eighty, 80);
713        assert_eq!(sut.pop(), Some(510));
714        assert_eq!(sut[80], 511);
715    }
716
717    #[test]
718    #[should_panic(expected = "swap_remove index (is 0) should be < len (is 0)")]
719    fn test_swap_remove_panic_empty() {
720        let mut sut: SegmentArray<u32> = SegmentArray::new();
721        sut.swap_remove(0);
722    }
723
724    #[test]
725    #[should_panic(expected = "swap_remove index (is 1) should be < len (is 1)")]
726    fn test_swap_remove_panic_range_edge() {
727        let mut sut: SegmentArray<u32> = SegmentArray::new();
728        sut.push(1);
729        sut.swap_remove(1);
730    }
731
732    #[test]
733    #[should_panic(expected = "swap_remove index (is 2) should be < len (is 1)")]
734    fn test_swap_remove_panic_range_exceed() {
735        let mut sut: SegmentArray<u32> = SegmentArray::new();
736        sut.push(1);
737        sut.swap_remove(2);
738    }
739
740    #[test]
741    fn test_push_get_thousands_structs() {
742        struct MyData {
743            a: u64,
744            b: i32,
745        }
746        let mut sut: SegmentArray<MyData> = SegmentArray::new();
747        for value in 0..88_888i32 {
748            sut.push(MyData {
749                a: value as u64,
750                b: value,
751            });
752        }
753        assert_eq!(sut.len(), 88_888);
754        for idx in 0..88_888i32 {
755            let maybe = sut.get(idx as usize);
756            assert!(maybe.is_some(), "{idx} is none");
757            let actual = maybe.unwrap();
758            assert_eq!(idx as u64, actual.a);
759            assert_eq!(idx, actual.b);
760        }
761    }
762
763    #[test]
764    fn test_push_get_hundred_ints() {
765        let mut sut: SegmentArray<i32> = SegmentArray::new();
766        for value in 0..100 {
767            sut.push(value);
768        }
769        assert_eq!(sut.len(), 100);
770        for idx in 0..100 {
771            let maybe = sut.get(idx);
772            assert!(maybe.is_some(), "{idx} is none");
773            let actual = maybe.unwrap();
774            assert_eq!(idx, *actual as usize);
775        }
776        assert_eq!(sut[99], 99);
777    }
778
779    #[test]
780    fn test_len_and_capacity() {
781        let mut sut: SegmentArray<i32> = SegmentArray::new();
782        assert_eq!(sut.len(), 0);
783        assert_eq!(sut.capacity(), 0);
784        for value in 0..100 {
785            sut.push(value);
786        }
787        assert_eq!(sut.len(), 100);
788        assert_eq!(sut.capacity(), 192);
789    }
790
791    #[test]
792    fn test_clear_and_reuse_tiny() {
793        // clear an array that allocated only one segment
794        let inputs = [
795            "one", "two", "three", "four", "five", "six", "seven", "eight", "nine",
796        ];
797        let mut sut: SegmentArray<String> = SegmentArray::new();
798        for item in inputs {
799            sut.push(item.to_owned());
800        }
801        assert_eq!(sut.len(), 9);
802        sut.clear();
803        assert_eq!(sut.len(), 0);
804        for item in inputs {
805            sut.push(item.to_owned());
806        }
807        assert_eq!(sut.len(), 9);
808        // implicitly drop()
809    }
810
811    #[test]
812    fn test_clear_and_reuse_ints() {
813        let mut sut: SegmentArray<i32> = SegmentArray::new();
814        for value in 0..512 {
815            sut.push(value);
816        }
817        assert_eq!(sut.len(), 512);
818        sut.clear();
819        assert_eq!(sut.len(), 0);
820        for value in 0..512 {
821            sut.push(value);
822        }
823        for idx in 0..512 {
824            let maybe = sut.get(idx);
825            assert!(maybe.is_some(), "{idx} is none");
826            let actual = maybe.unwrap();
827            assert_eq!(idx, *actual as usize);
828        }
829    }
830
831    #[test]
832    fn test_clear_and_reuse_strings() {
833        let mut sut: SegmentArray<String> = SegmentArray::new();
834        for _ in 0..512 {
835            let value = ulid::Ulid::new().to_string();
836            sut.push(value);
837        }
838        assert_eq!(sut.len(), 512);
839        sut.clear();
840        assert_eq!(sut.len(), 0);
841        for _ in 0..512 {
842            let value = ulid::Ulid::new().to_string();
843            sut.push(value);
844        }
845        assert_eq!(sut.len(), 512);
846        // implicitly drop()
847    }
848
849    #[test]
850    fn test_push_get_many_ints() {
851        let mut sut: SegmentArray<i32> = SegmentArray::new();
852        for value in 0..1_000_000 {
853            sut.push(value);
854        }
855        assert_eq!(sut.len(), 1_000_000);
856        for idx in 0..1_000_000 {
857            let maybe = sut.get(idx);
858            assert!(maybe.is_some(), "{idx} is none");
859            let actual = maybe.unwrap();
860            assert_eq!(idx, *actual as usize);
861        }
862        assert_eq!(sut[99_999], 99_999);
863    }
864
865    #[test]
866    fn test_array_iterator() {
867        let inputs = [
868            "one", "two", "three", "four", "five", "six", "seven", "eight", "nine",
869        ];
870        let mut sut: SegmentArray<String> = SegmentArray::new();
871        for item in inputs {
872            sut.push(item.to_owned());
873        }
874        for (idx, elem) in sut.iter().enumerate() {
875            assert_eq!(inputs[idx], elem);
876        }
877    }
878
879    #[test]
880    fn test_array_intoiterator() {
881        // an array that only requires a single segment
882        let inputs = [
883            "one", "two", "three", "four", "five", "six", "seven", "eight", "nine",
884        ];
885        let mut sut: SegmentArray<String> = SegmentArray::new();
886        for item in inputs {
887            sut.push(item.to_owned());
888        }
889        for (idx, elem) in sut.into_iter().enumerate() {
890            assert_eq!(inputs[idx], elem);
891        }
892        // sut.len(); // error: ownership of sut was moved
893    }
894
895    #[test]
896    fn test_array_intoiterator_drop_tiny() {
897        // an array that only requires a single segment and only some need to be
898        // dropped after partially iterating the values
899        let inputs = [
900            "one", "two", "three", "four", "five", "six", "seven", "eight", "nine",
901        ];
902        let mut sut: SegmentArray<String> = SegmentArray::new();
903        for item in inputs {
904            sut.push(item.to_owned());
905        }
906        for (idx, _) in sut.into_iter().enumerate() {
907            if idx > 2 {
908                break;
909            }
910        }
911        // implicitly drop()
912    }
913
914    #[test]
915    fn test_array_intoiterator_drop_large() {
916        // by adding 512 values and iterating less than 64 times, there will be
917        // values in the first segment and some in the last segment, and two
918        // segments inbetween that all need to be dropped
919        let mut sut: SegmentArray<String> = SegmentArray::new();
920        for _ in 0..512 {
921            let value = ulid::Ulid::new().to_string();
922            sut.push(value);
923        }
924        for (idx, _) in sut.into_iter().enumerate() {
925            if idx >= 30 {
926                break;
927            }
928        }
929        // implicitly drop()
930    }
931
932    #[test]
933    fn test_array_fromiterator() {
934        let mut inputs: Vec<i32> = Vec::new();
935        for value in 0..10_000 {
936            inputs.push(value);
937        }
938        let sut: SegmentArray<i32> = inputs.into_iter().collect();
939        assert_eq!(sut.len(), 10_000);
940        for idx in 0..10_000i32 {
941            let maybe = sut.get(idx as usize);
942            assert!(maybe.is_some(), "{idx} is none");
943            let actual = maybe.unwrap();
944            assert_eq!(idx, *actual);
945        }
946    }
947
948    #[test]
949    fn test_push_get_many_instances_ints() {
950        // test allocating, filling, and then dropping many instances
951        for _ in 0..1_000 {
952            let mut sut: SegmentArray<usize> = SegmentArray::new();
953            for value in 0..10_000 {
954                sut.push(value);
955            }
956            assert_eq!(sut.len(), 10_000);
957        }
958    }
959
960    #[test]
961    fn test_push_get_many_instances_strings() {
962        // test allocating, filling, and then dropping many instances
963        for _ in 0..1_000 {
964            let mut sut: SegmentArray<String> = SegmentArray::new();
965            for _ in 0..1_000 {
966                let value = ulid::Ulid::new().to_string();
967                sut.push(value);
968            }
969            assert_eq!(sut.len(), 1_000);
970        }
971    }
972}