Skip to main content

obeli_sk_small_btree/
lib.rs

1//! A crate that provides a `SmallBTreeMap` collection, which is initially backed by an inline vec
2//! but changes its backing to a heap map if its number of elements exceeds `ARRAY_SIZE`.
3//!
4//! This provides performance benefits for maps that are expected to be small most of the time,
5//! by avoiding heap allocations for the common case while still supporting larger collections when needed.
6
7#![doc = include_str!("../ABOUT.md")]
8#![doc(
9    html_logo_url = "https://raw.githubusercontent.com/boa-dev/boa/main/assets/logo_black.svg",
10    html_favicon_url = "https://raw.githubusercontent.com/boa-dev/boa/main/assets/logo_black.svg"
11)]
12use std::{
13    borrow::Borrow,
14    collections::{BTreeMap, btree_map},
15    fmt,
16    hash::{Hash, Hasher},
17    iter::FusedIterator,
18    ops::{Index, IndexMut},
19};
20
21use arrayvec::ArrayVec;
22
23mod entry;
24
25pub use entry::{Entry, OccupiedEntry, VacantEntry};
26
27use Entry::{Occupied, Vacant};
28
29/// A map that is initially backed by an inline vec, but changes its backing to a heap map if its
30/// number of elements exceeds `ARRAY_SIZE`.
31#[derive(Clone)]
32pub struct SmallBTreeMap<K, V, const ARRAY_SIZE: usize> {
33    inner: Inner<K, V, ARRAY_SIZE>,
34}
35
36#[derive(Debug, Clone)]
37enum Inner<K, V, const ARRAY_SIZE: usize> {
38    Inline(ArrayVec<(K, V), ARRAY_SIZE>),
39    Heap(BTreeMap<K, V>),
40}
41
42/// An iterator over the entries of a `SmallBTreeMap`.
43///
44/// This `struct` is created by the [`iter`] method on [`SmallBTreeMap`]. See its
45/// documentation for more.
46///
47/// [`iter`]: SmallBTreeMap::iter
48#[derive(Clone)]
49pub struct Iter<'a, K, V> {
50    inner: InnerIter<'a, K, V>,
51}
52
53#[derive(Clone)]
54enum InnerIter<'a, K, V> {
55    Inline(std::slice::Iter<'a, (K, V)>),
56    Heap(btree_map::Iter<'a, K, V>),
57}
58
59impl<K: fmt::Debug, V: fmt::Debug> fmt::Debug for Iter<'_, K, V> {
60    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
61        match &self.inner {
62            InnerIter::Inline(i) => f.debug_tuple("Inline").field(i).finish(),
63            InnerIter::Heap(h) => f.debug_tuple("Heap").field(h).finish(),
64        }
65    }
66}
67
68impl<K, V> Default for Iter<'_, K, V> {
69    /// Creates an empty `small_btree::Iter`.
70    fn default() -> Self {
71        Self {
72            inner: InnerIter::Inline(std::slice::Iter::default()),
73        }
74    }
75}
76
77/// A mutable iterator over the entries of a `SmallBTreeMap`.
78///
79/// This `struct` is created by the [`iter_mut`] method on [`SmallBTreeMap`]. See its
80/// documentation for more.
81///
82/// [`iter_mut`]: SmallBTreeMap::iter_mut
83pub struct IterMut<'a, K, V> {
84    inner: InnerIterMut<'a, K, V>,
85}
86
87enum InnerIterMut<'a, K, V> {
88    Inline(std::slice::IterMut<'a, (K, V)>),
89    Heap(btree_map::IterMut<'a, K, V>),
90}
91
92impl<K: fmt::Debug, V: fmt::Debug> fmt::Debug for IterMut<'_, K, V> {
93    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
94        match &self.inner {
95            InnerIterMut::Inline(i) => f.debug_tuple("Inline").field(i).finish(),
96            InnerIterMut::Heap(h) => f.debug_tuple("Heap").field(h).finish(),
97        }
98    }
99}
100
101impl<K, V> Default for IterMut<'_, K, V> {
102    /// Creates an empty `small_btree::IterMut`.
103    fn default() -> Self {
104        Self {
105            inner: InnerIterMut::Inline(std::slice::IterMut::default()),
106        }
107    }
108}
109
110/// An owning iterator over the entries of a `SmallBTreeMap`.
111///
112/// This `struct` is created by the [`into_iter`] method on [`SmallBTreeMap`]
113/// (provided by the [`IntoIterator`] trait). See its documentation for more.
114///
115/// [`into_iter`]: IntoIterator::into_iter
116pub struct IntoIter<K, V, const ARRAY_SIZE: usize> {
117    inner: InnerIntoIter<K, V, ARRAY_SIZE>,
118}
119
120enum InnerIntoIter<K, V, const ARRAY_SIZE: usize> {
121    Inline(arrayvec::IntoIter<(K, V), ARRAY_SIZE>),
122    Heap(btree_map::IntoIter<K, V>),
123}
124
125impl<K: fmt::Debug, V: fmt::Debug, const ARRAY_SIZE: usize> fmt::Debug
126    for IntoIter<K, V, ARRAY_SIZE>
127{
128    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
129        match &self.inner {
130            InnerIntoIter::Inline(i) => f.debug_tuple("Inline").field(i).finish(),
131            InnerIntoIter::Heap(h) => f.debug_tuple("Heap").field(h).finish(),
132        }
133    }
134}
135
136impl<K, V, const ARRAY_SIZE: usize> Default for IntoIter<K, V, ARRAY_SIZE> {
137    /// Creates an empty `small_btree::IntoIter`.
138    fn default() -> Self {
139        Self {
140            inner: InnerIntoIter::Inline(ArrayVec::new().into_iter()),
141        }
142    }
143}
144
145impl<K, V, const ARRAY_SIZE: usize> SmallBTreeMap<K, V, ARRAY_SIZE> {
146    /// Makes a new, empty `SmallBTreeMap`.
147    #[must_use]
148    pub const fn new() -> Self {
149        Self {
150            inner: Inner::Inline(ArrayVec::new_const()),
151        }
152    }
153
154    /// Clears the map, removing all elements.
155    ///
156    /// The current implementation will preserve the heap map allocation
157    /// if the map has already transitioned to the fallback heap map.
158    pub fn clear(&mut self) {
159        match &mut self.inner {
160            Inner::Inline(v) => v.clear(),
161            Inner::Heap(h) => h.clear(),
162        }
163    }
164
165    /// Returns a reference to the value corresponding to the key.
166    ///
167    /// The key may be any borrowed form of the map's key type, but the ordering
168    /// on the borrowed form *must* match the ordering on the key type.
169    pub fn get<Q>(&self, key: &Q) -> Option<&V>
170    where
171        K: Borrow<Q> + Ord + Eq,
172        Q: ?Sized + Ord + Eq,
173    {
174        match &self.inner {
175            Inner::Inline(v) => v.iter().find(|(k, _)| k.borrow() == key).map(|(_, v)| v),
176            Inner::Heap(h) => h.get(key),
177        }
178    }
179
180    /// Returns the key-value pair corresponding to the supplied key.
181    ///
182    /// The supplied key may be any borrowed form of the map's key type, but the ordering
183    /// on the borrowed form *must* match the ordering on the key type.
184    #[allow(clippy::map_identity)]
185    pub fn get_key_value<Q>(&self, key: &Q) -> Option<(&K, &V)>
186    where
187        K: Borrow<Q> + Ord + Eq,
188        Q: ?Sized + Ord + Eq,
189    {
190        match &self.inner {
191            Inner::Inline(v) => v
192                .iter()
193                .find(|(k, _)| k.borrow() == key)
194                .map(|(k, v)| (k, v)),
195            Inner::Heap(h) => h.get_key_value(key),
196        }
197    }
198
199    /// Returns `true` if the map contains a value for the specified key.
200    ///
201    /// The key may be any borrowed form of the map's key type, but the ordering
202    /// on the borrowed form *must* match the ordering on the key type.
203    pub fn contains_key<Q>(&self, key: &Q) -> bool
204    where
205        K: Borrow<Q> + Ord + Eq,
206        Q: ?Sized + Ord + Eq,
207    {
208        self.get(key).is_some()
209    }
210
211    /// Returns a mutable reference to the value corresponding to the key.
212    ///
213    /// The key may be any borrowed form of the map's key type, but the ordering
214    /// on the borrowed form *must* match the ordering on the key type.
215    pub fn get_mut<Q>(&mut self, key: &Q) -> Option<&mut V>
216    where
217        K: Borrow<Q> + Ord + Eq,
218        Q: ?Sized + Ord + Eq,
219    {
220        match &mut self.inner {
221            Inner::Inline(v) => v
222                .iter_mut()
223                .find(|(k, _)| k.borrow() == key)
224                .map(|(_, v)| v),
225            Inner::Heap(h) => h.get_mut(key),
226        }
227    }
228
229    /// Inserts a key-value pair into the map.
230    ///
231    /// If the map did not have this key present, `None` is returned.
232    ///
233    /// If the map did have this key present, the value is updated, and the old
234    /// value is returned. The key is not updated, though; this matters for
235    /// types that can be `==` without being identical. See the [**Insert and complex keys**][keys]
236    /// section from the [`std::collections`] module documentation for more information.
237    ///
238    /// [keys]: https://doc.rust-lang.org/std/collections/index.html#insert-and-complex-keys
239    pub fn insert(&mut self, key: K, value: V) -> Option<V>
240    where
241        K: Eq + Ord,
242    {
243        match self.entry(key) {
244            Occupied(mut entry) => Some(entry.insert(value)),
245            Vacant(entry) => {
246                entry.insert(value);
247                None
248            }
249        }
250    }
251
252    /// Removes a key from the map, returning the value at the key if the key
253    /// was previously in the map.
254    ///
255    /// The key may be any borrowed form of the map's key type, but the ordering
256    /// on the borrowed form *must* match the ordering on the key type.
257    pub fn remove<Q>(&mut self, key: &Q) -> Option<V>
258    where
259        K: Borrow<Q> + Ord + Eq,
260        Q: ?Sized + Ord + Eq,
261    {
262        self.remove_entry(key).map(|(_, v)| v)
263    }
264
265    /// Removes a key from the map, returning the stored key and value if the key
266    /// was previously in the map.
267    ///
268    /// The key may be any borrowed form of the map's key type, but the ordering
269    /// on the borrowed form *must* match the ordering on the key type.
270    pub fn remove_entry<Q>(&mut self, key: &Q) -> Option<(K, V)>
271    where
272        K: Borrow<Q> + Ord,
273        Q: ?Sized + Ord,
274    {
275        match &mut self.inner {
276            Inner::Inline(v) => v
277                .iter()
278                .position(|(k, _)| k.borrow() == key)
279                .map(|idx| v.remove(idx)),
280            Inner::Heap(h) => h.remove_entry(key),
281        }
282    }
283
284    /// Retains only the elements specified by the predicate.
285    ///
286    /// In other words, remove all pairs `(k, v)` for which `f(&k, &mut v)` returns `false`.
287    pub fn retain<F>(&mut self, mut f: F)
288    where
289        K: Ord,
290        F: FnMut(&K, &mut V) -> bool,
291    {
292        match &mut self.inner {
293            Inner::Inline(v) => v.retain(|(k, v)| f(k, v)),
294            Inner::Heap(h) => h.retain(f),
295        }
296    }
297
298    /// Moves all elements from `other` into `self`, leaving `other` empty.
299    ///
300    /// If a key from `other` is already present in `self`, the respective
301    /// value from `self` will be overwritten with the respective value from `other`.
302    pub fn append<const OTHER_SIZE: usize>(&mut self, other: &mut SmallBTreeMap<K, V, OTHER_SIZE>)
303    where
304        K: Ord + Eq,
305    {
306        if other.is_empty() {
307            return;
308        }
309
310        let inline = matches!(other.inner, Inner::Inline(_));
311
312        let other = std::mem::replace(
313            other,
314            SmallBTreeMap {
315                inner: if inline {
316                    Inner::Inline(ArrayVec::new())
317                } else {
318                    Inner::Heap(BTreeMap::new())
319                },
320            },
321        );
322
323        self.extend(other);
324    }
325
326    /// Gets the given key's corresponding entry in the map for in-place manipulation.
327    pub fn entry(&mut self, key: K) -> Entry<'_, K, V, ARRAY_SIZE>
328    where
329        K: Eq + Ord,
330    {
331        match &mut self.inner {
332            Inner::Inline(array) => {
333                let Some(index) = array.iter().position(|(k, _)| *k == key) else {
334                    return Vacant(VacantEntry {
335                        inner: entry::InnerVacant::Inline(entry::InlineVacantEntry {
336                            key,
337                            map: self,
338                        }),
339                    });
340                };
341
342                // Workaround for Problem case 3 of the current borrow checker.
343                // https://rust-lang.github.io/rfcs/2094-nll.html#problem-case-3-conditional-control-flow-across-functions
344                // Hopefully we can remove this with some improvements to the borrow checker.
345                match &mut self.inner {
346                    Inner::Inline(array) => Occupied(OccupiedEntry {
347                        inner: entry::InnerOccupied::Inline(entry::InlineOccupiedEntry {
348                            index,
349                            array,
350                        }),
351                    }),
352                    Inner::Heap(_) => unreachable!(),
353                }
354            }
355            // Same workaround as above.
356            Inner::Heap(_) => match &mut self.inner {
357                Inner::Heap(h) => match h.entry(key) {
358                    btree_map::Entry::Vacant(entry) => Vacant(VacantEntry {
359                        inner: entry::InnerVacant::Heap(entry),
360                    }),
361                    btree_map::Entry::Occupied(entry) => Occupied(OccupiedEntry {
362                        inner: entry::InnerOccupied::Heap(entry),
363                    }),
364                },
365                Inner::Inline(_) => unreachable!(),
366            },
367        }
368    }
369}
370
371impl<'a, K, V, const ARRAY_SIZE: usize> IntoIterator for &'a SmallBTreeMap<K, V, ARRAY_SIZE> {
372    type Item = (&'a K, &'a V);
373    type IntoIter = Iter<'a, K, V>;
374
375    fn into_iter(self) -> Self::IntoIter {
376        self.iter()
377    }
378}
379
380impl<'a, K, V> Iterator for Iter<'a, K, V> {
381    type Item = (&'a K, &'a V);
382
383    #[allow(clippy::map_identity)]
384    fn next(&mut self) -> Option<Self::Item> {
385        match &mut self.inner {
386            InnerIter::Inline(i) => i.next().map(|(k, v)| (k, v)),
387            InnerIter::Heap(h) => h.next(),
388        }
389    }
390
391    fn size_hint(&self) -> (usize, Option<usize>) {
392        match &self.inner {
393            InnerIter::Inline(i) => i.size_hint(),
394            InnerIter::Heap(h) => h.size_hint(),
395        }
396    }
397
398    #[allow(clippy::map_identity)]
399    fn last(self) -> Option<(&'a K, &'a V)> {
400        match self.inner {
401            InnerIter::Inline(i) => i.last().map(|(k, v)| (k, v)),
402            InnerIter::Heap(h) => h.last(),
403        }
404    }
405}
406
407impl<K, V> FusedIterator for Iter<'_, K, V> {}
408
409impl<'a, K: 'a, V: 'a> DoubleEndedIterator for Iter<'a, K, V> {
410    #[allow(clippy::map_identity)]
411    fn next_back(&mut self) -> Option<(&'a K, &'a V)> {
412        match &mut self.inner {
413            InnerIter::Inline(i) => i.next_back().map(|(k, v)| (k, v)),
414            InnerIter::Heap(h) => h.next_back(),
415        }
416    }
417}
418
419impl<K, V> ExactSizeIterator for Iter<'_, K, V> {
420    fn len(&self) -> usize {
421        match &self.inner {
422            InnerIter::Inline(i) => i.len(),
423            InnerIter::Heap(h) => h.len(),
424        }
425    }
426}
427
428impl<'a, K, V, const ARRAY_SIZE: usize> IntoIterator for &'a mut SmallBTreeMap<K, V, ARRAY_SIZE> {
429    type Item = (&'a K, &'a mut V);
430    type IntoIter = IterMut<'a, K, V>;
431
432    fn into_iter(self) -> Self::IntoIter {
433        self.iter_mut()
434    }
435}
436
437impl<'a, K, V> Iterator for IterMut<'a, K, V> {
438    type Item = (&'a K, &'a mut V);
439
440    fn next(&mut self) -> Option<Self::Item> {
441        match &mut self.inner {
442            InnerIterMut::Inline(i) => i.next().map(|(k, v)| (&*k, v)),
443            InnerIterMut::Heap(h) => h.next(),
444        }
445    }
446
447    fn size_hint(&self) -> (usize, Option<usize>) {
448        match &self.inner {
449            InnerIterMut::Inline(i) => i.size_hint(),
450            InnerIterMut::Heap(h) => h.size_hint(),
451        }
452    }
453
454    fn last(self) -> Option<(&'a K, &'a mut V)> {
455        match self.inner {
456            InnerIterMut::Inline(i) => i.last().map(|(k, v)| (&*k, v)),
457            InnerIterMut::Heap(h) => h.last(),
458        }
459    }
460}
461
462impl<K, V> FusedIterator for IterMut<'_, K, V> {}
463
464impl<'a, K: 'a, V: 'a> DoubleEndedIterator for IterMut<'a, K, V> {
465    fn next_back(&mut self) -> Option<(&'a K, &'a mut V)> {
466        match &mut self.inner {
467            InnerIterMut::Inline(i) => i.next_back().map(|(k, v)| (&*k, v)),
468            InnerIterMut::Heap(h) => h.next_back(),
469        }
470    }
471}
472
473impl<K, V> ExactSizeIterator for IterMut<'_, K, V> {
474    fn len(&self) -> usize {
475        match &self.inner {
476            InnerIterMut::Inline(i) => i.len(),
477            InnerIterMut::Heap(h) => h.len(),
478        }
479    }
480}
481
482impl<K, V, const ARRAY_SIZE: usize> IntoIterator for SmallBTreeMap<K, V, ARRAY_SIZE> {
483    type Item = (K, V);
484    type IntoIter = IntoIter<K, V, ARRAY_SIZE>;
485
486    fn into_iter(self) -> Self::IntoIter {
487        match self.inner {
488            Inner::Inline(i) => IntoIter {
489                inner: InnerIntoIter::Inline(i.into_iter()),
490            },
491            Inner::Heap(h) => IntoIter {
492                inner: InnerIntoIter::Heap(h.into_iter()),
493            },
494        }
495    }
496}
497
498impl<K, V, const ARRAY_SIZE: usize> Iterator for IntoIter<K, V, ARRAY_SIZE> {
499    type Item = (K, V);
500
501    fn next(&mut self) -> Option<(K, V)> {
502        match &mut self.inner {
503            InnerIntoIter::Inline(i) => i.next(),
504            InnerIntoIter::Heap(h) => h.next(),
505        }
506    }
507
508    fn size_hint(&self) -> (usize, Option<usize>) {
509        match &self.inner {
510            InnerIntoIter::Inline(i) => i.size_hint(),
511            InnerIntoIter::Heap(h) => h.size_hint(),
512        }
513    }
514}
515
516impl<K, V, const ARRAY_SIZE: usize> DoubleEndedIterator for IntoIter<K, V, ARRAY_SIZE> {
517    fn next_back(&mut self) -> Option<(K, V)> {
518        match &mut self.inner {
519            InnerIntoIter::Inline(i) => i.next_back(),
520            InnerIntoIter::Heap(h) => h.next_back(),
521        }
522    }
523}
524
525impl<K, V, const ARRAY_SIZE: usize> ExactSizeIterator for IntoIter<K, V, ARRAY_SIZE> {
526    fn len(&self) -> usize {
527        match &self.inner {
528            InnerIntoIter::Inline(i) => i.len(),
529            InnerIntoIter::Heap(h) => h.len(),
530        }
531    }
532}
533
534impl<K, V, const ARRAY_SIZE: usize> FusedIterator for IntoIter<K, V, ARRAY_SIZE> {}
535
536impl<K: Eq + Ord, V, const ARRAY_SIZE: usize> Extend<(K, V)> for SmallBTreeMap<K, V, ARRAY_SIZE> {
537    fn extend<T: IntoIterator<Item = (K, V)>>(&mut self, iter: T) {
538        iter.into_iter().for_each(move |(k, v)| {
539            self.insert(k, v);
540        });
541    }
542}
543
544impl<'a, K: Eq + Ord + Copy, V: Copy, const ARRAY_SIZE: usize> Extend<(&'a K, &'a V)>
545    for SmallBTreeMap<K, V, ARRAY_SIZE>
546{
547    fn extend<I: IntoIterator<Item = (&'a K, &'a V)>>(&mut self, iter: I) {
548        self.extend(iter.into_iter().map(|(&key, &value)| (key, value)));
549    }
550}
551
552impl<K: Hash, V: Hash, const ARRAY_SIZE: usize> Hash for SmallBTreeMap<K, V, ARRAY_SIZE> {
553    fn hash<H: Hasher>(&self, state: &mut H) {
554        // TODO: track https://github.com/rust-lang/rust/issues/96762
555        // state.write_length_prefix(self.len());
556        state.write_usize(self.len());
557        for elt in self {
558            elt.hash(state);
559        }
560    }
561}
562
563impl<K, V, const ARRAY_SIZE: usize> Default for SmallBTreeMap<K, V, ARRAY_SIZE> {
564    /// Creates an empty `SmallBTreeMap`.
565    fn default() -> Self {
566        Self::new()
567    }
568}
569
570impl<K: PartialEq + Ord, V: PartialEq, const LHS_SIZE: usize, const RHS_SIZE: usize>
571    PartialEq<SmallBTreeMap<K, V, RHS_SIZE>> for SmallBTreeMap<K, V, LHS_SIZE>
572{
573    fn eq(&self, other: &SmallBTreeMap<K, V, RHS_SIZE>) -> bool {
574        if let (Inner::Heap(lhs), Inner::Heap(rhs)) = (&self.inner, &other.inner) {
575            return lhs == rhs;
576        }
577
578        if self.len() != other.len() {
579            return false;
580        }
581
582        self.iter()
583            .all(|(key, value)| other.get(key).is_some_and(|v| *value == *v))
584    }
585}
586
587impl<K: Eq + Ord, V: Eq, const ARRAY_SIZE: usize> Eq for SmallBTreeMap<K, V, ARRAY_SIZE> {}
588
589impl<K: fmt::Debug, V: fmt::Debug, const ARRAY_SIZE: usize> fmt::Debug
590    for SmallBTreeMap<K, V, ARRAY_SIZE>
591{
592    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
593        f.debug_map().entries(self.iter()).finish()
594    }
595}
596
597impl<K, Q: ?Sized, V, const ARRAY_SIZE: usize> Index<&Q> for SmallBTreeMap<K, V, ARRAY_SIZE>
598where
599    K: Eq + Ord + Borrow<Q>,
600    Q: Eq + Ord,
601{
602    type Output = V;
603
604    fn index(&self, index: &Q) -> &Self::Output {
605        self.get(index).expect("no entry found for key")
606    }
607}
608
609impl<K, Q: ?Sized, V, const ARRAY_SIZE: usize> IndexMut<&Q> for SmallBTreeMap<K, V, ARRAY_SIZE>
610where
611    K: Eq + Ord + Borrow<Q>,
612    Q: Eq + Ord,
613{
614    fn index_mut(&mut self, index: &Q) -> &mut Self::Output {
615        self.get_mut(index).expect("no entry found for key")
616    }
617}
618
619impl<K, V, const ARRAY_SIZE: usize> SmallBTreeMap<K, V, ARRAY_SIZE> {
620    /// Gets an iterator over the entries of the map.
621    pub fn iter(&self) -> Iter<'_, K, V> {
622        match &self.inner {
623            Inner::Inline(i) => Iter {
624                inner: InnerIter::Inline(i.iter()),
625            },
626            Inner::Heap(h) => Iter {
627                inner: InnerIter::Heap(h.iter()),
628            },
629        }
630    }
631
632    /// Gets a mutable iterator over the entries of the map.
633    pub fn iter_mut(&mut self) -> IterMut<'_, K, V> {
634        match &mut self.inner {
635            Inner::Inline(i) => IterMut {
636                inner: InnerIterMut::Inline(i.iter_mut()),
637            },
638            Inner::Heap(h) => IterMut {
639                inner: InnerIterMut::Heap(h.iter_mut()),
640            },
641        }
642    }
643
644    /// Returns the number of elements in the map.
645    pub fn len(&self) -> usize {
646        match &self.inner {
647            Inner::Inline(i) => i.len(),
648            Inner::Heap(h) => h.len(),
649        }
650    }
651
652    /// Returns `true` if the map contains no elements.
653    pub fn is_empty(&self) -> bool {
654        self.len() == 0
655    }
656}