segment_array/
lib.rs

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