hashed_array_tree/
lib.rs

1//
2// Copyright (c) 2025 Nathan Fiedler
3//
4
5//! An implementation of Hashed Array Trees by Edward Sitarski.
6//! 
7//! From the original article:
8//! 
9//! > To overcome the limitations of variable-length arrays, I created a data
10//! > structure that has fast constant access time like an array, but mostly
11//! > avoids copying elements when it grows. I call this new structure a
12//! > "Hashed-Array Tree" (HAT) because it combines some of the features of hash
13//! > tables, arrays, and trees.
14//! 
15//! To achieve this, the data structure uses a standard growable vector to
16//! reference separate data blocks which hold the array elements. The index and
17//! the blocks are at most O(√N) in size. As more elements are added, the size
18//! of the index and blocks will grow by powers of two (4, 8, 16, 32, etc).
19//!
20//! # Memory Usage
21//!
22//! An empty hased array tree is approximately 72 bytes in size, and while
23//! holding elements it will have a space overhead on the order of O(√N). As
24//! elements are added the array will grow by allocating additional data blocks.
25//! Likewise, as elements are removed from the end of the array, data blocks
26//! will be deallocated as they become empty.
27//! 
28//! # Performance
29//! 
30//! The get and set operations are O(1) while the push and pop may take O(N) in
31//! the worst case, if the array needs to be grown or shrunk.
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::ops::{Index, IndexMut};
42
43/// Hashed Array Tree (HAT) described by Edward Sitarski.
44pub struct HashedArrayTree<T> {
45    /// top array that holds pointers to data blocks ("leaves")
46    index: Vec<*mut T>,
47    /// number of elements in the array
48    count: usize,
49    /// index and leaves are 2^k in length
50    k: usize,
51    /// bit-mask to get the index into a leaf array
52    k_mask: usize,
53    /// the number of slots in the top array and leaves
54    l: usize,
55    /// when size increases to upper_limit, an expand is required
56    upper_limit: usize,
57    /// when size decreases to lower_limit, a compress is required
58    lower_limit: usize,
59}
60
61impl<T> HashedArrayTree<T> {
62    /// Returns a hashed array tree with zero capacity.
63    pub fn new() -> Self {
64        let index: Vec<*mut T> = vec![];
65        Self {
66            index,
67            count: 0,
68            k: 2,
69            k_mask: 3,
70            l: 4,
71            upper_limit: 16,
72            lower_limit: 0,
73        }
74    }
75
76    /// Double the capacity of this array by combining its leaves into new
77    /// leaves of double the capacity.
78    fn expand(&mut self) {
79        let l_prime = 1 << (self.k + 1);
80        let old_index: Vec<*mut T> = std::mem::take(&mut self.index);
81        let mut iter = old_index.into_iter();
82        while let Some(a) = iter.next() {
83            let layout = Layout::array::<T>(l_prime).expect("unexpected overflow");
84            let buffer = unsafe {
85                let ptr = alloc(layout).cast::<T>();
86                if ptr.is_null() {
87                    handle_alloc_error(layout);
88                }
89                ptr
90            };
91            if let Some(b) = iter.next() {
92                let b_dst = unsafe { buffer.add(self.l) };
93                let old_layout = Layout::array::<T>(self.l).expect("unexpected overflow");
94                unsafe {
95                    std::ptr::copy(a, buffer, self.l);
96                    std::ptr::copy(b, b_dst, self.l);
97                    dealloc(a as *mut u8, old_layout);
98                    dealloc(b as *mut u8, old_layout);
99                }
100            } else {
101                let old_layout = Layout::array::<T>(self.l).expect("unexpected overflow");
102                unsafe {
103                    std::ptr::copy(a, buffer, self.l);
104                    dealloc(a as *mut u8, old_layout);
105                }
106            }
107            self.index.push(buffer);
108        }
109        self.k += 1;
110        self.k_mask = (1 << self.k) - 1;
111        self.l = 1 << self.k;
112        self.upper_limit = self.l * self.l;
113        self.lower_limit = self.upper_limit / 8;
114    }
115
116    /// Appends an element to the back of a collection.
117    ///
118    /// # Panics
119    ///
120    /// Panics if a new block is allocated that would exceed `isize::MAX` _bytes_.
121    ///
122    /// # Time complexity
123    ///
124    /// O(N) in the worst case (expand).
125    pub fn push(&mut self, value: T) {
126        let len = self.count;
127        if len >= self.upper_limit {
128            self.expand();
129        }
130        if len >= self.capacity() {
131            let layout = Layout::array::<T>(self.l).expect("unexpected overflow");
132            let buffer = unsafe {
133                let ptr = alloc(layout).cast::<T>();
134                if ptr.is_null() {
135                    handle_alloc_error(layout);
136                }
137                ptr
138            };
139            self.index.push(buffer);
140        }
141        let block = len >> self.k;
142        let slot = len & self.k_mask;
143        unsafe { std::ptr::write(self.index[block].add(slot), value) }
144        self.count += 1;
145    }
146
147    /// Appends an element if there is sufficient spare capacity, otherwise an
148    /// error is returned with the element.
149    ///
150    /// # Time complexity
151    ///
152    /// O(N) in the worst case (expand).
153    pub fn push_within_capacity(&mut self, value: T) -> Result<(), T> {
154        if self.capacity() <= self.count {
155            Err(value)
156        } else {
157            self.push(value);
158            Ok(())
159        }
160    }
161
162    /// Retrieve a reference to the element at the given offset.
163    ///
164    /// # Time complexity
165    ///
166    /// Constant time.
167    pub fn get(&self, index: usize) -> Option<&T> {
168        if index >= self.count {
169            None
170        } else {
171            let block = index >> self.k;
172            let slot = index & self.k_mask;
173            unsafe { Some(&*self.index[block].add(slot)) }
174        }
175    }
176
177    /// Returns a mutable reference to an element.
178    ///
179    /// # Time complexity
180    ///
181    /// Constant time.
182    pub fn get_mut(&mut self, index: usize) -> Option<&mut T> {
183        if index >= self.count {
184            None
185        } else {
186            let block = index >> self.k;
187            let slot = index & self.k_mask;
188            unsafe { (self.index[block].add(slot)).as_mut() }
189        }
190    }
191
192    /// Shrink the capacity of this array by splitting its leaves into new
193    /// leaves of half the capacity.
194    fn compress(&mut self) {
195        let old_index: Vec<*mut T> = std::mem::take(&mut self.index);
196        for old_buffer in old_index.into_iter() {
197            let half = self.l / 2;
198            let layout = Layout::array::<T>(half).expect("unexpected overflow");
199            let a = unsafe {
200                let ptr = alloc(layout).cast::<T>();
201                if ptr.is_null() {
202                    handle_alloc_error(layout);
203                }
204                ptr
205            };
206            let b = unsafe {
207                let ptr = alloc(layout).cast::<T>();
208                if ptr.is_null() {
209                    handle_alloc_error(layout);
210                }
211                ptr
212            };
213            unsafe {
214                std::ptr::copy(old_buffer, a, half);
215                std::ptr::copy(old_buffer.add(half), b, half);
216            };
217            let layout = Layout::array::<T>(self.l).expect("unexpected overflow");
218            unsafe {
219                dealloc(old_buffer as *mut u8, layout);
220            }
221            self.index.push(a);
222            self.index.push(b);
223        }
224        self.k -= 1;
225        self.k_mask = (1 << self.k) - 1;
226        self.l = 1 << self.k;
227        self.upper_limit = self.l * self.l;
228        self.lower_limit = self.upper_limit / 8;
229    }
230
231    /// Removes the last element from the array and returns it, or `None` if the
232    /// array is empty.
233    ///
234    /// # Time complexity
235    ///
236    /// O(N) in the worst case (shrink).
237    pub fn pop(&mut self) -> Option<T> {
238        if self.count > 0 {
239            let index = self.count - 1;
240            // avoid compressing the leaves smaller than 4
241            if index < self.lower_limit && self.k > 2 {
242                self.compress();
243            }
244            let block = index >> self.k;
245            let slot = index & self.k_mask;
246            let ret = unsafe { Some(std::ptr::read(self.index[block].add(slot))) };
247            if slot == 0 {
248                // prune leaves as they become empty
249                let ptr = self.index.pop().unwrap();
250                let layout = Layout::array::<T>(self.l).expect("unexpected overflow");
251                unsafe {
252                    dealloc(ptr as *mut u8, layout);
253                }
254            }
255            self.count -= 1;
256            ret
257        } else {
258            None
259        }
260    }
261
262    /// Removes and returns the last element from an array if the predicate
263    /// returns true, or `None`` if the predicate returns `false`` or the array
264    /// is empty (the predicate will not be called in that case).
265    ///
266    /// # Time complexity
267    ///
268    /// O(N) in the worst case (shrink).
269    pub fn pop_if(&mut self, predicate: impl FnOnce(&mut T) -> bool) -> Option<T> {
270        if self.count == 0 {
271            None
272        } else if let Some(last) = self.get_mut(self.count - 1) {
273            if predicate(last) { self.pop() } else { None }
274        } else {
275            None
276        }
277    }
278
279    /// Removes an element from the array and returns it.
280    ///
281    /// The removed element is replaced by the last element of the array.
282    ///
283    /// This does not preserve ordering of the remaining elements.
284    ///
285    /// # Time complexity
286    ///
287    /// O(N) in the worst case (shrink).
288    pub fn swap_remove(&mut self, index: usize) -> T {
289        if index >= self.count {
290            panic!(
291                "swap_remove index (is {index}) should be < len (is {})",
292                self.count
293            );
294        }
295        // retreive the value at index before overwriting
296        let block = index >> self.k;
297        let slot = index & self.k_mask;
298        unsafe {
299            let index_ptr = self.index[block].add(slot);
300            let value = index_ptr.read();
301            // find the pointer of the last element and copy to index pointer
302            let block = (self.count - 1) >> self.k;
303            let slot = (self.count - 1) & self.k_mask;
304            let last_ptr = self.index[block].add(slot);
305            std::ptr::copy(last_ptr, index_ptr, 1);
306            if slot == 0 {
307                // prune leaves as they become empty
308                let ptr = self.index.pop().unwrap();
309                let layout = Layout::array::<T>(self.l).expect("unexpected overflow");
310                dealloc(ptr as *mut u8, layout);
311            }
312            self.count -= 1;
313            value
314        }
315    }
316
317    // Returns an iterator over the array.
318    //
319    // The iterator yields all items from start to end.
320    pub fn iter(&self) -> ArrayIter<'_, T> {
321        ArrayIter {
322            array: self,
323            index: 0,
324        }
325    }
326
327    /// Return the number of elements in the array.
328    ///
329    /// # Time complexity
330    ///
331    /// Constant time.
332    pub fn len(&self) -> usize {
333        self.count
334    }
335
336    /// Returns the total number of elements the array can hold without
337    /// reallocating.
338    ///
339    /// # Time complexity
340    ///
341    /// Constant time.
342    pub fn capacity(&self) -> usize {
343        (1 << self.k) * self.index.len()
344    }
345
346    /// Returns true if the array has a length of 0.
347    ///
348    /// # Time complexity
349    ///
350    /// Constant time.
351    pub fn is_empty(&self) -> bool {
352        self.count == 0
353    }
354
355    /// Clears the array, removing all values and deallocating all leaves.
356    ///
357    /// # Time complexity
358    ///
359    /// O(N) if elements are droppable, otherwise O(√N)
360    pub fn clear(&mut self) {
361        use std::ptr::{drop_in_place, slice_from_raw_parts_mut};
362
363        if self.count > 0 && std::mem::needs_drop::<T>() {
364            // find the last leaf that contains values and drop them
365            let last_index = self.count - 1;
366            let last_block = last_index >> self.k;
367            let last_slot = last_index & self.k_mask;
368            unsafe {
369                // last_slot is pointing at the last element, need to add
370                // one to include it in the slice
371                drop_in_place(slice_from_raw_parts_mut(
372                    self.index[last_block],
373                    last_slot + 1,
374                ));
375            }
376
377            // drop the values in all of the preceding leaves
378            for block in 0..last_block {
379                unsafe {
380                    drop_in_place(slice_from_raw_parts_mut(self.index[block], self.l));
381                }
382            }
383        }
384
385        // deallocate all leaves using the index as the source of truth
386        let layout = Layout::array::<T>(self.l).expect("unexpected overflow");
387        for block in 0..self.index.len() {
388            unsafe {
389                dealloc(self.index[block] as *mut u8, layout);
390            }
391        }
392        self.index.clear();
393
394        self.count = 0;
395        self.k = 2;
396        self.k_mask = 3;
397        self.l = 1 << self.k;
398        self.upper_limit = self.l * self.l;
399        self.lower_limit = 0;
400    }
401}
402
403impl<T> Default for HashedArrayTree<T> {
404    fn default() -> Self {
405        Self::new()
406    }
407}
408
409impl<T> fmt::Display for HashedArrayTree<T> {
410    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
411        write!(
412            f,
413            "HashedArrayTree(k: {}, count: {}, dope: {})",
414            self.k,
415            self.count,
416            self.index.len(),
417        )
418    }
419}
420
421impl<T> Index<usize> for HashedArrayTree<T> {
422    type Output = T;
423
424    fn index(&self, index: usize) -> &Self::Output {
425        let Some(item) = self.get(index) else {
426            panic!("index out of bounds: {}", index);
427        };
428        item
429    }
430}
431
432impl<T> IndexMut<usize> for HashedArrayTree<T> {
433    fn index_mut(&mut self, index: usize) -> &mut Self::Output {
434        let Some(item) = self.get_mut(index) else {
435            panic!("index out of bounds: {}", index);
436        };
437        item
438    }
439}
440
441impl<T> Drop for HashedArrayTree<T> {
442    fn drop(&mut self) {
443        self.clear();
444    }
445}
446
447impl<A> FromIterator<A> for HashedArrayTree<A> {
448    fn from_iter<T: IntoIterator<Item = A>>(iter: T) -> Self {
449        let mut arr: HashedArrayTree<A> = HashedArrayTree::new();
450        for value in iter {
451            arr.push(value)
452        }
453        arr
454    }
455}
456
457/// Immutable hashed array tree iterator.
458pub struct ArrayIter<'a, T> {
459    array: &'a HashedArrayTree<T>,
460    index: usize,
461}
462
463impl<'a, T> Iterator for ArrayIter<'a, T> {
464    type Item = &'a T;
465
466    fn next(&mut self) -> Option<Self::Item> {
467        let value = self.array.get(self.index);
468        self.index += 1;
469        value
470    }
471}
472
473/// An iterator that moves out of a hashed array tree.
474pub struct ArrayIntoIter<T> {
475    index: usize,
476    k: usize,
477    k_mask: usize,
478    count: usize,
479    dope: Vec<*mut T>,
480}
481
482impl<T> Iterator for ArrayIntoIter<T> {
483    type Item = T;
484
485    fn next(&mut self) -> Option<Self::Item> {
486        if self.index < self.count {
487            let block = self.index >> self.k;
488            let slot = self.index & self.k_mask;
489            self.index += 1;
490            unsafe { Some((self.dope[block].add(slot)).read()) }
491        } else {
492            None
493        }
494    }
495}
496
497impl<T> IntoIterator for HashedArrayTree<T> {
498    type Item = T;
499    type IntoIter = ArrayIntoIter<Self::Item>;
500
501    fn into_iter(self) -> Self::IntoIter {
502        let mut me = std::mem::ManuallyDrop::new(self);
503        let dope = std::mem::take(&mut me.index);
504        ArrayIntoIter {
505            index: 0,
506            count: me.count,
507            k: me.k,
508            k_mask: me.k_mask,
509            dope,
510        }
511    }
512}
513
514impl<T> Drop for ArrayIntoIter<T> {
515    fn drop(&mut self) {
516        use std::ptr::{drop_in_place, slice_from_raw_parts_mut};
517        let block_len = 1 << self.k;
518
519        if std::mem::needs_drop::<T>() {
520            let first_block = self.index >> self.k;
521            let first_slot = self.index & self.k_mask;
522            let last_block = (self.count - 1) >> self.k;
523            let last_slot = (self.count - 1) & self.k_mask;
524            if first_block == last_block {
525                // special-case, remaining values are in only one leaf
526                if first_slot <= last_slot {
527                    unsafe {
528                        // last_slot is pointing at the last element, need to
529                        // add one to include it in the slice
530                        drop_in_place(slice_from_raw_parts_mut(
531                            self.dope[first_block].add(first_slot),
532                            last_slot - first_slot + 1,
533                        ));
534                    }
535                }
536            } else {
537                // drop the remaining values in the first leaf
538                if block_len < self.count {
539                    unsafe {
540                        drop_in_place(slice_from_raw_parts_mut(
541                            self.dope[first_block].add(first_slot),
542                            block_len - first_slot,
543                        ));
544                    }
545                }
546
547                // drop the values in the last leaf
548                unsafe {
549                    drop_in_place(slice_from_raw_parts_mut(
550                        self.dope[last_block],
551                        last_slot + 1,
552                    ));
553                }
554
555                // drop the values in all of the other leaves
556                for block in first_block + 1..last_block {
557                    unsafe {
558                        drop_in_place(slice_from_raw_parts_mut(self.dope[block], block_len));
559                    }
560                }
561            }
562        }
563
564        // deallocate all of the leaves
565        for block in 0..self.dope.len() {
566            let layout = Layout::array::<T>(block_len).expect("unexpected overflow");
567            unsafe {
568                dealloc(self.dope[block] as *mut u8, layout);
569            }
570        }
571    }
572}
573
574#[cfg(test)]
575mod tests {
576    use super::*;
577
578    #[test]
579    fn test_empty() {
580        let sut = HashedArrayTree::<usize>::new();
581        assert!(sut.get(0).is_none());
582    }
583
584    #[test]
585    #[should_panic(expected = "index out of bounds:")]
586    fn test_index_out_of_bounds() {
587        let mut sut: HashedArrayTree<i32> = HashedArrayTree::new();
588        sut.push(10);
589        sut.push(20);
590        let _ = sut[2];
591    }
592
593    #[test]
594    #[should_panic(expected = "index out of bounds:")]
595    fn test_index_mut_out_of_bounds() {
596        let mut sut: HashedArrayTree<i32> = HashedArrayTree::new();
597        sut.push(10);
598        sut.push(20);
599        sut[2] = 30;
600    }
601
602    #[test]
603    fn test_push_no_expand() {
604        // push few enough elements to avoid an expansion
605        let mut sut = HashedArrayTree::<usize>::new();
606        for value in 0..13 {
607            sut.push(value);
608        }
609        assert_eq!(sut.len(), 13);
610        assert_eq!(sut.capacity(), 16);
611        for value in 0..13 {
612            assert_eq!(sut[value], value);
613        }
614        // pop enough to cause the last leaf to be freed
615        sut.pop();
616        assert_eq!(sut.len(), 12);
617        assert_eq!(sut.capacity(), 12);
618    }
619
620    #[test]
621    fn test_push_with_expand() {
622        // push few enough elements to cause an expansion
623        let mut sut = HashedArrayTree::<usize>::new();
624        for value in 0..64 {
625            sut.push(value);
626        }
627        assert_eq!(sut.len(), 64);
628        assert_eq!(sut.capacity(), 64);
629        for value in 0..64 {
630            assert_eq!(sut[value], value);
631        }
632    }
633
634    #[test]
635    fn test_expand_and_compress() {
636        // add enough to cause multiple expansions
637        let mut sut = HashedArrayTree::<usize>::new();
638        for value in 0..1024 {
639            sut.push(value);
640        }
641        assert_eq!(sut.len(), 1024);
642        assert_eq!(sut.capacity(), 1024);
643        // remove enough to cause multiple compressions
644        for _ in 0..960 {
645            sut.pop();
646        }
647        // ensure the correct elements remain
648        assert_eq!(sut.len(), 64);
649        assert_eq!(sut.capacity(), 64);
650        for value in 0..64 {
651            assert_eq!(sut[value], value);
652        }
653    }
654
655    #[test]
656    fn test_push_get_get_mut() {
657        let mut sut = HashedArrayTree::<usize>::new();
658        for value in 0..12 {
659            sut.push(value);
660        }
661        assert_eq!(sut.get(2), Some(&2));
662        if let Some(value) = sut.get_mut(1) {
663            *value = 11;
664        } else {
665            panic!("get_mut() returned None")
666        }
667        assert_eq!(sut[0], 0);
668        assert_eq!(sut[1], 11);
669        assert_eq!(sut[2], 2);
670    }
671
672    #[test]
673    fn test_push_within_capacity() {
674        // empty array has no allocated space
675        let mut sut = HashedArrayTree::<u32>::new();
676        assert_eq!(sut.push_within_capacity(101), Err(101));
677        // will have 4 slots after a single allocation
678        sut.push(1);
679        sut.push(2);
680        assert_eq!(sut.push_within_capacity(3), Ok(()));
681        assert_eq!(sut.push_within_capacity(4), Ok(()));
682        assert_eq!(sut.push_within_capacity(5), Err(5));
683    }
684
685    #[test]
686    fn test_pop_small() {
687        let mut sut = HashedArrayTree::<usize>::new();
688        assert!(sut.is_empty());
689        assert_eq!(sut.len(), 0);
690        for value in 0..15 {
691            sut.push(value);
692        }
693        assert!(!sut.is_empty());
694        assert_eq!(sut.len(), 15);
695        for value in (0..15).rev() {
696            assert_eq!(sut.pop(), Some(value));
697        }
698        assert!(sut.is_empty());
699        assert_eq!(sut.len(), 0);
700        assert_eq!(sut.capacity(), 0);
701    }
702
703    #[test]
704    fn test_pop_if() {
705        let mut sut = HashedArrayTree::<u32>::new();
706        assert!(sut.pop_if(|_| panic!("should not be called")).is_none());
707        for value in 0..10 {
708            sut.push(value);
709        }
710        assert!(sut.pop_if(|_| false).is_none());
711        let maybe = sut.pop_if(|v| *v == 9);
712        assert_eq!(maybe.unwrap(), 9);
713        assert!(sut.pop_if(|v| *v == 9).is_none());
714    }
715
716    #[test]
717    fn test_clear_and_reuse_ints() {
718        let mut sut: HashedArrayTree<i32> = HashedArrayTree::new();
719        for value in 0..512 {
720            sut.push(value);
721        }
722        assert_eq!(sut.len(), 512);
723        sut.clear();
724        assert_eq!(sut.len(), 0);
725        for value in 0..512 {
726            sut.push(value);
727        }
728        for idx in 0..512 {
729            let maybe = sut.get(idx);
730            assert!(maybe.is_some(), "{idx} is none");
731            let actual = maybe.unwrap();
732            assert_eq!(idx, *actual as usize);
733        }
734    }
735
736    #[test]
737    fn test_clear_and_reuse_strings() {
738        let mut sut: HashedArrayTree<String> = HashedArrayTree::new();
739        for _ in 0..512 {
740            let value = ulid::Ulid::new().to_string();
741            sut.push(value);
742        }
743        assert_eq!(sut.len(), 512);
744        sut.clear();
745        assert_eq!(sut.len(), 0);
746        for _ in 0..512 {
747            let value = ulid::Ulid::new().to_string();
748            sut.push(value);
749        }
750        assert_eq!(sut.len(), 512);
751        // implicitly drop()
752    }
753
754    #[test]
755    fn test_from_iterator() {
756        let mut inputs: Vec<i32> = Vec::new();
757        for value in 0..10_000 {
758            inputs.push(value);
759        }
760        let sut: HashedArrayTree<i32> = inputs.into_iter().collect();
761        assert_eq!(sut.len(), 10_000);
762        for idx in 0..10_000i32 {
763            let maybe = sut.get(idx as usize);
764            assert!(maybe.is_some(), "{idx} is none");
765            let actual = maybe.unwrap();
766            assert_eq!(idx, *actual);
767        }
768    }
769
770    #[test]
771    fn test_iterator() {
772        let mut sut = HashedArrayTree::<usize>::new();
773        for value in 0..512 {
774            sut.push(value);
775        }
776        assert_eq!(sut.len(), 512);
777        for (idx, elem) in sut.iter().enumerate() {
778            assert_eq!(sut[idx], *elem);
779        }
780    }
781
782    #[test]
783    fn test_into_iterator() {
784        // an array that only requires a single segment
785        let inputs = [
786            "one", "two", "three", "four", "five", "six", "seven", "eight", "nine",
787        ];
788        let mut sut: HashedArrayTree<String> = HashedArrayTree::new();
789        for item in inputs {
790            sut.push(item.to_owned());
791        }
792        for (idx, elem) in sut.into_iter().enumerate() {
793            assert_eq!(inputs[idx], elem);
794        }
795        // sut.len(); // error: ownership of sut was moved
796    }
797
798    #[test]
799    fn test_into_iterator_drop_tiny() {
800        // an array that only requires a single segment and only some need to be
801        // dropped after partially iterating the values
802        let inputs = [
803            "one", "two", "three", "four", "five", "six", "seven", "eight", "nine",
804        ];
805        let mut sut: HashedArrayTree<String> = HashedArrayTree::new();
806        for item in inputs {
807            sut.push(item.to_owned());
808        }
809        for (idx, _) in sut.into_iter().enumerate() {
810            if idx > 2 {
811                break;
812            }
813        }
814        // implicitly drop()
815    }
816
817    #[test]
818    fn test_into_iterator_drop_large() {
819        // by adding 512 values and iterating less than 64 times, there will be
820        // values in the first segment and some in the last segment, and two
821        // segments inbetween that all need to be dropped
822        let mut sut: HashedArrayTree<String> = HashedArrayTree::new();
823        for _ in 0..512 {
824            let value = ulid::Ulid::new().to_string();
825            sut.push(value);
826        }
827        for (idx, _) in sut.into_iter().enumerate() {
828            if idx >= 30 {
829                break;
830            }
831        }
832        // implicitly drop()
833    }
834
835    #[test]
836    fn test_swap_remove_single_segment() {
837        let mut sut: HashedArrayTree<u32> = HashedArrayTree::new();
838        sut.push(1);
839        sut.push(2);
840        assert_eq!(sut.len(), 2);
841        let one = sut.swap_remove(0);
842        assert_eq!(one, 1);
843        assert_eq!(sut[0], 2);
844    }
845
846    #[test]
847    fn test_swap_remove_prune_empty() {
848        let mut sut: HashedArrayTree<u32> = HashedArrayTree::new();
849        for value in 0..13 {
850            sut.push(value);
851        }
852        assert_eq!(sut.len(), 13);
853        assert_eq!(sut.capacity(), 16);
854        let value = sut.swap_remove(8);
855        assert_eq!(value, 8);
856        assert_eq!(sut[8], 12);
857        assert_eq!(sut.len(), 12);
858        assert_eq!(sut.capacity(), 12);
859    }
860
861    #[test]
862    fn test_swap_remove_multiple_segments() {
863        let mut sut: HashedArrayTree<u32> = HashedArrayTree::new();
864        for value in 0..512 {
865            sut.push(value);
866        }
867        assert_eq!(sut.len(), 512);
868        let eighty = sut.swap_remove(80);
869        assert_eq!(eighty, 80);
870        assert_eq!(sut.pop(), Some(510));
871        assert_eq!(sut[80], 511);
872    }
873
874    #[test]
875    #[should_panic(expected = "swap_remove index (is 0) should be < len (is 0)")]
876    fn test_swap_remove_panic_empty() {
877        let mut sut: HashedArrayTree<u32> = HashedArrayTree::new();
878        sut.swap_remove(0);
879    }
880
881    #[test]
882    #[should_panic(expected = "swap_remove index (is 1) should be < len (is 1)")]
883    fn test_swap_remove_panic_range_edge() {
884        let mut sut: HashedArrayTree<u32> = HashedArrayTree::new();
885        sut.push(1);
886        sut.swap_remove(1);
887    }
888
889    #[test]
890    #[should_panic(expected = "swap_remove index (is 2) should be < len (is 1)")]
891    fn test_swap_remove_panic_range_exceed() {
892        let mut sut: HashedArrayTree<u32> = HashedArrayTree::new();
893        sut.push(1);
894        sut.swap_remove(2);
895    }
896
897    #[test]
898    fn test_push_get_many_instances_ints() {
899        // test allocating, filling, and then dropping many instances
900        for _ in 0..1_000 {
901            let mut sut: HashedArrayTree<usize> = HashedArrayTree::new();
902            for value in 0..10_000 {
903                sut.push(value);
904            }
905            assert_eq!(sut.len(), 10_000);
906        }
907    }
908
909    #[test]
910    fn test_push_get_many_instances_strings() {
911        // test allocating, filling, and then dropping many instances
912        for _ in 0..1_000 {
913            let mut sut: HashedArrayTree<String> = HashedArrayTree::new();
914            for _ in 0..1_000 {
915                let value = ulid::Ulid::new().to_string();
916                sut.push(value);
917            }
918            assert_eq!(sut.len(), 1_000);
919        }
920    }
921}