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::cmp::Ordering;
41use std::fmt;
42use std::ops::{Index, IndexMut};
43
44/// Hashed Array Tree (HAT) described by Edward Sitarski.
45pub struct HashedArrayTree<T> {
46    /// top array that holds pointers to data blocks ("leaves")
47    index: Vec<*mut T>,
48    /// number of elements in the array
49    count: usize,
50    /// index and leaves are 2^k in length
51    k: usize,
52    /// bit-mask to get the index into a leaf array
53    k_mask: usize,
54    /// the number of slots in the top array and leaves
55    l: usize,
56    /// when size increases to upper_limit, an expand is required
57    upper_limit: usize,
58    /// when size decreases to lower_limit, a compress is required
59    lower_limit: usize,
60}
61
62impl<T> HashedArrayTree<T> {
63    /// Returns a hashed array tree with zero capacity.
64    pub fn new() -> Self {
65        let index: Vec<*mut T> = vec![];
66        Self {
67            index,
68            count: 0,
69            k: 2,
70            k_mask: 3,
71            l: 4,
72            upper_limit: 16,
73            lower_limit: 0,
74        }
75    }
76
77    /// Double the capacity of this array by combining its leaves into new
78    /// leaves of double the capacity.
79    fn expand(&mut self) {
80        let l_prime = 1 << (self.k + 1);
81        let old_index: Vec<*mut T> = std::mem::take(&mut self.index);
82        let mut iter = old_index.into_iter();
83        while let Some(a) = iter.next() {
84            let layout = Layout::array::<T>(l_prime).expect("unexpected overflow");
85            let buffer = unsafe {
86                let ptr = alloc(layout).cast::<T>();
87                if ptr.is_null() {
88                    handle_alloc_error(layout);
89                }
90                ptr
91            };
92            if let Some(b) = iter.next() {
93                let b_dst = unsafe { buffer.add(self.l) };
94                let old_layout = Layout::array::<T>(self.l).expect("unexpected overflow");
95                unsafe {
96                    std::ptr::copy(a, buffer, self.l);
97                    std::ptr::copy(b, b_dst, self.l);
98                    dealloc(a as *mut u8, old_layout);
99                    dealloc(b as *mut u8, old_layout);
100                }
101            } else {
102                let old_layout = Layout::array::<T>(self.l).expect("unexpected overflow");
103                unsafe {
104                    std::ptr::copy(a, buffer, self.l);
105                    dealloc(a as *mut u8, old_layout);
106                }
107            }
108            self.index.push(buffer);
109        }
110        self.k += 1;
111        self.k_mask = (1 << self.k) - 1;
112        self.l = 1 << self.k;
113        self.upper_limit = self.l * self.l;
114        self.lower_limit = self.upper_limit / 8;
115    }
116
117    /// Appends an element to the back of a collection.
118    ///
119    /// # Panics
120    ///
121    /// Panics if a new block is allocated that would exceed `isize::MAX` _bytes_.
122    ///
123    /// # Time complexity
124    ///
125    /// O(N) in the worst case (expand).
126    pub fn push(&mut self, value: T) {
127        let len = self.count;
128        if len >= self.upper_limit {
129            self.expand();
130        }
131        if len >= self.capacity() {
132            let layout = Layout::array::<T>(self.l).expect("unexpected overflow");
133            let buffer = unsafe {
134                let ptr = alloc(layout).cast::<T>();
135                if ptr.is_null() {
136                    handle_alloc_error(layout);
137                }
138                ptr
139            };
140            self.index.push(buffer);
141        }
142        let block = len >> self.k;
143        let slot = len & self.k_mask;
144        unsafe { std::ptr::write(self.index[block].add(slot), value) }
145        self.count += 1;
146    }
147
148    /// Appends an element if there is sufficient spare capacity, otherwise an
149    /// error is returned with the element.
150    ///
151    /// # Time complexity
152    ///
153    /// O(N) in the worst case (expand).
154    pub fn push_within_capacity(&mut self, value: T) -> Result<(), T> {
155        if self.capacity() <= self.count {
156            Err(value)
157        } else {
158            self.push(value);
159            Ok(())
160        }
161    }
162
163    /// Like `get()` but without the `Option` wrapper.
164    fn raw_get(&self, index: usize) -> &T {
165        let block = index >> self.k;
166        let slot = index & self.k_mask;
167        unsafe { &*self.index[block].add(slot) }
168    }
169
170    /// Retrieve a reference to the element at the given offset.
171    ///
172    /// # Time complexity
173    ///
174    /// Constant time.
175    pub fn get(&self, index: usize) -> Option<&T> {
176        if index >= self.count {
177            None
178        } else {
179            Some(self.raw_get(index))
180        }
181    }
182
183    /// Returns a mutable reference to an element.
184    ///
185    /// # Time complexity
186    ///
187    /// Constant time.
188    pub fn get_mut(&mut self, index: usize) -> Option<&mut T> {
189        if index >= self.count {
190            None
191        } else {
192            let block = index >> self.k;
193            let slot = index & self.k_mask;
194            unsafe { (self.index[block].add(slot)).as_mut() }
195        }
196    }
197
198    /// Shrink the capacity of this array by splitting its leaves into new
199    /// leaves of half the capacity.
200    fn compress(&mut self) {
201        let old_index: Vec<*mut T> = std::mem::take(&mut self.index);
202        for old_buffer in old_index.into_iter() {
203            let half = self.l / 2;
204            let layout = Layout::array::<T>(half).expect("unexpected overflow");
205            let a = unsafe {
206                let ptr = alloc(layout).cast::<T>();
207                if ptr.is_null() {
208                    handle_alloc_error(layout);
209                }
210                ptr
211            };
212            let b = unsafe {
213                let ptr = alloc(layout).cast::<T>();
214                if ptr.is_null() {
215                    handle_alloc_error(layout);
216                }
217                ptr
218            };
219            unsafe {
220                std::ptr::copy(old_buffer, a, half);
221                std::ptr::copy(old_buffer.add(half), b, half);
222            };
223            let layout = Layout::array::<T>(self.l).expect("unexpected overflow");
224            unsafe {
225                dealloc(old_buffer as *mut u8, layout);
226            }
227            self.index.push(a);
228            self.index.push(b);
229        }
230        self.k -= 1;
231        self.k_mask = (1 << self.k) - 1;
232        self.l = 1 << self.k;
233        self.upper_limit = self.l * self.l;
234        self.lower_limit = self.upper_limit / 8;
235    }
236
237    /// Removes the last element from the array and returns it, or `None` if the
238    /// array is empty.
239    ///
240    /// # Time complexity
241    ///
242    /// O(N) in the worst case (shrink).
243    pub fn pop(&mut self) -> Option<T> {
244        if self.count > 0 {
245            let index = self.count - 1;
246            // avoid compressing the leaves smaller than 4
247            if index < self.lower_limit && self.k > 2 {
248                self.compress();
249            }
250            let block = index >> self.k;
251            let slot = index & self.k_mask;
252            let ret = unsafe { Some(std::ptr::read(self.index[block].add(slot))) };
253            if slot == 0 {
254                // prune leaves as they become empty
255                let ptr = self.index.pop().unwrap();
256                let layout = Layout::array::<T>(self.l).expect("unexpected overflow");
257                unsafe {
258                    dealloc(ptr as *mut u8, layout);
259                }
260            }
261            self.count -= 1;
262            ret
263        } else {
264            None
265        }
266    }
267
268    /// Removes and returns the last element from an array if the predicate
269    /// returns true, or `None`` if the predicate returns `false`` or the array
270    /// is empty (the predicate will not be called in that case).
271    ///
272    /// # Time complexity
273    ///
274    /// O(N) in the worst case (shrink).
275    pub fn pop_if(&mut self, predicate: impl FnOnce(&mut T) -> bool) -> Option<T> {
276        if self.count == 0 {
277            None
278        } else if let Some(last) = self.get_mut(self.count - 1) {
279            if predicate(last) { self.pop() } else { None }
280        } else {
281            None
282        }
283    }
284
285    /// Removes an element from the array and returns it.
286    ///
287    /// The removed element is replaced by the last element of the array.
288    ///
289    /// This does not preserve ordering of the remaining elements.
290    ///
291    /// # Panics
292    ///
293    /// Panics if the index is out of bounds.
294    ///
295    /// # Time complexity
296    ///
297    /// O(N) in the worst case (shrink).
298    pub fn swap_remove(&mut self, index: usize) -> T {
299        if index >= self.count {
300            panic!(
301                "swap_remove index (is {index}) should be < len (is {})",
302                self.count
303            );
304        }
305        // retreive the value at index before overwriting
306        let block = index >> self.k;
307        let slot = index & self.k_mask;
308        unsafe {
309            let index_ptr = self.index[block].add(slot);
310            let value = index_ptr.read();
311            // find the pointer of the last element and copy to index pointer
312            let block = (self.count - 1) >> self.k;
313            let slot = (self.count - 1) & self.k_mask;
314            let last_ptr = self.index[block].add(slot);
315            std::ptr::copy(last_ptr, index_ptr, 1);
316            if slot == 0 {
317                // prune leaves as they become empty
318                let ptr = self.index.pop().unwrap();
319                let layout = Layout::array::<T>(self.l).expect("unexpected overflow");
320                dealloc(ptr as *mut u8, layout);
321            }
322            self.count -= 1;
323            value
324        }
325    }
326
327    // Returns an iterator over the array.
328    //
329    // The iterator yields all items from start to end.
330    pub fn iter(&self) -> ArrayIter<'_, T> {
331        ArrayIter {
332            array: self,
333            index: 0,
334        }
335    }
336
337    /// Return the number of elements in the array.
338    ///
339    /// # Time complexity
340    ///
341    /// Constant time.
342    pub fn len(&self) -> usize {
343        self.count
344    }
345
346    /// Returns the total number of elements the array can hold without
347    /// reallocating.
348    ///
349    /// # Time complexity
350    ///
351    /// Constant time.
352    pub fn capacity(&self) -> usize {
353        (1 << self.k) * self.index.len()
354    }
355
356    /// Returns true if the array has a length of 0.
357    ///
358    /// # Time complexity
359    ///
360    /// Constant time.
361    pub fn is_empty(&self) -> bool {
362        self.count == 0
363    }
364
365    /// Clears the array, removing all values and deallocating all leaves.
366    ///
367    /// # Time complexity
368    ///
369    /// O(N) if elements are droppable, otherwise O(√N)
370    pub fn clear(&mut self) {
371        use std::ptr::{drop_in_place, slice_from_raw_parts_mut};
372
373        if self.count > 0 && std::mem::needs_drop::<T>() {
374            // find the last leaf that contains values and drop them
375            let last_index = self.count - 1;
376            let last_block = last_index >> self.k;
377            let last_slot = last_index & self.k_mask;
378            unsafe {
379                // last_slot is pointing at the last element, need to add
380                // one to include it in the slice
381                drop_in_place(slice_from_raw_parts_mut(
382                    self.index[last_block],
383                    last_slot + 1,
384                ));
385            }
386
387            // drop the values in all of the preceding leaves
388            for block in 0..last_block {
389                unsafe {
390                    drop_in_place(slice_from_raw_parts_mut(self.index[block], self.l));
391                }
392            }
393        }
394
395        // deallocate all leaves using the index as the source of truth
396        let layout = Layout::array::<T>(self.l).expect("unexpected overflow");
397        for block in 0..self.index.len() {
398            unsafe {
399                dealloc(self.index[block] as *mut u8, layout);
400            }
401        }
402        self.index.clear();
403
404        self.count = 0;
405        self.k = 2;
406        self.k_mask = 3;
407        self.l = 1 << self.k;
408        self.upper_limit = self.l * self.l;
409        self.lower_limit = 0;
410    }
411
412    /// Swap two elements in the array.
413    ///
414    /// # Panics
415    ///
416    /// Panics if either index is out of bounds.
417    ///
418    pub fn swap(&mut self, a: usize, b: usize) {
419        if a >= self.count {
420            panic!("swap a (is {a}) should be < len (is {})", self.count);
421        }
422        if b >= self.count {
423            panic!("swap b (is {b}) should be < len (is {})", self.count);
424        }
425        // save the value in slot a before overwriting with value from slot b,
426        // then write the saved value to slot b
427        let a_block = a >> self.k;
428        let a_slot = a & self.k_mask;
429        let b_block = b >> self.k;
430        let b_slot = b & self.k_mask;
431        unsafe {
432            let a_ptr = self.index[a_block].add(a_slot);
433            let value = a_ptr.read();
434            let b_ptr = self.index[b_block].add(b_slot);
435            std::ptr::copy(b_ptr, a_ptr, 1);
436            std::ptr::write(b_ptr, value);
437        }
438    }
439
440    /// Sorts the slice in ascending order with a comparison function,
441    /// **without** preserving the initial order of equal elements.
442    ///
443    /// This sort is unstable (i.e., may reorder equal elements), in-place
444    /// (i.e., does not allocate), and *O*(*n* \* log(*n*)) worst-case.
445    ///
446    /// Implements the standard heapsort algorithm.
447    pub fn sort_unstable_by<F>(&mut self, mut compare: F)
448    where
449        F: FnMut(&T, &T) -> Ordering,
450    {
451        if self.count < 2 {
452            return;
453        }
454        let mut start = self.count / 2;
455        let mut end = self.count;
456        while end > 1 {
457            if start > 0 {
458                start -= 1;
459            } else {
460                end -= 1;
461                self.swap(end, 0);
462            }
463            let mut root = start;
464            let mut child = 2 * root + 1;
465            while child < end {
466                if child + 1 < end && compare(&self[child], &self[child + 1]) == Ordering::Less {
467                    child += 1;
468                }
469                if compare(&self[root], &self[child]) == Ordering::Less {
470                    self.swap(root, child);
471                    root = child;
472                    child = 2 * root + 1;
473                } else {
474                    break;
475                }
476            }
477        }
478    }
479
480    /// Removes all but the first of consecutive elements in the array
481    /// satisfying a given equality relation.
482    ///
483    /// The `same_bucket` function is passed references to two elements from the
484    /// array and must determine if the elements compare equal. The elements are
485    /// passed in reverse order from their order in the array, so if
486    /// `same_bucket(a, b)` returns `true`, `a` is removed.
487    ///
488    /// If the array is sorted, this removes all duplicates.
489    pub fn dedup_by<F>(&mut self, mut same_bucket: F)
490    where
491        F: FnMut(&T, &T) -> bool,
492    {
493        let len = self.len();
494        if len <= 1 {
495            return;
496        }
497
498        // Check if any duplicates exist to avoid allocating, copying, and
499        // deallocating memory if nothing needs to be removed.
500        let mut first_duplicate_idx: usize = 1;
501        while first_duplicate_idx != len {
502            let found_duplicate = {
503                let prev = self.raw_get(first_duplicate_idx - 1);
504                let current = self.raw_get(first_duplicate_idx);
505                same_bucket(current, prev)
506            };
507            if found_duplicate {
508                break;
509            }
510            first_duplicate_idx += 1;
511        }
512        if first_duplicate_idx == len {
513            return;
514        }
515
516        // duplicates exist, build a new array of only unique values; steal the
517        // old index and sizes, then clear the rest of the properties in order
518        // to start over
519        let index = std::mem::take(&mut self.index);
520        let old_l = self.l;
521        let mut remaining = self.count - 1;
522        self.count = 0;
523        self.clear();
524        let layout = Layout::array::<T>(old_l).expect("unexpected overflow");
525
526        // read the first value (we know there are at least two) to get the
527        // process started
528        let mut prev = unsafe { index[0].read() };
529        let mut slot = 1;
530        for buffer in index.into_iter() {
531            while slot < old_l {
532                let current = unsafe { buffer.add(slot).read() };
533                if same_bucket(&current, &prev) {
534                    drop(current);
535                } else {
536                    self.push(prev);
537                    prev = current;
538                }
539                remaining -= 1;
540                if remaining == 0 {
541                    break;
542                }
543                slot += 1;
544            }
545            unsafe {
546                dealloc(buffer as *mut u8, layout);
547            }
548            slot = 0;
549        }
550        // the last element always gets saved
551        self.push(prev);
552    }
553
554    /// Moves all the elements of `other` into `self`, leaving `other` empty.
555    pub fn append(&mut self, other: &mut Self) {
556        let index = std::mem::take(&mut other.index);
557        let mut remaining = other.count;
558        // prevent other from performing any dropping
559        other.count = 0;
560        let layout = Layout::array::<T>(other.l).expect("unexpected overflow");
561        for buffer in index.into_iter() {
562            for slot in 0..other.l {
563                let value = unsafe { buffer.add(slot).read() };
564                self.push(value);
565                remaining -= 1;
566                if remaining == 0 {
567                    break;
568                }
569            }
570            unsafe {
571                dealloc(buffer as *mut u8, layout);
572            }
573        }
574    }
575}
576
577impl<T> Default for HashedArrayTree<T> {
578    fn default() -> Self {
579        Self::new()
580    }
581}
582
583impl<T> fmt::Display for HashedArrayTree<T> {
584    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
585        write!(
586            f,
587            "HashedArrayTree(k: {}, count: {}, dope: {})",
588            self.k,
589            self.count,
590            self.index.len(),
591        )
592    }
593}
594
595impl<T> Index<usize> for HashedArrayTree<T> {
596    type Output = T;
597
598    fn index(&self, index: usize) -> &Self::Output {
599        let Some(item) = self.get(index) else {
600            panic!("index out of bounds: {}", index);
601        };
602        item
603    }
604}
605
606impl<T> IndexMut<usize> for HashedArrayTree<T> {
607    fn index_mut(&mut self, index: usize) -> &mut Self::Output {
608        let Some(item) = self.get_mut(index) else {
609            panic!("index out of bounds: {}", index);
610        };
611        item
612    }
613}
614
615impl<T> Drop for HashedArrayTree<T> {
616    fn drop(&mut self) {
617        self.clear();
618    }
619}
620
621impl<T: Clone> Clone for HashedArrayTree<T> {
622    fn clone(&self) -> Self {
623        let mut result = HashedArrayTree::<T>::new();
624        for value in self.iter() {
625            result.push(value.clone());
626        }
627        result
628    }
629}
630
631unsafe impl<T: Send> Send for HashedArrayTree<T> {}
632
633impl<A> FromIterator<A> for HashedArrayTree<A> {
634    fn from_iter<T: IntoIterator<Item = A>>(iter: T) -> Self {
635        let mut arr: HashedArrayTree<A> = HashedArrayTree::new();
636        for value in iter {
637            arr.push(value)
638        }
639        arr
640    }
641}
642
643/// Immutable hashed array tree iterator.
644pub struct ArrayIter<'a, T> {
645    array: &'a HashedArrayTree<T>,
646    index: usize,
647}
648
649impl<'a, T> Iterator for ArrayIter<'a, T> {
650    type Item = &'a T;
651
652    fn next(&mut self) -> Option<Self::Item> {
653        let value = self.array.get(self.index);
654        self.index += 1;
655        value
656    }
657}
658
659/// An iterator that moves out of a hashed array tree.
660pub struct ArrayIntoIter<T> {
661    index: usize,
662    k: usize,
663    k_mask: usize,
664    count: usize,
665    dope: Vec<*mut T>,
666}
667
668impl<T> Iterator for ArrayIntoIter<T> {
669    type Item = T;
670
671    fn next(&mut self) -> Option<Self::Item> {
672        if self.index < self.count {
673            let block = self.index >> self.k;
674            let slot = self.index & self.k_mask;
675            self.index += 1;
676            unsafe { Some((self.dope[block].add(slot)).read()) }
677        } else {
678            None
679        }
680    }
681}
682
683impl<T> IntoIterator for HashedArrayTree<T> {
684    type Item = T;
685    type IntoIter = ArrayIntoIter<Self::Item>;
686
687    fn into_iter(self) -> Self::IntoIter {
688        let mut me = std::mem::ManuallyDrop::new(self);
689        let dope = std::mem::take(&mut me.index);
690        ArrayIntoIter {
691            index: 0,
692            count: me.count,
693            k: me.k,
694            k_mask: me.k_mask,
695            dope,
696        }
697    }
698}
699
700impl<T> Drop for ArrayIntoIter<T> {
701    fn drop(&mut self) {
702        use std::ptr::{drop_in_place, slice_from_raw_parts_mut};
703        let block_len = 1 << self.k;
704
705        if std::mem::needs_drop::<T>() {
706            let first_block = self.index >> self.k;
707            let first_slot = self.index & self.k_mask;
708            let last_block = (self.count - 1) >> self.k;
709            let last_slot = (self.count - 1) & self.k_mask;
710            if first_block == last_block {
711                // special-case, remaining values are in only one leaf
712                if first_slot <= last_slot {
713                    unsafe {
714                        // last_slot is pointing at the last element, need to
715                        // add one to include it in the slice
716                        drop_in_place(slice_from_raw_parts_mut(
717                            self.dope[first_block].add(first_slot),
718                            last_slot - first_slot + 1,
719                        ));
720                    }
721                }
722            } else {
723                // drop the remaining values in the first leaf
724                if block_len < self.count {
725                    unsafe {
726                        drop_in_place(slice_from_raw_parts_mut(
727                            self.dope[first_block].add(first_slot),
728                            block_len - first_slot,
729                        ));
730                    }
731                }
732
733                // drop the values in the last leaf
734                unsafe {
735                    drop_in_place(slice_from_raw_parts_mut(
736                        self.dope[last_block],
737                        last_slot + 1,
738                    ));
739                }
740
741                // drop the values in all of the other leaves
742                for block in first_block + 1..last_block {
743                    unsafe {
744                        drop_in_place(slice_from_raw_parts_mut(self.dope[block], block_len));
745                    }
746                }
747            }
748        }
749
750        // deallocate all of the leaves
751        for block in 0..self.dope.len() {
752            let layout = Layout::array::<T>(block_len).expect("unexpected overflow");
753            unsafe {
754                dealloc(self.dope[block] as *mut u8, layout);
755            }
756        }
757    }
758}
759
760#[cfg(test)]
761mod tests {
762    use super::*;
763
764    #[test]
765    fn test_empty() {
766        let sut = HashedArrayTree::<usize>::new();
767        assert!(sut.get(0).is_none());
768    }
769
770    #[test]
771    #[should_panic(expected = "index out of bounds:")]
772    fn test_index_out_of_bounds() {
773        let mut sut: HashedArrayTree<i32> = HashedArrayTree::new();
774        sut.push(10);
775        sut.push(20);
776        let _ = sut[2];
777    }
778
779    #[test]
780    #[should_panic(expected = "index out of bounds:")]
781    fn test_index_mut_out_of_bounds() {
782        let mut sut: HashedArrayTree<i32> = HashedArrayTree::new();
783        sut.push(10);
784        sut.push(20);
785        sut[2] = 30;
786    }
787
788    #[test]
789    fn test_push_no_expand() {
790        // push few enough elements to avoid an expansion
791        let mut sut = HashedArrayTree::<usize>::new();
792        for value in 0..13 {
793            sut.push(value);
794        }
795        assert_eq!(sut.len(), 13);
796        assert_eq!(sut.capacity(), 16);
797        for value in 0..13 {
798            assert_eq!(sut[value], value);
799        }
800        // pop enough to cause the last leaf to be freed
801        sut.pop();
802        assert_eq!(sut.len(), 12);
803        assert_eq!(sut.capacity(), 12);
804    }
805
806    #[test]
807    fn test_push_with_expand() {
808        // push few enough elements to cause an expansion
809        let mut sut = HashedArrayTree::<usize>::new();
810        for value in 0..64 {
811            sut.push(value);
812        }
813        assert_eq!(sut.len(), 64);
814        assert_eq!(sut.capacity(), 64);
815        for value in 0..64 {
816            assert_eq!(sut[value], value);
817        }
818    }
819
820    #[test]
821    fn test_expand_and_compress() {
822        // add enough to cause multiple expansions
823        let mut sut = HashedArrayTree::<usize>::new();
824        for value in 0..1024 {
825            sut.push(value);
826        }
827        assert_eq!(sut.len(), 1024);
828        assert_eq!(sut.capacity(), 1024);
829        // remove enough to cause multiple compressions
830        for _ in 0..960 {
831            sut.pop();
832        }
833        // ensure the correct elements remain
834        assert_eq!(sut.len(), 64);
835        assert_eq!(sut.capacity(), 64);
836        for value in 0..64 {
837            assert_eq!(sut[value], value);
838        }
839    }
840
841    #[test]
842    fn test_push_get_get_mut() {
843        let mut sut = HashedArrayTree::<usize>::new();
844        for value in 0..12 {
845            sut.push(value);
846        }
847        assert_eq!(sut.get(2), Some(&2));
848        if let Some(value) = sut.get_mut(1) {
849            *value = 11;
850        } else {
851            panic!("get_mut() returned None")
852        }
853        assert_eq!(sut[0], 0);
854        assert_eq!(sut[1], 11);
855        assert_eq!(sut[2], 2);
856    }
857
858    #[test]
859    fn test_push_within_capacity() {
860        // empty array has no allocated space
861        let mut sut = HashedArrayTree::<u32>::new();
862        assert_eq!(sut.push_within_capacity(101), Err(101));
863        // will have 4 slots after a single allocation
864        sut.push(1);
865        sut.push(2);
866        assert_eq!(sut.push_within_capacity(3), Ok(()));
867        assert_eq!(sut.push_within_capacity(4), Ok(()));
868        assert_eq!(sut.push_within_capacity(5), Err(5));
869    }
870
871    #[test]
872    fn test_pop_small() {
873        let mut sut = HashedArrayTree::<usize>::new();
874        assert!(sut.is_empty());
875        assert_eq!(sut.len(), 0);
876        for value in 0..15 {
877            sut.push(value);
878        }
879        assert!(!sut.is_empty());
880        assert_eq!(sut.len(), 15);
881        for value in (0..15).rev() {
882            assert_eq!(sut.pop(), Some(value));
883        }
884        assert!(sut.is_empty());
885        assert_eq!(sut.len(), 0);
886        assert_eq!(sut.capacity(), 0);
887    }
888
889    #[test]
890    fn test_pop_if() {
891        let mut sut = HashedArrayTree::<u32>::new();
892        assert!(sut.pop_if(|_| panic!("should not be called")).is_none());
893        for value in 0..10 {
894            sut.push(value);
895        }
896        assert!(sut.pop_if(|_| false).is_none());
897        let maybe = sut.pop_if(|v| *v == 9);
898        assert_eq!(maybe.unwrap(), 9);
899        assert!(sut.pop_if(|v| *v == 9).is_none());
900    }
901
902    #[test]
903    fn test_clear_and_reuse_ints() {
904        let mut sut: HashedArrayTree<i32> = HashedArrayTree::new();
905        for value in 0..512 {
906            sut.push(value);
907        }
908        assert_eq!(sut.len(), 512);
909        sut.clear();
910        assert_eq!(sut.len(), 0);
911        for value in 0..512 {
912            sut.push(value);
913        }
914        for idx in 0..512 {
915            let maybe = sut.get(idx);
916            assert!(maybe.is_some(), "{idx} is none");
917            let actual = maybe.unwrap();
918            assert_eq!(idx, *actual as usize);
919        }
920    }
921
922    #[test]
923    fn test_clear_and_reuse_strings() {
924        let mut sut: HashedArrayTree<String> = HashedArrayTree::new();
925        for _ in 0..512 {
926            let value = ulid::Ulid::new().to_string();
927            sut.push(value);
928        }
929        assert_eq!(sut.len(), 512);
930        sut.clear();
931        assert_eq!(sut.len(), 0);
932        for _ in 0..512 {
933            let value = ulid::Ulid::new().to_string();
934            sut.push(value);
935        }
936        assert_eq!(sut.len(), 512);
937        // implicitly drop()
938    }
939
940    #[test]
941    fn test_clone_ints() {
942        let mut sut = HashedArrayTree::<usize>::new();
943        for value in 0..512 {
944            sut.push(value);
945        }
946        let cloned = sut.clone();
947        let ai = sut.iter();
948        let bi = cloned.iter();
949        for (a, b) in ai.zip(bi) {
950            assert_eq!(a, b);
951        }
952    }
953
954    #[test]
955    fn test_clone_strings() {
956        let mut sut = HashedArrayTree::<String>::new();
957        for _ in 0..64 {
958            let value = ulid::Ulid::new().to_string();
959            sut.push(value);
960        }
961        let cloned = sut.clone();
962        let ai = sut.iter();
963        let bi = cloned.iter();
964        for (a, b) in ai.zip(bi) {
965            assert_eq!(a, b);
966        }
967    }
968
969    #[test]
970    fn test_swap() {
971        let mut sut = HashedArrayTree::<usize>::new();
972        sut.push(1);
973        sut.push(2);
974        sut.push(3);
975        sut.push(4);
976        sut.swap(1, 3);
977        assert_eq!(sut[0], 1);
978        assert_eq!(sut[1], 4);
979        assert_eq!(sut[2], 3);
980        assert_eq!(sut[3], 2);
981    }
982
983    #[test]
984    #[should_panic(expected = "swap a (is 1) should be < len (is 1)")]
985    fn test_swap_panic_a() {
986        let mut sut = HashedArrayTree::<usize>::new();
987        sut.push(1);
988        sut.swap(1, 2);
989    }
990
991    #[test]
992    #[should_panic(expected = "swap b (is 1) should be < len (is 1)")]
993    fn test_swap_panic_b() {
994        let mut sut = HashedArrayTree::<usize>::new();
995        sut.push(1);
996        sut.swap(0, 1);
997    }
998
999    #[test]
1000    fn test_sort_unstable_by_ints() {
1001        let mut sut = HashedArrayTree::<usize>::new();
1002        sut.push(10);
1003        sut.push(1);
1004        sut.push(100);
1005        sut.push(20);
1006        sut.push(2);
1007        sut.push(99);
1008        sut.push(88);
1009        sut.push(77);
1010        sut.push(66);
1011        sut.sort_unstable_by(|a, b| a.cmp(b));
1012        assert_eq!(sut[0], 1);
1013        assert_eq!(sut[1], 2);
1014        assert_eq!(sut[2], 10);
1015        assert_eq!(sut[3], 20);
1016        assert_eq!(sut[4], 66);
1017        assert_eq!(sut[5], 77);
1018        assert_eq!(sut[6], 88);
1019        assert_eq!(sut[7], 99);
1020        assert_eq!(sut[8], 100);
1021    }
1022
1023    #[test]
1024    fn test_sort_unstable_by_strings() {
1025        let mut sut = HashedArrayTree::<String>::new();
1026        sut.push("cat".into());
1027        sut.push("ape".into());
1028        sut.push("zebra".into());
1029        sut.push("dog".into());
1030        sut.push("bird".into());
1031        sut.push("tapir".into());
1032        sut.push("monkey".into());
1033        sut.push("giraffe".into());
1034        sut.push("frog".into());
1035        sut.sort_unstable_by(|a, b| a.cmp(b));
1036        assert_eq!(sut[0], "ape");
1037        assert_eq!(sut[1], "bird");
1038        assert_eq!(sut[2], "cat");
1039        assert_eq!(sut[3], "dog");
1040        assert_eq!(sut[4], "frog");
1041        assert_eq!(sut[5], "giraffe");
1042        assert_eq!(sut[6], "monkey");
1043        assert_eq!(sut[7], "tapir");
1044        assert_eq!(sut[8], "zebra");
1045    }
1046
1047    #[test]
1048    fn test_append() {
1049        let odds = ["one", "three", "five", "seven", "nine"];
1050        let mut sut = HashedArrayTree::<String>::new();
1051        for item in odds {
1052            sut.push(item.to_owned());
1053        }
1054        let evens = ["two", "four", "six", "eight", "ten"];
1055        let mut other = HashedArrayTree::<String>::new();
1056        for item in evens {
1057            other.push(item.to_owned());
1058        }
1059        sut.append(&mut other);
1060        assert_eq!(sut.len(), 10);
1061        assert_eq!(sut.capacity(), 12);
1062        assert_eq!(other.len(), 0);
1063        assert_eq!(other.capacity(), 0);
1064        sut.sort_unstable_by(|a, b| a.cmp(b));
1065        assert_eq!(sut[0], "eight");
1066        assert_eq!(sut[1], "five");
1067        assert_eq!(sut[2], "four");
1068        assert_eq!(sut[3], "nine");
1069        assert_eq!(sut[4], "one");
1070        assert_eq!(sut[5], "seven");
1071        assert_eq!(sut[6], "six");
1072        assert_eq!(sut[7], "ten");
1073        assert_eq!(sut[8], "three");
1074        assert_eq!(sut[9], "two");
1075    }
1076
1077    #[test]
1078    fn test_dedup_by_tiny() {
1079        let mut sut = HashedArrayTree::<String>::new();
1080        sut.push("one".into());
1081        sut.dedup_by(|a, b| a == b);
1082        assert_eq!(sut.len(), 1);
1083        assert_eq!(sut[0], "one");
1084    }
1085
1086    #[test]
1087    fn test_dedup_by_2_dupes() {
1088        let mut sut = HashedArrayTree::<String>::new();
1089        sut.push("one".into());
1090        sut.push("one".into());
1091        sut.dedup_by(|a, b| a == b);
1092        assert_eq!(sut.len(), 1);
1093        assert_eq!(sut[0], "one");
1094    }
1095
1096    #[test]
1097    fn test_dedup_by_2_unique() {
1098        let mut sut = HashedArrayTree::<String>::new();
1099        sut.push("one".into());
1100        sut.push("two".into());
1101        sut.dedup_by(|a, b| a == b);
1102        assert_eq!(sut.len(), 2);
1103        assert_eq!(sut[0], "one");
1104        assert_eq!(sut[1], "two");
1105    }
1106
1107    #[test]
1108    fn test_dedup_by_all_unique() {
1109        let inputs = [
1110            "one", "two", "three", "four", "five", "six", "seven", "eight", "nine",
1111        ];
1112        let mut sut = HashedArrayTree::<String>::new();
1113        for item in inputs {
1114            sut.push(item.to_owned());
1115        }
1116        sut.dedup_by(|a, b| a == b);
1117        assert_eq!(sut.len(), 9);
1118        for (idx, elem) in sut.into_iter().enumerate() {
1119            assert_eq!(inputs[idx], elem);
1120        }
1121    }
1122
1123    #[test]
1124    fn test_dedup_by_all_dupes() {
1125        let inputs = [
1126            "one", "one", "one", "one", "one", "one", "one", "one", "one", "one",
1127        ];
1128        let mut sut = HashedArrayTree::<String>::new();
1129        for item in inputs {
1130            sut.push(item.to_owned());
1131        }
1132        assert_eq!(sut.len(), 10);
1133        sut.dedup_by(|a, b| a == b);
1134        assert_eq!(sut.len(), 1);
1135        assert_eq!(inputs[0], "one");
1136    }
1137
1138    #[test]
1139    fn test_dedup_by_some_dupes_ints() {
1140        let inputs = [1, 2, 2, 3, 2];
1141        let mut sut = HashedArrayTree::<usize>::new();
1142        for item in inputs {
1143            sut.push(item.to_owned());
1144        }
1145        assert_eq!(sut.len(), 5);
1146        sut.dedup_by(|a, b| a == b);
1147        assert_eq!(sut.len(), 4);
1148        assert_eq!(sut[0], 1);
1149        assert_eq!(sut[1], 2);
1150        assert_eq!(sut[2], 3);
1151        assert_eq!(sut[3], 2);
1152    }
1153
1154    #[test]
1155    fn test_dedup_by_some_dupes_strings() {
1156        let inputs = ["foo", "bar", "Bar", "baz", "bar"];
1157        let mut sut = HashedArrayTree::<String>::new();
1158        for item in inputs {
1159            sut.push(item.to_owned());
1160        }
1161        assert_eq!(sut.len(), 5);
1162        sut.dedup_by(|a, b| a.eq_ignore_ascii_case(b));
1163        assert_eq!(sut.len(), 4);
1164        assert_eq!(sut[0], "foo");
1165        assert_eq!(sut[1], "bar");
1166        assert_eq!(sut[2], "baz");
1167        assert_eq!(sut[3], "bar");
1168    }
1169
1170    #[test]
1171    fn test_from_iterator() {
1172        let mut inputs: Vec<i32> = Vec::new();
1173        for value in 0..10_000 {
1174            inputs.push(value);
1175        }
1176        let sut: HashedArrayTree<i32> = inputs.into_iter().collect();
1177        assert_eq!(sut.len(), 10_000);
1178        for idx in 0..10_000i32 {
1179            let maybe = sut.get(idx as usize);
1180            assert!(maybe.is_some(), "{idx} is none");
1181            let actual = maybe.unwrap();
1182            assert_eq!(idx, *actual);
1183        }
1184    }
1185
1186    #[test]
1187    fn test_iterator() {
1188        let mut sut = HashedArrayTree::<usize>::new();
1189        for value in 0..512 {
1190            sut.push(value);
1191        }
1192        assert_eq!(sut.len(), 512);
1193        for (idx, elem) in sut.iter().enumerate() {
1194            assert_eq!(sut[idx], *elem);
1195        }
1196    }
1197
1198    #[test]
1199    fn test_into_iterator() {
1200        // an array that only requires a single segment
1201        let inputs = [
1202            "one", "two", "three", "four", "five", "six", "seven", "eight", "nine",
1203        ];
1204        let mut sut: HashedArrayTree<String> = HashedArrayTree::new();
1205        for item in inputs {
1206            sut.push(item.to_owned());
1207        }
1208        for (idx, elem) in sut.into_iter().enumerate() {
1209            assert_eq!(inputs[idx], elem);
1210        }
1211        // sut.len(); // error: ownership of sut was moved
1212    }
1213
1214    #[test]
1215    fn test_into_iterator_drop_tiny() {
1216        // an array that only requires a single segment and only some need to be
1217        // dropped after partially iterating the values
1218        let inputs = [
1219            "one", "two", "three", "four", "five", "six", "seven", "eight", "nine",
1220        ];
1221        let mut sut: HashedArrayTree<String> = HashedArrayTree::new();
1222        for item in inputs {
1223            sut.push(item.to_owned());
1224        }
1225        for (idx, _) in sut.into_iter().enumerate() {
1226            if idx > 2 {
1227                break;
1228            }
1229        }
1230        // implicitly drop()
1231    }
1232
1233    #[test]
1234    fn test_into_iterator_drop_large() {
1235        // by adding 512 values and iterating less than 64 times, there will be
1236        // values in the first segment and some in the last segment, and two
1237        // segments inbetween that all need to be dropped
1238        let mut sut: HashedArrayTree<String> = HashedArrayTree::new();
1239        for _ in 0..512 {
1240            let value = ulid::Ulid::new().to_string();
1241            sut.push(value);
1242        }
1243        for (idx, _) in sut.into_iter().enumerate() {
1244            if idx >= 30 {
1245                break;
1246            }
1247        }
1248        // implicitly drop()
1249    }
1250
1251    #[test]
1252    fn test_swap_remove_single_segment() {
1253        let mut sut: HashedArrayTree<u32> = HashedArrayTree::new();
1254        sut.push(1);
1255        sut.push(2);
1256        assert_eq!(sut.len(), 2);
1257        let one = sut.swap_remove(0);
1258        assert_eq!(one, 1);
1259        assert_eq!(sut[0], 2);
1260    }
1261
1262    #[test]
1263    fn test_swap_remove_prune_empty() {
1264        let mut sut: HashedArrayTree<u32> = HashedArrayTree::new();
1265        for value in 0..13 {
1266            sut.push(value);
1267        }
1268        assert_eq!(sut.len(), 13);
1269        assert_eq!(sut.capacity(), 16);
1270        let value = sut.swap_remove(8);
1271        assert_eq!(value, 8);
1272        assert_eq!(sut[8], 12);
1273        assert_eq!(sut.len(), 12);
1274        assert_eq!(sut.capacity(), 12);
1275    }
1276
1277    #[test]
1278    fn test_swap_remove_multiple_segments() {
1279        let mut sut: HashedArrayTree<u32> = HashedArrayTree::new();
1280        for value in 0..512 {
1281            sut.push(value);
1282        }
1283        assert_eq!(sut.len(), 512);
1284        let eighty = sut.swap_remove(80);
1285        assert_eq!(eighty, 80);
1286        assert_eq!(sut.pop(), Some(510));
1287        assert_eq!(sut[80], 511);
1288    }
1289
1290    #[test]
1291    #[should_panic(expected = "swap_remove index (is 0) should be < len (is 0)")]
1292    fn test_swap_remove_panic_empty() {
1293        let mut sut: HashedArrayTree<u32> = HashedArrayTree::new();
1294        sut.swap_remove(0);
1295    }
1296
1297    #[test]
1298    #[should_panic(expected = "swap_remove index (is 1) should be < len (is 1)")]
1299    fn test_swap_remove_panic_range_edge() {
1300        let mut sut: HashedArrayTree<u32> = HashedArrayTree::new();
1301        sut.push(1);
1302        sut.swap_remove(1);
1303    }
1304
1305    #[test]
1306    #[should_panic(expected = "swap_remove index (is 2) should be < len (is 1)")]
1307    fn test_swap_remove_panic_range_exceed() {
1308        let mut sut: HashedArrayTree<u32> = HashedArrayTree::new();
1309        sut.push(1);
1310        sut.swap_remove(2);
1311    }
1312
1313    #[test]
1314    fn test_push_get_many_instances_ints() {
1315        // test allocating, filling, and then dropping many instances
1316        for _ in 0..1_000 {
1317            let mut sut: HashedArrayTree<usize> = HashedArrayTree::new();
1318            for value in 0..10_000 {
1319                sut.push(value);
1320            }
1321            assert_eq!(sut.len(), 10_000);
1322        }
1323    }
1324
1325    #[test]
1326    fn test_push_get_many_instances_strings() {
1327        // test allocating, filling, and then dropping many instances
1328        for _ in 0..1_000 {
1329            let mut sut: HashedArrayTree<String> = HashedArrayTree::new();
1330            for _ in 0..1_000 {
1331                let value = ulid::Ulid::new().to_string();
1332                sut.push(value);
1333            }
1334            assert_eq!(sut.len(), 1_000);
1335        }
1336    }
1337}