rpds/map/hash_trie_map/
mod.rs

1mod sparse_array_usize;
2
3use super::entry::Entry;
4use crate::List;
5use crate::list;
6use crate::utils::DefaultBuildHasher;
7use alloc::vec::Vec;
8use archery::{ArcTK, RcK, SharedPointer, SharedPointerKind};
9use core::borrow::Borrow;
10use core::fmt::Display;
11use core::hash::BuildHasher;
12use core::hash::Hash;
13use core::iter;
14use core::iter::FromIterator;
15use core::ops::Index;
16use core::slice;
17use sparse_array_usize::SparseArrayUsize;
18
19type HashValue = u64;
20
21// TODO Use impl trait instead of this when available.
22pub type Iter<'a, K, V, P> =
23    iter::Map<IterPtr<'a, K, V, P>, fn(&'a SharedPointer<Entry<K, V>, P>) -> (&'a K, &'a V)>;
24pub type IterKeys<'a, K, V, P> = iter::Map<Iter<'a, K, V, P>, fn((&'a K, &V)) -> &'a K>;
25pub type IterValues<'a, K, V, P> = iter::Map<Iter<'a, K, V, P>, fn((&K, &'a V)) -> &'a V>;
26
27#[allow(clippy::cast_possible_truncation)]
28const DEFAULT_DEGREE: u8 = usize::BITS as u8;
29
30/// Creates a [`HashTrieMap`](crate::HashTrieMap) containing the given arguments:
31///
32/// ```
33/// # use rpds::*;
34/// #
35/// let m = HashTrieMap::new()
36///     .insert(1, "one")
37///     .insert(2, "two")
38///     .insert(3, "three");
39///
40/// assert_eq!(ht_map![1 => "one", 2 => "two", 3 => "three"], m);
41/// ```
42#[macro_export]
43macro_rules! ht_map {
44    ($($k:expr => $v:expr),*) => {
45        {
46            #[allow(unused_mut)]
47            let mut m = $crate::HashTrieMap::new();
48            $(
49                m.insert_mut($k, $v);
50            )*
51            m
52        }
53    };
54}
55
56/// Creates a [`HashTrieMap`](crate::HashTrieMap) that implements `Sync`, containing the given
57/// arguments:
58///
59/// ```
60/// # use rpds::*;
61/// #
62/// let m = HashTrieMap::new_sync()
63///     .insert(1, "one")
64///     .insert(2, "two")
65///     .insert(3, "three");
66///
67/// assert_eq!(ht_map_sync![1 => "one", 2 => "two", 3 => "three"], m);
68/// ```
69#[macro_export]
70macro_rules! ht_map_sync {
71    ($($k:expr => $v:expr),*) => {
72        {
73            #[allow(unused_mut)]
74            let mut m = $crate::HashTrieMap::new_sync();
75            $(
76                m.insert_mut($k, $v);
77            )*
78            m
79        }
80    };
81}
82
83/// A persistent map with structural sharing.  This implementation uses a
84/// [hash array mapped trie](https://en.wikipedia.org/wiki/Hash_array_mapped_trie).
85///
86/// # Complexity
87///
88/// Let *n* be the number of elements in the map.
89///
90/// ## Temporal complexity
91///
92/// | Operation                  | Average   | Worst case  |
93/// |:-------------------------- | ---------:| -----------:|
94/// | `new()`                    |      Θ(1) |        Θ(1) |
95/// | `insert()`                 |      Θ(1) |        Θ(n) |
96/// | `remove()`                 |      Θ(1) |        Θ(n) |
97/// | `get()`                    |      Θ(1) |        Θ(n) |
98/// | `contains_key()`           |      Θ(1) |        Θ(n) |
99/// | `size()`                   |      Θ(1) |        Θ(1) |
100/// | `clone()`                  |      Θ(1) |        Θ(1) |
101/// | iterator creation          |      Θ(1) |        Θ(1) |
102/// | iterator step              |      Θ(1) |        Θ(1) |
103/// | iterator full              |      Θ(n) |        Θ(n) |
104///
105/// # Implementation details
106///
107/// This implementation uses a
108/// [hash array mapped trie](https://en.wikipedia.org/wiki/Hash_array_mapped_trie).
109/// Details can be found in
110/// [Ideal Hash Trees](https://infoscience.epfl.ch/record/64398/files/idealhashtrees.pdf).
111///
112/// See the `Node` documentation for details.
113#[derive(Debug)]
114pub struct HashTrieMap<K, V, P = RcK, H: BuildHasher = DefaultBuildHasher>
115where
116    P: SharedPointerKind,
117{
118    root: SharedPointer<Node<K, V, P>, P>,
119    size: usize,
120    degree: u8,
121    hasher_builder: H,
122}
123
124pub type HashTrieMapSync<K, V, H = DefaultBuildHasher> = HashTrieMap<K, V, ArcTK, H>;
125
126/// This map works like a trie that breaks the hash of the key in segments, and the segments are
127/// used as the index in the trie branches.
128///
129/// Consider the following example, where we have a tree with degree 16 (e.g. each level uses 4
130/// bits of the hash) and the following mapping between keys and their hashes:
131///
132/// | *key*   | *hash(key)*                       |
133/// | ------- | ---------------------------------:|
134/// |   *A*   | `0b_0000_0000_···_0000_0010_0110` |
135/// |   *B*   | `0b_0000_0000_···_0000_0001_0110` |
136/// |   *C*   | `0b_0000_0000_···_0000_0100_0010` |
137/// |   *D*   | `0b_0111_0000_···_0000_0000_1000` |
138/// |   *E*   | `0b_0111_0000_···_0000_0000_1000` |
139///
140/// Then the tree will look like this:
141///
142/// ```text
143///        0  ···  2  ···  6  ···  8  ···
144///      ├───┼───┼───┼───┼───┼───┼───┼───┤
145///      │ ∅ │ ∅ │ C │ ∅ │ • │ ∅ │ • │ ∅ │                depth 0
146///      └───┴───┴───┴───┴─│─┴───┴─│─┴───┘
147///                       ╱         ╲
148///                      ╱           ╲
149///                     ╱             ╲
150///         0   1   2  ···            0   1   2  ···
151///       ├───┼───┼───┼───┤         ├───┼───┼───┼───┤
152///       │ ∅ │ B │ A │ ∅ │         │ • │ ∅ │ ∅ │ ∅ │     depth 1
153///       └───┴───┴───┴───┘         └─│─┴───┴───┴───┘
154///                                   │
155///                                   ·
156///                                   ·
157///                                   ·
158///                                   │
159///                            0  ···   7   ···
160///                          ├───┼───┼─────┼───┤
161///                          │ ∅ │ ∅ │ D E │ ∅ │          depth 16 (maximum depth)
162///                          └───┴───┴─────┴───┘
163/// ```
164///
165/// Note that we stop the insertion process early when possible.  In the example above we did not
166/// had to expand the tree any further to accommodate *C*, since there is no other entry with a
167/// hash that starts with `0b0010`.  The entries *A* and *B* exemplifies the case where a single
168/// level is not enough because their hash both start with `0b0110`.  In case of a full hash
169/// collision we dig through all the levels of the tree so we get to the final leaf where a
170/// collision exists, like we can see in the case of *D* and *E*.
171///
172/// # Invariants
173///
174/// The tree has the following invariants (among others):
175///
176///   1. The root is the only node that can have zero children.
177///   2. A node with a collision can only exist at the maximum depth of the tree.
178///   3. A non-root branch always have two or more entries under it (because it could be
179///      compressed).
180#[derive(Debug)]
181enum Node<K, V, P = RcK>
182where
183    P: SharedPointerKind,
184{
185    Branch(SparseArrayUsize<SharedPointer<Node<K, V, P>, P>>),
186    Leaf(Bucket<K, V, P>),
187}
188
189#[derive(Debug)]
190enum Bucket<K, V, P = RcK>
191where
192    P: SharedPointerKind,
193{
194    Single(EntryWithHash<K, V, P>),
195    Collision(List<EntryWithHash<K, V, P>, P>),
196}
197
198#[derive(Debug)]
199struct EntryWithHash<K, V, P = RcK>
200where
201    P: SharedPointerKind,
202{
203    entry: SharedPointer<Entry<K, V>, P>,
204    key_hash: HashValue,
205}
206
207mod node_utils {
208    use super::HashValue;
209    use core::hash::BuildHasher;
210    use core::hash::Hash;
211    use core::mem::size_of_val;
212
213    /// Returns the index of the array for the given hash on depth `depth`.
214    ///
215    /// When the hash is exhausted, meaning that we are at the maximum depth, this returns `None`.
216    #[inline]
217    pub fn index_from_hash(hash: HashValue, depth: usize, degree: u8) -> Option<usize> {
218        debug_assert!(degree.is_power_of_two());
219
220        #[allow(clippy::cast_possible_truncation)]
221        let shift = depth as u32 * degree.trailing_zeros();
222
223        #[allow(clippy::cast_lossless)]
224        if (shift as usize) < 8 * size_of_val(&hash) {
225            let mask = degree as HashValue - 1;
226            #[allow(clippy::cast_possible_truncation)]
227            Some(((hash >> shift) & mask) as usize)
228        } else {
229            None
230        }
231    }
232
233    pub fn hash<T: ?Sized + Hash, H: BuildHasher>(v: &T, hasher_builder: &H) -> HashValue {
234        hasher_builder.hash_one(v)
235    }
236}
237
238impl<K, V, P> Node<K, V, P>
239where
240    K: Eq + Hash,
241    P: SharedPointerKind,
242{
243    fn new_empty_branch() -> Node<K, V, P> {
244        Node::Branch(SparseArrayUsize::new())
245    }
246
247    fn get<Q: ?Sized>(
248        &self,
249        key: &Q,
250        key_hash: HashValue,
251        depth: usize,
252        degree: u8,
253    ) -> Option<&EntryWithHash<K, V, P>>
254    where
255        K: Borrow<Q>,
256        Q: Hash + Eq,
257    {
258        match self {
259            Node::Branch(subtrees) => {
260                let index: usize = node_utils::index_from_hash(key_hash, depth, degree)
261                    .expect("hash cannot be exhausted if we are on a branch");
262
263                subtrees
264                    .get(index)
265                    .and_then(|subtree| subtree.get(key, key_hash, depth + 1, degree))
266            }
267            Node::Leaf(bucket) => bucket.get(key, key_hash),
268        }
269    }
270
271    fn get_mut<Q: ?Sized>(
272        &mut self,
273        key: &Q,
274        key_hash: HashValue,
275        depth: usize,
276        degree: u8,
277    ) -> Option<&mut EntryWithHash<K, V, P>>
278    where
279        K: Borrow<Q>,
280        Q: Hash + Eq,
281    {
282        match self {
283            Node::Branch(subtrees) => {
284                let index: usize = node_utils::index_from_hash(key_hash, depth, degree)
285                    .expect("hash cannot be exhausted if we are on a branch");
286
287                subtrees.get_mut(index).and_then(|subtree| {
288                    SharedPointer::make_mut(subtree).get_mut(key, key_hash, depth + 1, degree)
289                })
290            }
291            Node::Leaf(bucket) => bucket.get_mut(key, key_hash),
292        }
293    }
294
295    /// Returns a pair with the node with the new entry and whether the key is new.
296    fn insert(&mut self, entry: EntryWithHash<K, V, P>, depth: usize, degree: u8) -> bool {
297        match self {
298            Node::Branch(subtrees) => {
299                let index: usize = node_utils::index_from_hash(entry.key_hash, depth, degree)
300                    .expect("hash cannot be exhausted if we are on a branch");
301
302                match subtrees.get_mut(index) {
303                    Some(subtree) => {
304                        SharedPointer::make_mut(subtree).insert(entry, depth + 1, degree)
305                    }
306
307                    None => {
308                        let new_subtree = Node::Leaf(Bucket::Single(entry));
309                        subtrees.set(index, SharedPointer::new(new_subtree));
310                        true
311                    }
312                }
313            }
314            Node::Leaf(bucket) => {
315                // If we are at maximum depth then the hash was totally consumed and we have a
316                // collision.
317                let maximum_depth =
318                    node_utils::index_from_hash(entry.key_hash, depth, degree).is_none();
319
320                let bucket_contains_key: bool = bucket.contains_key(entry.key(), entry.key_hash);
321
322                match maximum_depth {
323                    // We reached a bucket.  If the bucket contains the key we are inserting then
324                    // we just need to replace it.
325                    false if bucket_contains_key => bucket.insert(entry),
326
327                    // We reached a bucket and the key we will insert is not there.  We need to
328                    // create a `Node::Branch` and insert the elements of the bucket there, as well
329                    // as the new element.
330                    false => {
331                        // TODO This clone should not be needed.
332                        let old_entry: EntryWithHash<K, V, P> = match bucket {
333                            Bucket::Single(e) => e.clone(),
334                            Bucket::Collision(_) => unreachable!(
335                                "hash is not exhausted, so there cannot be a collision here"
336                            ),
337                        };
338
339                        *self = Node::new_empty_branch();
340
341                        self.insert(old_entry, depth, degree);
342                        self.insert(entry, depth, degree);
343
344                        true
345                    }
346
347                    // Hash was already totally consumed.  This is a collision.
348                    true => bucket.insert(entry),
349                }
350            }
351        }
352    }
353
354    /// Compresses a node.  This makes the shallowest tree that is well-formed, i.e. branches with
355    /// a single entry become a leaf with it.
356    fn compress(&mut self) {
357        let new_node = match self {
358            Node::Branch(subtrees) => {
359                match subtrees.size() {
360                    1 => {
361                        let compress: bool = {
362                            let subtree = subtrees.first().unwrap();
363
364                            // Keep collision at the bottom of the tree.
365                            matches!(subtree.borrow(), Node::Leaf(Bucket::Single(_)))
366                        };
367
368                        match compress {
369                            true => subtrees.pop(),
370                            false => None,
371                        }
372                    }
373                    _ => None,
374                }
375            }
376            Node::Leaf(_) => None,
377        };
378
379        if let Some(node) = new_node {
380            crate::utils::replace(self, node);
381        }
382    }
383
384    /// Returns `true` if the key was present.
385    fn remove<Q: ?Sized>(&mut self, key: &Q, key_hash: HashValue, depth: usize, degree: u8) -> bool
386    where
387        K: Borrow<Q>,
388        Q: Hash + Eq,
389    {
390        match self {
391            Node::Branch(subtrees) => {
392                let index: usize = node_utils::index_from_hash(key_hash, depth, degree)
393                    .expect("hash cannot be exhausted if we are on a branch");
394
395                match subtrees.get_mut(index) {
396                    Some(subtree) => {
397                        let subtree = SharedPointer::make_mut(subtree);
398                        let removed = subtree.remove(key, key_hash, depth + 1, degree);
399
400                        match (subtree.is_empty(), removed) {
401                            (_, false) => (),
402                            (false, true) => {
403                                // Note that we still must call compress because it is possible that
404                                // we had a node with just one entry, which was not compressed
405                                // because it had a collision.  Maybe now we do not have a collision
406                                // and we can compress it.
407                                self.compress();
408                            }
409                            (true, true) => {
410                                subtrees.remove(index);
411
412                                self.compress();
413                            }
414                        }
415
416                        removed
417                    }
418
419                    None => false,
420                }
421            }
422
423            Node::Leaf(bucket) => {
424                let mut bucket_ref = Some(bucket);
425                let removed = Bucket::remove(&mut bucket_ref, key, key_hash);
426
427                if bucket_ref.is_none() {
428                    // TODO Most of these empty branches will be dropped very soon.  We might
429                    //      gain some speed if we avoid this.  (However, currently no heap
430                    //      allocation happens anyway.)
431                    //      We can do something similar to Bucket::remove() where we receive
432                    //      a `&mut Option<&mut Bucket<_, _>>`.
433                    *self = Node::new_empty_branch();
434                }
435
436                removed
437            }
438        }
439    }
440
441    fn is_empty(&self) -> bool {
442        match self {
443            Node::Branch(subtrees) => subtrees.size() == 0,
444            Node::Leaf(Bucket::Single(_)) => false,
445            Node::Leaf(Bucket::Collision(entries)) => {
446                debug_assert!(entries.len() >= 2, "collisions must have at least two entries");
447                false
448            }
449        }
450    }
451}
452
453impl<K, V, P> Clone for Node<K, V, P>
454where
455    K: Eq + Hash,
456    P: SharedPointerKind,
457{
458    fn clone(&self) -> Node<K, V, P> {
459        match self {
460            Node::Branch(subtrees) => Node::Branch(subtrees.clone()),
461            Node::Leaf(bucket) => Node::Leaf(bucket.clone()),
462        }
463    }
464}
465
466mod bucket_utils {
467    use super::*;
468
469    pub fn list_remove_first<T: Clone, P: SharedPointerKind, F: Fn(&T) -> bool>(
470        list: &mut List<T, P>,
471        predicate: F,
472    ) -> Option<T> {
473        let mut before_needle: Vec<T> = Vec::with_capacity(list.len());
474        let remaining: &mut List<T, P> = list;
475        let mut removed = None;
476
477        while !remaining.is_empty() {
478            let e: T = remaining.first().unwrap().clone();
479
480            remaining.drop_first_mut();
481
482            if predicate(&e) {
483                removed = Some(e);
484                break;
485            }
486
487            before_needle.push(e);
488        }
489
490        let new_entries = remaining;
491
492        while let Some(e) = before_needle.pop() {
493            new_entries.push_front_mut(e);
494        }
495
496        removed
497    }
498}
499
500impl<K, V, P> Bucket<K, V, P>
501where
502    K: Eq + Hash,
503    P: SharedPointerKind,
504{
505    fn get<Q: ?Sized>(&self, key: &Q, key_hash: HashValue) -> Option<&EntryWithHash<K, V, P>>
506    where
507        K: Borrow<Q>,
508        Q: Hash + Eq,
509    {
510        match self {
511            Bucket::Single(entry) if entry.matches(key, key_hash) => Some(entry),
512            Bucket::Single(_) => None,
513            Bucket::Collision(entries) => entries.iter().find(|e| e.matches(key, key_hash)),
514        }
515    }
516
517    fn get_mut<Q: ?Sized>(
518        &mut self,
519        key: &Q,
520        key_hash: HashValue,
521    ) -> Option<&mut EntryWithHash<K, V, P>>
522    where
523        K: Borrow<Q>,
524        Q: Hash + Eq,
525    {
526        match self {
527            Bucket::Single(entry) if entry.matches(key, key_hash) => Some(entry),
528            Bucket::Single(_) => None,
529            Bucket::Collision(entries) => {
530                let removed =
531                    bucket_utils::list_remove_first(entries, |e| e.matches(key, key_hash));
532                removed.and_then(|e| {
533                    entries.push_front_mut(e);
534                    entries.first_mut()
535                })
536            }
537        }
538    }
539
540    #[inline]
541    fn contains_key<Q: ?Sized>(&self, key: &Q, key_hash: HashValue) -> bool
542    where
543        K: Borrow<Q>,
544        Q: Hash + Eq,
545    {
546        self.get(key, key_hash).is_some()
547    }
548
549    /// Returns `true` if the key is new.
550    ///
551    /// If there is a collision then `entry` will be put on the front of the entries list to
552    /// improve performance with high temporal locality (since `get()` will try to match according
553    /// to the list order).  The order of the rest of the list must be preserved for the same
554    /// reason.
555    fn insert(&mut self, entry: EntryWithHash<K, V, P>) -> bool {
556        match self {
557            Bucket::Single(existing_entry)
558                if existing_entry.matches(entry.key(), entry.key_hash) =>
559            {
560                *existing_entry = entry;
561                false
562            }
563            Bucket::Single(existing_entry) => {
564                let mut entries = List::new_with_ptr_kind();
565
566                // TODO In theory we should not need to clone `existing_entry`.
567                entries.push_front_mut(existing_entry.clone());
568                entries.push_front_mut(entry);
569
570                *self = Bucket::Collision(entries);
571
572                true
573            }
574            Bucket::Collision(entries) => {
575                let key_existed = bucket_utils::list_remove_first(entries, |e| {
576                    e.matches(entry.key(), entry.key_hash)
577                })
578                .is_some();
579
580                entries.push_front_mut(entry);
581
582                !key_existed
583            }
584        }
585    }
586
587    /// Returns `true` if the key was present.
588    ///
589    /// If the bucket becomes empty `bucket` it be set to `None`.
590    fn remove<Q: ?Sized>(
591        bucket: &mut Option<&mut Bucket<K, V, P>>,
592        key: &Q,
593        key_hash: HashValue,
594    ) -> bool
595    where
596        K: Borrow<Q>,
597        Q: Hash + Eq,
598    {
599        match bucket.take() {
600            Some(b) => {
601                match b {
602                    Bucket::Single(existing_entry) if existing_entry.matches(key, key_hash) => {
603                        // bucket is already `None`.
604                        true
605                    }
606                    Bucket::Single(_) => {
607                        // Nothing to change.
608                        *bucket = Some(b);
609                        false
610                    }
611
612                    Bucket::Collision(entries) => {
613                        let removed =
614                            bucket_utils::list_remove_first(entries, |e| e.matches(key, key_hash))
615                                .is_some();
616
617                        match entries.len() {
618                            0 => unreachable!(
619                                "impossible to have collision with a single or no entry"
620                            ),
621                            1 => {
622                                let entry = entries.first().unwrap().clone();
623
624                                *b = Bucket::Single(entry);
625                            }
626                            _ => (),
627                        }
628
629                        *bucket = Some(b);
630
631                        removed
632                    }
633                }
634            }
635            None => false,
636        }
637    }
638}
639
640impl<K, V, P> Clone for Bucket<K, V, P>
641where
642    K: Eq + Hash,
643    P: SharedPointerKind,
644{
645    fn clone(&self) -> Bucket<K, V, P> {
646        match self {
647            Bucket::Single(entry) => Bucket::Single(EntryWithHash::clone(entry)),
648            Bucket::Collision(entries) => Bucket::Collision(List::clone(entries)),
649        }
650    }
651}
652
653impl<K, V, P> EntryWithHash<K, V, P>
654where
655    K: Eq + Hash,
656    P: SharedPointerKind,
657{
658    fn new<H: BuildHasher>(key: K, value: V, hash_builder: &H) -> EntryWithHash<K, V, P> {
659        let key_hash = node_utils::hash(&key, hash_builder);
660
661        EntryWithHash { entry: SharedPointer::new(Entry::new(key, value)), key_hash }
662    }
663
664    fn key(&self) -> &K {
665        &self.entry.key
666    }
667
668    fn value(&self) -> &V {
669        &self.entry.value
670    }
671
672    #[inline]
673    fn matches<Q: ?Sized>(&self, key: &Q, key_hash: HashValue) -> bool
674    where
675        K: Borrow<Q>,
676        Q: Hash + Eq,
677    {
678        self.key_hash == key_hash && self.key().borrow() == key
679    }
680}
681
682impl<K, V, P> EntryWithHash<K, V, P>
683where
684    K: Eq + Hash + Clone,
685    V: Clone,
686    P: SharedPointerKind,
687{
688    fn value_mut(&mut self) -> &mut V {
689        &mut SharedPointer::make_mut(&mut self.entry).value
690    }
691}
692
693impl<K, V, P> Clone for EntryWithHash<K, V, P>
694where
695    K: Eq + Hash,
696    P: SharedPointerKind,
697{
698    fn clone(&self) -> EntryWithHash<K, V, P> {
699        EntryWithHash { entry: SharedPointer::clone(&self.entry), key_hash: self.key_hash }
700    }
701}
702
703impl<K, V> HashTrieMap<K, V>
704where
705    K: Eq + Hash,
706{
707    #[must_use]
708    pub fn new() -> HashTrieMap<K, V> {
709        HashTrieMap::new_with_degree(DEFAULT_DEGREE)
710    }
711
712    #[must_use]
713    pub fn new_with_degree(degree: u8) -> HashTrieMap<K, V> {
714        HashTrieMap::new_with_hasher_and_degree_and_ptr_kind(DefaultBuildHasher::default(), degree)
715    }
716}
717
718impl<K, V> HashTrieMapSync<K, V>
719where
720    K: Eq + Hash,
721{
722    #[must_use]
723    pub fn new_sync() -> HashTrieMapSync<K, V> {
724        HashTrieMap::new_sync_with_degree(DEFAULT_DEGREE)
725    }
726
727    #[must_use]
728    pub fn new_sync_with_degree(degree: u8) -> HashTrieMapSync<K, V> {
729        HashTrieMap::new_with_hasher_and_degree_and_ptr_kind(DefaultBuildHasher::default(), degree)
730    }
731}
732
733impl<K, V, P, H: BuildHasher> HashTrieMap<K, V, P, H>
734where
735    K: Eq + Hash,
736    H: Clone,
737    P: SharedPointerKind,
738{
739    #[must_use]
740    pub fn new_with_hasher_and_ptr_kind(hasher_builder: H) -> HashTrieMap<K, V, P, H> {
741        HashTrieMap::new_with_hasher_and_degree_and_ptr_kind(hasher_builder, DEFAULT_DEGREE)
742    }
743
744    #[must_use]
745    pub fn new_with_hasher_and_degree_and_ptr_kind(
746        hasher_builder: H,
747        degree: u8,
748    ) -> HashTrieMap<K, V, P, H> {
749        assert!(degree.is_power_of_two(), "degree must be a power of two");
750        assert!(degree <= DEFAULT_DEGREE, "degree is too big");
751
752        HashTrieMap {
753            root: SharedPointer::new(Node::new_empty_branch()),
754            size: 0,
755            degree,
756            hasher_builder,
757        }
758    }
759
760    #[must_use]
761    pub fn get<Q: ?Sized>(&self, key: &Q) -> Option<&V>
762    where
763        K: Borrow<Q>,
764        Q: Hash + Eq,
765    {
766        let key_hash = node_utils::hash(key, &self.hasher_builder);
767
768        self.root.get(key, key_hash, 0, self.degree).map(EntryWithHash::value)
769    }
770
771    #[must_use]
772    pub fn get_key_value<Q: ?Sized>(&self, key: &Q) -> Option<(&K, &V)>
773    where
774        K: Borrow<Q>,
775        Q: Hash + Eq,
776    {
777        let key_hash = node_utils::hash(key, &self.hasher_builder);
778
779        self.root.get(key, key_hash, 0, self.degree).map(|e| (e.key(), e.value()))
780    }
781
782    #[must_use]
783    pub fn insert(&self, key: K, value: V) -> HashTrieMap<K, V, P, H> {
784        let mut new_map = self.clone();
785
786        new_map.insert_mut(key, value);
787
788        new_map
789    }
790
791    pub fn insert_mut(&mut self, key: K, value: V) {
792        let entry = EntryWithHash::new(key, value, &self.hasher_builder);
793        let is_new_key = SharedPointer::make_mut(&mut self.root).insert(entry, 0, self.degree);
794
795        if is_new_key {
796            self.size += 1;
797        }
798    }
799
800    #[must_use]
801    pub fn remove<Q: ?Sized>(&self, key: &Q) -> HashTrieMap<K, V, P, H>
802    where
803        K: Borrow<Q>,
804        Q: Hash + Eq,
805    {
806        let mut new_map = self.clone();
807
808        if new_map.remove_mut(key) {
809            new_map
810        } else {
811            // We want to keep maximum sharing so in case of no change we just `clone()` ourselves.
812            self.clone()
813        }
814    }
815
816    pub fn remove_mut<Q: ?Sized>(&mut self, key: &Q) -> bool
817    where
818        K: Borrow<Q>,
819        Q: Hash + Eq,
820    {
821        let key_hash = node_utils::hash(key, &self.hasher_builder);
822        let removed = SharedPointer::make_mut(&mut self.root).remove(key, key_hash, 0, self.degree);
823
824        // Note that unfortunately, even if nothing was removed, we still might have cloned some
825        // part of the tree unnecessarily.
826
827        if removed {
828            self.size -= 1;
829        }
830
831        removed
832    }
833
834    #[must_use]
835    pub fn contains_key<Q: ?Sized>(&self, key: &Q) -> bool
836    where
837        K: Borrow<Q>,
838        Q: Hash + Eq,
839    {
840        self.get(key).is_some()
841    }
842
843    /// Test whether the two maps refer to the same content in memory.
844    ///
845    /// This would return true if you’re comparing a map to itself,
846    /// or if you’re comparing a map to a fresh clone of itself.
847    pub(crate) fn ptr_eq<PO: SharedPointerKind, HO: BuildHasher>(
848        &self,
849        other: &HashTrieMap<K, V, PO, HO>,
850    ) -> bool {
851        let a = SharedPointer::as_ptr(&self.root);
852        // Note how we're casting the raw pointer changing from P to PO
853        // We cannot perform the equality in a type safe way because the root type depends
854        // on P/PO, and we can't pass different types to SharedPtr::same_ptr or std::ptr::eq.
855        let b = SharedPointer::as_ptr(&other.root).cast::<Node<K, V, P>>();
856        core::ptr::eq(a, b)
857    }
858
859    #[must_use]
860    #[inline]
861    pub fn size(&self) -> usize {
862        self.size
863    }
864
865    #[must_use]
866    #[inline]
867    pub fn is_empty(&self) -> bool {
868        self.size() == 0
869    }
870
871    #[allow(clippy::iter_without_into_iter)]
872    pub fn iter(&self) -> Iter<'_, K, V, P> {
873        self.iter_ptr().map(|e| (&e.key, &e.value))
874    }
875
876    #[must_use]
877    fn iter_ptr(&self) -> IterPtr<'_, K, V, P> {
878        IterPtr::new(self)
879    }
880
881    pub fn keys(&self) -> IterKeys<'_, K, V, P> {
882        self.iter().map(|(k, _)| k)
883    }
884
885    pub fn values(&self) -> IterValues<'_, K, V, P> {
886        self.iter().map(|(_, v)| v)
887    }
888}
889
890impl<K, V, P, H: BuildHasher> HashTrieMap<K, V, P, H>
891where
892    K: Eq + Hash + Clone,
893    V: Clone,
894    H: Clone,
895    P: SharedPointerKind,
896{
897    pub fn get_mut<Q: ?Sized>(&mut self, key: &Q) -> Option<&mut V>
898    where
899        K: Borrow<Q>,
900        Q: Hash + Eq,
901    {
902        // Note that unfortunately, even if nothing is found, we still might have cloned some
903        // part of the tree unnecessarily.
904        let key_hash = node_utils::hash(key, &self.hasher_builder);
905        SharedPointer::make_mut(&mut self.root)
906            .get_mut(key, key_hash, 0, self.degree)
907            .map(EntryWithHash::value_mut)
908    }
909}
910
911impl<K, Q: ?Sized, V, P, H: BuildHasher> Index<&Q> for HashTrieMap<K, V, P, H>
912where
913    K: Eq + Hash + Borrow<Q>,
914    Q: Hash + Eq,
915    H: Clone,
916    P: SharedPointerKind,
917{
918    type Output = V;
919
920    fn index(&self, key: &Q) -> &V {
921        self.get(key).expect("no entry found for key")
922    }
923}
924
925impl<K, V, P, H: BuildHasher> Clone for HashTrieMap<K, V, P, H>
926where
927    K: Eq + Hash,
928    H: Clone,
929    P: SharedPointerKind,
930{
931    fn clone(&self) -> HashTrieMap<K, V, P, H> {
932        HashTrieMap {
933            root: SharedPointer::clone(&self.root),
934            size: self.size,
935            degree: self.degree,
936            hasher_builder: self.hasher_builder.clone(),
937        }
938    }
939}
940
941impl<K, V, P, H: BuildHasher> Default for HashTrieMap<K, V, P, H>
942where
943    K: Eq + Hash,
944    H: Default + Clone,
945    P: SharedPointerKind,
946{
947    fn default() -> HashTrieMap<K, V, P, H> {
948        HashTrieMap::new_with_hasher_and_ptr_kind(H::default())
949    }
950}
951
952impl<K: Eq, V: PartialEq, P, PO, H: BuildHasher> PartialEq<HashTrieMap<K, V, PO, H>>
953    for HashTrieMap<K, V, P, H>
954where
955    K: Hash,
956    H: Clone,
957    P: SharedPointerKind,
958    PO: SharedPointerKind,
959{
960    fn eq(&self, other: &HashTrieMap<K, V, PO, H>) -> bool {
961        if self.ptr_eq(other) {
962            return true;
963        }
964        self.size() == other.size()
965            && self.iter().all(|(key, value)| other.get(key).is_some_and(|v| *value == *v))
966    }
967}
968
969impl<K: Eq, V: Eq, P, H: BuildHasher> Eq for HashTrieMap<K, V, P, H>
970where
971    K: Hash,
972    H: Clone,
973    P: SharedPointerKind,
974{
975}
976
977impl<K, V, P, H: BuildHasher> Display for HashTrieMap<K, V, P, H>
978where
979    K: Eq + Hash + Display,
980    V: Display,
981    H: Clone,
982    P: SharedPointerKind,
983{
984    fn fmt(&self, fmt: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
985        let mut first = true;
986
987        fmt.write_str("{")?;
988
989        for (k, v) in self.iter() {
990            if !first {
991                fmt.write_str(", ")?;
992            }
993            k.fmt(fmt)?;
994            fmt.write_str(": ")?;
995            v.fmt(fmt)?;
996            first = false;
997        }
998
999        fmt.write_str("}")
1000    }
1001}
1002
1003impl<'a, K, V, P, H: BuildHasher> IntoIterator for &'a HashTrieMap<K, V, P, H>
1004where
1005    K: Eq + Hash,
1006    H: Default + Clone,
1007    P: SharedPointerKind,
1008{
1009    type Item = (&'a K, &'a V);
1010    type IntoIter = Iter<'a, K, V, P>;
1011
1012    fn into_iter(self) -> Iter<'a, K, V, P> {
1013        self.iter()
1014    }
1015}
1016
1017impl<K, V, P, H> FromIterator<(K, V)> for HashTrieMap<K, V, P, H>
1018where
1019    K: Eq + Hash,
1020    H: BuildHasher + Clone + Default,
1021    P: SharedPointerKind,
1022{
1023    fn from_iter<I: IntoIterator<Item = (K, V)>>(into_iter: I) -> HashTrieMap<K, V, P, H> {
1024        let mut map = HashTrieMap::new_with_hasher_and_ptr_kind(Default::default());
1025
1026        for (k, v) in into_iter {
1027            map.insert_mut(k, v);
1028        }
1029
1030        map
1031    }
1032}
1033
1034#[derive(Debug)]
1035pub struct IterPtr<'a, K, V, P>
1036where
1037    P: SharedPointerKind,
1038{
1039    stack: Vec<IterStackElement<'a, K, V, P>>,
1040    size: usize,
1041}
1042
1043#[derive(Debug)]
1044enum IterStackElement<'a, K, V, P>
1045where
1046    P: SharedPointerKind,
1047{
1048    Branch(slice::Iter<'a, SharedPointer<Node<K, V, P>, P>>),
1049    LeafCollision(list::Iter<'a, EntryWithHash<K, V, P>, P>),
1050    LeafSingle(iter::Once<&'a SharedPointer<Entry<K, V>, P>>),
1051}
1052
1053impl<'a, K, V, P> IterStackElement<'a, K, V, P>
1054where
1055    K: Eq + Hash,
1056    P: SharedPointerKind,
1057{
1058    #[inline]
1059    fn new(node: &Node<K, V, P>) -> IterStackElement<'_, K, V, P> {
1060        match node {
1061            Node::Branch(children) => IterStackElement::Branch(children.iter()),
1062            Node::Leaf(Bucket::Collision(entries)) => {
1063                IterStackElement::LeafCollision(entries.iter())
1064            }
1065            Node::Leaf(Bucket::Single(entry)) => {
1066                IterStackElement::LeafSingle(iter::once(&entry.entry))
1067            }
1068        }
1069    }
1070
1071    /// Returns the next `Entry` _or_ the next `IterStackElement` to be pushed into the stack.
1072    /// If the result is None the `IterStackElement` should be popped from the stack.
1073    #[inline]
1074    fn next(&mut self) -> Option<Result<&'a SharedPointer<Entry<K, V>, P>, Self>> {
1075        match self {
1076            IterStackElement::Branch(i) => i.next().map(|node| match &**node {
1077                Node::Branch(_) | Node::Leaf(Bucket::Collision(_)) => {
1078                    Err(IterStackElement::new(node))
1079                }
1080                Node::Leaf(Bucket::Single(e)) => Ok(&e.entry),
1081            }),
1082            IterStackElement::LeafCollision(i) => i.next().map(|i| Ok(&i.entry)),
1083            IterStackElement::LeafSingle(i) => i.next().map(Ok),
1084        }
1085    }
1086}
1087
1088mod iter_utils {
1089    use super::HashValue;
1090
1091    pub fn trie_max_height(degree: u8) -> usize {
1092        let bits_per_level = (degree - 1).count_ones() as usize;
1093        let hash_bits = HashValue::BITS as usize;
1094
1095        (hash_bits / bits_per_level) + usize::from(hash_bits % bits_per_level > 0)
1096    }
1097}
1098
1099impl<K, V, P> IterPtr<'_, K, V, P>
1100where
1101    K: Eq + Hash,
1102    P: SharedPointerKind,
1103{
1104    fn new<H: BuildHasher + Clone>(map: &HashTrieMap<K, V, P, H>) -> IterPtr<'_, K, V, P> {
1105        let mut stack: Vec<IterStackElement<'_, K, V, P>> =
1106            Vec::with_capacity(iter_utils::trie_max_height(map.degree) + 1);
1107
1108        if map.size() > 0 {
1109            stack.push(IterStackElement::new(map.root.borrow()));
1110        }
1111
1112        IterPtr { stack, size: map.size() }
1113    }
1114}
1115
1116impl<'a, K, V, P> Iterator for IterPtr<'a, K, V, P>
1117where
1118    K: Eq + Hash,
1119    P: SharedPointerKind,
1120{
1121    type Item = &'a SharedPointer<Entry<K, V>, P>;
1122
1123    fn next(&mut self) -> Option<&'a SharedPointer<Entry<K, V>, P>> {
1124        while let Some(stack_element) = self.stack.last_mut() {
1125            match stack_element.next() {
1126                Some(Ok(elem)) => {
1127                    self.size -= 1;
1128                    return Some(elem);
1129                }
1130                Some(Err(stack_elem)) => {
1131                    self.stack.push(stack_elem);
1132                }
1133                None => {
1134                    self.stack.pop();
1135                }
1136            }
1137        }
1138        None
1139    }
1140
1141    #[inline]
1142    fn size_hint(&self) -> (usize, Option<usize>) {
1143        (self.size, Some(self.size))
1144    }
1145}
1146
1147impl<K: Eq + Hash, V, P> ExactSizeIterator for IterPtr<'_, K, V, P> where P: SharedPointerKind {}
1148
1149#[cfg(feature = "serde")]
1150pub mod serde {
1151    use super::*;
1152    use ::serde::de::{Deserialize, Deserializer, MapAccess, Visitor};
1153    use ::serde::ser::{Serialize, Serializer};
1154    use core::fmt;
1155    use core::marker::PhantomData;
1156
1157    impl<K, V, P, H> Serialize for HashTrieMap<K, V, P, H>
1158    where
1159        K: Eq + Hash + Serialize,
1160        V: Serialize,
1161        H: BuildHasher + Clone + Default,
1162        P: SharedPointerKind,
1163    {
1164        fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
1165            serializer.collect_map(self)
1166        }
1167    }
1168
1169    impl<'de, K, V, P, H> Deserialize<'de> for HashTrieMap<K, V, P, H>
1170    where
1171        K: Eq + Hash + Deserialize<'de>,
1172        V: Deserialize<'de>,
1173        H: BuildHasher + Clone + Default,
1174        P: SharedPointerKind,
1175    {
1176        fn deserialize<D: Deserializer<'de>>(
1177            deserializer: D,
1178        ) -> Result<HashTrieMap<K, V, P, H>, D::Error> {
1179            deserializer.deserialize_map(HashTrieMapVisitor {
1180                _phantom_entry: PhantomData,
1181                _phantom_h: PhantomData,
1182                _phantom_p: PhantomData,
1183            })
1184        }
1185    }
1186
1187    struct HashTrieMapVisitor<K, V, P, H>
1188    where
1189        P: SharedPointerKind,
1190    {
1191        _phantom_entry: PhantomData<(K, V)>,
1192        _phantom_h: PhantomData<H>,
1193        _phantom_p: PhantomData<P>,
1194    }
1195
1196    impl<'de, K, V, P, H> Visitor<'de> for HashTrieMapVisitor<K, V, P, H>
1197    where
1198        K: Eq + Hash + Deserialize<'de>,
1199        V: Deserialize<'de>,
1200        H: BuildHasher + Clone + Default,
1201        P: SharedPointerKind,
1202    {
1203        type Value = HashTrieMap<K, V, P, H>;
1204
1205        fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
1206            formatter.write_str("a map")
1207        }
1208
1209        fn visit_map<A>(self, mut map: A) -> Result<HashTrieMap<K, V, P, H>, A::Error>
1210        where
1211            A: MapAccess<'de>,
1212        {
1213            let mut hash_trie_map = HashTrieMap::new_with_hasher_and_ptr_kind(Default::default());
1214
1215            while let Some((k, v)) = map.next_entry()? {
1216                hash_trie_map.insert_mut(k, v);
1217            }
1218
1219            Ok(hash_trie_map)
1220        }
1221    }
1222}
1223
1224#[cfg(test)]
1225mod test;