Skip to main content

total_maps/
hash_map.rs

1//! Provides [TotalHashMap], a hash map in which every possible key has an associated value. Only
2//! entries with *uncommon* values are actually stored in the map; all other keys are presumed to be
3//! associated with a *common* value.
4
5use std::{
6    borrow::Borrow,
7    collections::{HashMap, hash_map},
8    fmt::{self, Debug, Formatter},
9    hash::Hash,
10    iter::FusedIterator,
11    mem,
12    ops::{Deref, DerefMut, Index},
13    sync::OnceLock,
14};
15
16use crate::{Commonality, DefaultCommonality, PhantomPtr};
17
18// --------------------------------------------------------------------------
19
20/// A hash map in which every possible key has an associated value. Only entries with *uncommon*
21/// values are actually stored in the map; all other keys are presumed to be associated with a
22/// *common* value.
23///
24/// See the [crate documentation](crate) for more information.
25///
26/// The API more-or-less matches that of [HashMap]. However, methods that treat this type like a
27/// collection (for example, [`len()`](Self::len) and [`iter()`](Self::iter)) operate only on the
28/// *uncommon* entries.
29pub struct TotalHashMap<K, V, C = DefaultCommonality> {
30    inner: HashMap<K, V>,
31    common: OnceLock<V>, // need to store this so we can return references to it, e.g., in Self::get
32    _commonality: PhantomPtr<C>,
33}
34
35impl<K: Clone, V: Clone, C> Clone for TotalHashMap<K, V, C> {
36    fn clone(&self) -> Self {
37        Self {
38            inner: self.inner.clone(),
39            common: self.common.clone(),
40            _commonality: PhantomPtr::default(),
41        }
42    }
43}
44
45impl<K, V, C> Default for TotalHashMap<K, V, C> {
46    fn default() -> Self {
47        Self::wrap(HashMap::default())
48    }
49}
50impl<K, V, C> TotalHashMap<K, V, C> {
51    /// Constructs a `TotalHashMap` in which all keys are associated with the *common* value.
52    pub fn new() -> Self {
53        Self::default()
54    }
55
56    /// Constructs a `TotalHashMap` in which all keys are associated with the *common* value, with
57    /// at least the specified capacity for *uncommon* values.
58    pub fn with_capacity(capacity: usize) -> TotalHashMap<K, V, C> {
59        Self::wrap(HashMap::with_capacity(capacity))
60    }
61
62    fn wrap(inner: HashMap<K, V>) -> Self {
63        debug_assert!(inner.is_empty());
64        Self { inner, common: OnceLock::new(), _commonality: PhantomPtr::default() }
65    }
66}
67
68impl<K, V, C: Commonality<V>> TotalHashMap<K, V, C> {
69    fn common(&self) -> &V {
70        self.common.get_or_init(C::common)
71    }
72}
73
74impl<K, V, C> TotalHashMap<K, V, C> {
75    /// Returns the number of *uncommon* entries in the map.
76    pub fn len(&self) -> usize {
77        self.inner.len()
78    }
79    /// Returns true if the map contains no *uncommon* entries.
80    pub fn is_empty(&self) -> bool {
81        self.inner.is_empty()
82    }
83    /// Resets all entries in the map to the *common* value.
84    pub fn clear(&mut self) {
85        self.inner.clear()
86    }
87
88    /// Returns the number of *uncommon* elements the map can hold without reallocating.
89    pub fn capacity(&self) -> usize {
90        self.inner.capacity()
91    }
92}
93
94impl<K: Eq + Hash, V, C> TotalHashMap<K, V, C> {
95    /// Reserves capacity for at least `additional` more *uncommon* elements to be inserted into the
96    /// `TotalHashMap`.
97    pub fn reserve(&mut self, additional: usize) {
98        self.inner.reserve(additional);
99    }
100    /// Shrinks the map's capacity for *uncommon* elements as much as possible.
101    pub fn shrink_to_fit(&mut self) {
102        self.inner.shrink_to_fit();
103    }
104    /// Shrinks the map's capiacity for *uncommon* elements with a lower limit.
105    pub fn shrink_to(&mut self, min_capacity: usize) {
106        self.inner.shrink_to(min_capacity);
107    }
108}
109
110// --------------------------------------------------------------------------
111// Element access
112
113impl<K: Eq + Hash, V, C> TotalHashMap<K, V, C> {
114    /// Returns true if the map contains an *uncommon* entry with the given key.
115    pub fn contains_key<Q>(&self, key: &Q) -> bool
116    where
117        K: Borrow<Q>,
118        Q: Eq + Hash + ?Sized,
119    {
120        self.inner.contains_key(key)
121    }
122}
123
124impl<K: Eq + Hash + Borrow<Q>, Q: Eq + Hash + ?Sized, V, C: Commonality<V>> Index<&Q>
125    for TotalHashMap<K, V, C>
126{
127    type Output = V;
128    fn index(&self, index: &Q) -> &Self::Output {
129        self.get(index)
130    }
131}
132
133impl<K: Eq + Hash, V, C: Commonality<V>> TotalHashMap<K, V, C> {
134    /// Returns a reference to the value associated with the given key.
135    pub fn get<Q>(&self, key: &Q) -> &V
136    where
137        K: Borrow<Q>,
138        Q: Eq + Hash + ?Sized,
139    {
140        self.inner.get(key).unwrap_or_else(|| self.common())
141    }
142
143    /// Associates a key with a value in the map, and returns the value previously associated with
144    /// that key.
145    pub fn insert(&mut self, key: K, value: V) -> V {
146        if C::is_common(&value) { self.inner.remove(&key) } else { self.inner.insert(key, value) }
147            .unwrap_or_else(C::common)
148    }
149
150    /// Associates a key with the *common* value in the map, and returns the value previously
151    /// associated with that key.
152    pub fn remove<Q>(&mut self, key: &Q) -> V
153    where
154        K: Borrow<Q>,
155        Q: Eq + Hash + ?Sized,
156    {
157        self.inner.remove(key).unwrap_or_else(C::common)
158    }
159
160    /// Gets the given key's associated entry in the map for in-place manipulation.
161    pub fn entry(&mut self, key: K) -> Entry<'_, K, K, V, C> {
162        Entry {
163            inner: match self.inner.entry(key) {
164                hash_map::Entry::Occupied(inner) => EntryInner::Occupied { inner },
165                hash_map::Entry::Vacant(inner) => EntryInner::Vacant { inner, value: C::common() },
166            },
167        }
168    }
169
170    /// Gets the given key's associated entry in the map if it has an *uncommon* value; otherwise
171    /// returns [None].
172    ///
173    /// In contrast with [Self::entry], this method accepts the key in borrowed form.
174    pub fn uncommon_entry<'a, Q>(&'a mut self, key: &'a Q) -> Option<Entry<'a, Q, K, V, C>>
175    where
176        K: Borrow<Q>,
177        Q: Eq + Hash + ?Sized,
178    {
179        let map = self as *mut _;
180        let value = self.inner.get_mut(key)?;
181        Some(Entry { inner: EntryInner::ByRef { map, key, value } })
182    }
183}
184
185/// A view into a single entry in a [TotalHashMap].
186///
187/// This view is constructed from [TotalHashMap::entry].
188pub struct Entry<'a, Q, K, V, C = DefaultCommonality>
189where
190    Q: Eq + Hash + ?Sized,
191    K: Eq + Hash + Borrow<Q>,
192    C: Commonality<V>,
193{
194    inner: EntryInner<'a, Q, K, V, C>,
195}
196
197impl<Q, K, V, C> Deref for Entry<'_, Q, K, V, C>
198where
199    Q: Eq + Hash + ?Sized,
200    K: Eq + Hash + Borrow<Q>,
201    C: Commonality<V>,
202{
203    type Target = V;
204    fn deref(&self) -> &Self::Target {
205        match &self.inner {
206            EntryInner::Occupied { inner } => inner.get(),
207            EntryInner::Vacant { value, .. } => value,
208            EntryInner::ByRef { value, .. } => value,
209            EntryInner::Dropping => unreachable!(),
210        }
211    }
212}
213impl<Q, K, V, C> DerefMut for Entry<'_, Q, K, V, C>
214where
215    Q: Eq + Hash + ?Sized,
216    K: Eq + Hash + Borrow<Q>,
217    C: Commonality<V>,
218{
219    fn deref_mut(&mut self) -> &mut Self::Target {
220        match &mut self.inner {
221            EntryInner::Occupied { inner } => inner.get_mut(),
222            EntryInner::Vacant { value, .. } => value,
223            EntryInner::ByRef { value, .. } => value,
224            EntryInner::Dropping => unreachable!(),
225        }
226    }
227}
228
229impl<Q, K, V, C> Drop for Entry<'_, Q, K, V, C>
230where
231    Q: Eq + Hash + ?Sized,
232    K: Eq + Hash + Borrow<Q>,
233    C: Commonality<V>,
234{
235    fn drop(&mut self) {
236        match mem::replace(&mut self.inner, EntryInner::Dropping) {
237            EntryInner::Occupied { inner } => {
238                if C::is_common(inner.get()) {
239                    inner.remove();
240                }
241            }
242            EntryInner::Vacant { inner, value } => {
243                if !C::is_common(&value) {
244                    inner.insert(value);
245                }
246            }
247            EntryInner::ByRef { map, key, value } => {
248                if C::is_common(value) {
249                    unsafe { &mut *map }.remove(key);
250                }
251            }
252            EntryInner::Dropping => unreachable!(),
253        }
254    }
255}
256
257impl<'a, Q, K, V, C> Debug for Entry<'a, Q, K, V, C>
258where
259    Q: Debug + Eq + Hash + ?Sized,
260    K: Debug + Eq + Hash + Borrow<Q>,
261    V: Debug,
262    C: Commonality<V>,
263{
264    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
265        let mut f = f.debug_tuple("Entry");
266        match &self.inner {
267            EntryInner::Occupied { inner } => f.field(inner.key()).field(inner.get()),
268            EntryInner::Vacant { inner, value } => f.field(inner.key()).field(value),
269            EntryInner::ByRef { key, value, .. } => f.field(key).field(value),
270            EntryInner::Dropping => &mut f,
271        };
272        f.finish()
273    }
274}
275
276enum EntryInner<'a, Q: ?Sized, K, V, C> {
277    Occupied { inner: hash_map::OccupiedEntry<'a, K, V> },
278    Vacant { inner: hash_map::VacantEntry<'a, K, V>, value: V },
279    ByRef { map: *mut TotalHashMap<K, V, C>, key: &'a Q, value: &'a mut V },
280    Dropping,
281}
282
283// --------------------------------------------------------------------------
284// Iteration
285
286impl<K, V, C> TotalHashMap<K, V, C> {
287    /// An iterator over all keys associated with *uncommon* values in the map, in arbitrary order.
288    pub fn keys(&self) -> Keys<'_, K, V> {
289        Keys(self.inner.keys())
290    }
291    /// Creates a consuming iterator over all keys associated with *uncommon* values in the map, in
292    /// arbitrary order.
293    pub fn into_keys(self) -> IntoKeys<K, V> {
294        IntoKeys(self.inner.into_keys())
295    }
296    /// An iterator over all *uncommon* values in the map, in arbitrary order.
297    pub fn values(&self) -> Values<'_, K, V> {
298        Values(self.inner.values())
299    }
300    /// Creates a consuming iterator over all *uncommon* values in the map, in arbitrary order.
301    pub fn into_values(self) -> IntoValues<K, V> {
302        IntoValues(self.inner.into_values())
303    }
304    /// An iterator over all *uncommon* entries in the map, in arbitrary order.
305    pub fn iter(&self) -> Iter<'_, K, V> {
306        Iter(self.inner.iter())
307    }
308    /// Resets all entries in the map to the *common* value, and returns all previously *uncommon*
309    /// entries as an iterator.
310    pub fn drain(&mut self) -> Drain<'_, K, V> {
311        Drain(self.inner.drain())
312    }
313
314    // We don't offer `values_mut` or `iter_mut` because the mutable references they expose could be
315    // used to violate the invariant that only uncommon values are stored in the map. Trying to
316    // restore the invariant in the iterator's Drop impl would be unsound because nothing prevents
317    // the mutable references from outliving the iterator. We could use the "lending iterator"
318    // pattern (with GATs) to implement `values_mut` and `iter_mut` soundly, but we'd be divorcing
319    // from standard Iterators and all the goodness that comes with them (e.g. for-loops).
320}
321
322impl<K, V, C> IntoIterator for TotalHashMap<K, V, C> {
323    type Item = (K, V);
324    type IntoIter = IntoIter<K, V>;
325    fn into_iter(self) -> Self::IntoIter {
326        IntoIter(self.inner.into_iter())
327    }
328}
329impl<'a, K, V, C> IntoIterator for &'a TotalHashMap<K, V, C> {
330    type Item = (&'a K, &'a V);
331    type IntoIter = Iter<'a, K, V>;
332    fn into_iter(self) -> Self::IntoIter {
333        self.iter()
334    }
335}
336
337/// An iterator over the keys associated with *uncommon* values in a [TotalHashMap].
338///
339/// This iterator is created by [TotalHashMap::keys].
340pub struct Keys<'a, K, V>(hash_map::Keys<'a, K, V>);
341impl<K, V> Clone for Keys<'_, K, V> {
342    fn clone(&self) -> Self {
343        Self(self.0.clone())
344    }
345}
346impl<'a, K, V> Iterator for Keys<'a, K, V> {
347    type Item = &'a K;
348    fn next(&mut self) -> Option<Self::Item> {
349        self.0.next()
350    }
351    fn size_hint(&self) -> (usize, Option<usize>) {
352        self.0.size_hint()
353    }
354}
355impl<K, V> ExactSizeIterator for Keys<'_, K, V> {
356    fn len(&self) -> usize {
357        self.0.len()
358    }
359}
360impl<K, V> FusedIterator for Keys<'_, K, V> {}
361impl<K: Debug, V: Debug> Debug for Keys<'_, K, V> {
362    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
363        f.debug_list().entries(self.clone()).finish()
364    }
365}
366
367/// An owning iterator over the keys associated with *uncommon* values in a [TotalHashMap].
368///
369/// This iterator is created by [TotalHashMap::into_keys].
370pub struct IntoKeys<K, V>(hash_map::IntoKeys<K, V>);
371impl<K, V> Iterator for IntoKeys<K, V> {
372    type Item = K;
373    fn next(&mut self) -> Option<Self::Item> {
374        self.0.next()
375    }
376    fn size_hint(&self) -> (usize, Option<usize>) {
377        self.0.size_hint()
378    }
379}
380impl<K, V> ExactSizeIterator for IntoKeys<K, V> {
381    fn len(&self) -> usize {
382        self.0.len()
383    }
384}
385impl<K, V> FusedIterator for IntoKeys<K, V> {}
386
387/// An iterator over the *uncommon* values in a [TotalHashMap].
388///
389/// This iterator is created by [TotalHashMap::values].
390pub struct Values<'a, K, V>(hash_map::Values<'a, K, V>);
391impl<K, V> Clone for Values<'_, K, V> {
392    fn clone(&self) -> Self {
393        Self(self.0.clone())
394    }
395}
396impl<'a, K, V> Iterator for Values<'a, K, V> {
397    type Item = &'a V;
398    fn next(&mut self) -> Option<Self::Item> {
399        self.0.next()
400    }
401    fn size_hint(&self) -> (usize, Option<usize>) {
402        self.0.size_hint()
403    }
404}
405impl<K, V> ExactSizeIterator for Values<'_, K, V> {
406    fn len(&self) -> usize {
407        self.0.len()
408    }
409}
410impl<K, V> FusedIterator for Values<'_, K, V> {}
411impl<K: Debug, V: Debug> Debug for Values<'_, K, V> {
412    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
413        f.debug_list().entries(self.clone()).finish()
414    }
415}
416
417/// An owning iterator over the *uncommon* values in a [TotalHashMap].
418///
419/// This iterator is created by [TotalHashMap::into_values].
420pub struct IntoValues<K, V>(hash_map::IntoValues<K, V>);
421impl<K, V> Iterator for IntoValues<K, V> {
422    type Item = V;
423    fn next(&mut self) -> Option<Self::Item> {
424        self.0.next()
425    }
426    fn size_hint(&self) -> (usize, Option<usize>) {
427        self.0.size_hint()
428    }
429}
430impl<K, V> ExactSizeIterator for IntoValues<K, V> {
431    fn len(&self) -> usize {
432        self.0.len()
433    }
434}
435impl<K, V> FusedIterator for IntoValues<K, V> {}
436
437/// An iterator over the *uncommon* entries in a [TotalHashMap].
438///
439/// This iterator is created by [TotalHashMap::iter].
440pub struct Iter<'a, K, V>(hash_map::Iter<'a, K, V>);
441impl<K, V> Clone for Iter<'_, K, V> {
442    fn clone(&self) -> Self {
443        Self(self.0.clone())
444    }
445}
446impl<'a, K, V> Iterator for Iter<'a, K, V> {
447    type Item = (&'a K, &'a V);
448    fn next(&mut self) -> Option<Self::Item> {
449        self.0.next()
450    }
451    fn size_hint(&self) -> (usize, Option<usize>) {
452        self.0.size_hint()
453    }
454}
455impl<K, V> ExactSizeIterator for Iter<'_, K, V> {
456    fn len(&self) -> usize {
457        self.0.len()
458    }
459}
460impl<K, V> FusedIterator for Iter<'_, K, V> {}
461impl<K: Debug, V: Debug> Debug for Iter<'_, K, V> {
462    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
463        f.debug_list().entries(self.clone()).finish()
464    }
465}
466
467/// An owning iterator over the *uncommon* entries in a [TotalHashMap].
468///
469/// This iterator is created by [TotalHashMap]'s implementation of [IntoIterator].
470pub struct IntoIter<K, V>(hash_map::IntoIter<K, V>);
471impl<K, V> Iterator for IntoIter<K, V> {
472    type Item = (K, V);
473    fn next(&mut self) -> Option<Self::Item> {
474        self.0.next()
475    }
476    fn size_hint(&self) -> (usize, Option<usize>) {
477        self.0.size_hint()
478    }
479}
480impl<K, V> ExactSizeIterator for IntoIter<K, V> {
481    fn len(&self) -> usize {
482        self.0.len()
483    }
484}
485impl<K, V> FusedIterator for IntoIter<K, V> {}
486
487/// A draining iterator over the *uncommon* entries in a [TotalHashMap].
488///
489/// This iterator is created by [TotalHashMap::drain].
490pub struct Drain<'a, K, V>(hash_map::Drain<'a, K, V>);
491impl<K, V> Iterator for Drain<'_, K, V> {
492    type Item = (K, V);
493    fn next(&mut self) -> Option<Self::Item> {
494        self.0.next()
495    }
496    fn size_hint(&self) -> (usize, Option<usize>) {
497        self.0.size_hint()
498    }
499}
500impl<K, V> ExactSizeIterator for Drain<'_, K, V> {
501    fn len(&self) -> usize {
502        self.0.len()
503    }
504}
505impl<K, V> FusedIterator for Drain<'_, K, V> {}
506
507// --------------------------------------------------------------------------
508// Population from iterators
509
510impl<K: Eq + Hash, V, C: Commonality<V>> Extend<(K, V)> for TotalHashMap<K, V, C> {
511    fn extend<T: IntoIterator<Item = (K, V)>>(&mut self, iter: T) {
512        for (key, value) in iter {
513            self.insert(key, value);
514        }
515    }
516}
517impl<K: Eq + Hash, V, C: Commonality<V>> FromIterator<(K, V)> for TotalHashMap<K, V, C> {
518    fn from_iter<T: IntoIterator<Item = (K, V)>>(iter: T) -> Self {
519        let mut this = Self::default();
520        this.extend(iter);
521        this
522    }
523}
524
525// --------------------------------------------------------------------------
526// Low-level access
527
528impl<K, V, C> TotalHashMap<K, V, C> {
529    /// Returns a view into the underlying [HashMap] of a [TotalHashMap], which contains the
530    /// *uncommon* entries.
531    pub fn as_hash_map(&self) -> &HashMap<K, V> {
532        &self.inner
533    }
534}
535
536impl<K, V, C: Commonality<V>> TotalHashMap<K, V, C> {
537    /// Returns a mutable view into the underlying [HashMap] of a [TotalHashMap], from which
538    /// mutating iterators can be obtained by calling [HashMap::values_mut] or [HashMap::iter_mut].
539    ///
540    /// By directly mutating the underlying [HashMap], it is possible to store *uncommon* entries in
541    /// the map temporarily. When the returned view is dropped, all *uncommon* entries will be
542    /// removed, restoring the invariant of [TotalHashMap].
543    ///
544    /// You don't need this method if you are only mutating individual entries; use the
545    /// [entry][Self::entry] method instead.
546    pub fn as_hash_map_mut(&mut self) -> AsHashMapMut<'_, K, V, C> {
547        AsHashMapMut { map: &mut self.inner, _commonality: PhantomPtr::default() }
548    }
549}
550
551/// A mutable view into the underlying [HashMap] of a [TotalHashMap].
552///
553/// This view is created by [TotalHashMap::as_hash_map_mut].
554pub struct AsHashMapMut<'a, K, V, C: Commonality<V> = DefaultCommonality> {
555    map: &'a mut HashMap<K, V>,
556    _commonality: PhantomPtr<C>,
557}
558
559impl<K, V, C: Commonality<V>> Deref for AsHashMapMut<'_, K, V, C> {
560    type Target = HashMap<K, V>;
561    fn deref(&self) -> &Self::Target {
562        self.map
563    }
564}
565impl<K, V, C: Commonality<V>> DerefMut for AsHashMapMut<'_, K, V, C> {
566    fn deref_mut(&mut self) -> &mut Self::Target {
567        self.map
568    }
569}
570
571impl<K, V, C: Commonality<V>> Drop for AsHashMapMut<'_, K, V, C> {
572    fn drop(&mut self) {
573        self.map.retain(|_, value| !C::is_common(value));
574    }
575}
576
577impl<K: Eq + Hash, V: PartialEq, C: Commonality<V>> PartialEq for AsHashMapMut<'_, K, V, C> {
578    fn eq(&self, other: &Self) -> bool {
579        // deliberately ignoring commonality
580        self.map == other.map
581    }
582}
583impl<K: Eq + Hash, V: Eq, C: Commonality<V>> Eq for AsHashMapMut<'_, K, V, C> {}
584impl<K: Debug, V: Debug, C: Commonality<V>> Debug for AsHashMapMut<'_, K, V, C> {
585    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
586        f.debug_tuple("AsHashMapMut").field(&self.map).finish()
587    }
588}
589
590// --------------------------------------------------------------------------
591// Miscellaneous traits
592
593impl<K: Eq + Hash, V: PartialEq, C> PartialEq for TotalHashMap<K, V, C> {
594    fn eq(&self, other: &Self) -> bool {
595        self.inner == other.inner
596    }
597}
598impl<K: Eq + Hash, V: Eq, C: Commonality<V>> Eq for TotalHashMap<K, V, C> {}
599
600impl<K: Debug, V: Debug, C> Debug for TotalHashMap<K, V, C> {
601    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
602        f.debug_map().entries(self.iter()).finish_non_exhaustive()
603    }
604}