inttable/
lib.rs

1//! This crate serves as a replacement for `intmap` in cases where the keys you are working with
2//! are already hashed. This is essentially just a wrapper around a `hashbrown::HashTable<V>` (with
3//! the added detail that the keys are stored alongside the values).
4//!
5//! This is significantly faster than `intmap` or the built-in [`std::collections::HashMap`] type,
6//! as it performs _no_ hashing. Thus, if your keys are not randomly distributed, performance
7//! can take a nosedive.
8//!
9//! And yes, I realise this crate is basically a "leftpad", but it can potentially save a tonne of
10//! boilerplate. I had to write it anyway since, so I might as well clean it up and publish it.
11//!
12//! A lot of surrounding code (i.e., tests and benchmarks) was taken as-is from `intmap`.
13#[cfg(feature = "serde")]
14mod serde;
15
16use std::ops::Index;
17
18pub use hashbrown::HashTable;
19use hashbrown::TryReserveError;
20
21/// A Map associating unique integers and randomly distributed integers to values.
22///
23/// Tries to match [`std::collections::HashMap`]'s API, but leaves out functions that either don't
24/// apply (anything to do with hashers), or that just don't make sense (like
25/// [`std::collections::HashMap::get_key_value`], as the key can just be copied).
26///
27/// This is also the reason why this doesn't include any code examples. In fact, I could leave this
28/// entire crate undocumented and just tell you to look at the built-in hashmap.
29pub struct IntTable<V> {
30    /// The hashtable actually working
31    inner: HashTable<(u64, V)>,
32}
33
34impl<V> IntTable<V> {
35    /// Creates a new, zero-capacity hashtable that will grow with insertions.
36    pub const fn new() -> Self {
37        Self {
38            inner: HashTable::new(),
39        }
40    }
41
42    /// Creates a new IntTable with the given capacity.
43    pub fn with_capacity(capacity: usize) -> Self {
44        Self {
45            inner: HashTable::with_capacity(capacity),
46        }
47    }
48
49    /// Removes the given key from the table, returning its associated value.
50    pub fn remove(&mut self, key: u64) -> Option<V> {
51        self.inner
52            .find_entry(key, eq(key))
53            .ok()
54            .map(|v| v.remove().0 .1)
55    }
56
57    /// Shrinks the capacity of the table with a lower limit. It will drop down no lower than the
58    /// supplied limit.
59    pub fn shrink_to(&mut self, min_capacity: usize) {
60        self.inner.shrink_to(min_capacity, hasher)
61    }
62
63    /// Shrinks the capacity of the underlying table to the number of elements it contains.
64    pub fn shrink_to_fit(&mut self) {
65        self.inner.shrink_to_fit(hasher)
66    }
67
68    /// Reserves at least `additional` spots in the backing allocation. This might allocate more.
69    /// You know the drill.
70    pub fn reserve(&mut self, additional: usize) {
71        self.inner.reserve(additional, hasher)
72    }
73
74    /// Returns the map's capacity
75    pub fn capacity(&self) -> usize {
76        self.inner.capacity()
77    }
78
79    /// Removes all elements from self
80    pub fn clear(&mut self) {
81        self.inner.clear()
82    }
83
84    /// Insertns the given key-value pair into the table, returning the old value at `key` if there
85    /// was one.
86    pub fn insert(&mut self, key: u64, value: V) -> Option<V> {
87        use hashbrown::hash_table::Entry;
88        match self.inner.entry(key, eq(key), hasher) {
89            Entry::Occupied(o) => {
90                let ((_, old_val), empty) = o.remove();
91                empty.insert((key, value));
92                Some(old_val)
93            }
94            Entry::Vacant(v) => {
95                v.insert((key, value));
96                None
97            }
98        }
99    }
100
101    /// Attempts to insert `value` at `key`, but if `key` was occupied, this function doesn't
102    /// replace the old value.
103    pub fn try_insert(&mut self, key: u64, value: V) -> Result<&mut V, V> {
104        use hashbrown::hash_table::Entry;
105        match self.inner.entry(key, eq(key), hasher) {
106            Entry::Occupied(_) => Err(value),
107            Entry::Vacant(v) => {
108                let entry = v.insert((key, value));
109                Ok(&mut entry.into_mut().1)
110            }
111        }
112    }
113
114    /// Tries to reserve addional capacity, but doesn't abort the programme on failure.
115    pub fn try_reserve(&mut self, additional: usize) -> Result<(), TryReserveError> {
116        self.inner.try_reserve(additional, hasher)
117    }
118
119    /// Returns the value at `key`
120    pub fn get(&self, key: u64) -> Option<&V> {
121        self.inner.find(key, eq(key)).map(|(_, v)| v)
122    }
123
124    /// Returns a mutable reference to the value at `key`
125    pub fn get_mut(&mut self, key: u64) -> Option<&mut V> {
126        self.inner.find_mut(key, eq(key)).map(|(_, v)| v)
127    }
128
129    /// Attempts to get mutable references to `N` values in the map at once.
130    ///
131    /// Returns an array of length `N` with the results of each query. For soundness, at most one
132    /// mutable reference will be returned to any value. `None` will be returned if any of the keys
133    /// are duplicates or missing.
134    pub fn get_many_mut<const N: usize>(&mut self, ks: [u64; N]) -> Option<[&mut V; N]> {
135        self.inner
136            .get_many_mut(ks, |idx, (k, _)| ks[idx] == *k)
137            .map(|a| a.map(|(_, v)| v))
138    }
139
140    /// Attempts to get mutable references to `N` values in the map at once, without validating
141    /// that the values are unique.
142    ///
143    /// Returns an array of length N with the resultsn of each query.
144    /// `None` will be returned if one of the keys are missing.
145    ///
146    /// For a safe alternative see `[get_many_mut]`
147    /// # Safety
148    /// Calling this method with overlapping keys is undefined behaviour even if the
149    /// resulting references are not used.
150    pub unsafe fn get_many_unchecked_mut<const N: usize>(
151        &mut self,
152        ks: [u64; N],
153    ) -> Option<[&mut V; N]> {
154        self.inner
155            .get_many_unchecked_mut(ks, |idx, (k, _)| ks[idx] == *k)
156            .map(|a| a.map(|(_, v)| v))
157    }
158
159    /// Removes all values for which `p` evaluates to `false`.
160    pub fn retain<F>(&mut self, mut p: F)
161    where
162        F: FnMut(&u64, &mut V) -> bool,
163    {
164        self.inner.retain(|(key, val)| p(&*key, val))
165    }
166
167    /// Returns an iterator over the keys
168    pub fn keys(&self) -> impl Iterator<Item = &u64> {
169        self.inner.iter().map(|(key, _)| key)
170    }
171
172    /// Returns an iterator over the values
173    pub fn values(&self) -> impl Iterator<Item = &V> {
174        self.inner.iter().map(|(_, val)| val)
175    }
176
177    /// Returns an iterator over mutable references to the stored values
178    pub fn values_mut(&mut self) -> impl Iterator<Item = &mut V> {
179        self.inner.iter_mut().map(|(_, val)| val)
180    }
181
182    /// Self-documenting.
183    pub fn contains_key(&self, key: u64) -> bool {
184        self.get(key).is_some()
185    }
186
187    /// Gets the given key's corresponding entry in the map for in-place manipulation.
188    pub fn entry(&mut self, key: u64) -> Entry<V> {
189        match self.inner.entry(key, eq(key), hasher) {
190            hashbrown::hash_table::Entry::Occupied(o) => Entry::Occupied(OccupiedEntry(o)),
191            hashbrown::hash_table::Entry::Vacant(v) => Entry::Vacant(VacantEntry(v, key)),
192        }
193    }
194
195    /// Returns the number of elements in the map
196    pub fn len(&self) -> usize {
197        self.inner.len()
198    }
199
200    /// Self-documenting.
201    pub fn is_empty(&self) -> bool {
202        self.inner().len() == 0
203    }
204
205    /// Returns an iterator over the mutable values, but provides a key. For API consistency, it
206    /// returns a reference to the key as well (instead of passing it by value).
207    pub fn iter_mut(&mut self) -> impl Iterator<Item = (&u64, &mut V)> {
208        self.inner.iter_mut().map(|(key, val)| (&*key, val))
209    }
210
211    /// Removes all values from self and returns an iterator over all (key, value) pairs.
212    pub fn drain(&mut self) -> impl Iterator<Item = (u64, V)> + '_ {
213        self.inner.drain()
214    }
215
216    /// Returns an iterator over all (key, value) pairs.
217    pub fn iter(&self) -> impl Iterator<Item = (&u64, &V)> {
218        self.inner().iter().map(|(k, v)| (k, v))
219    }
220
221    /// Like [`Self::retain`], but allows you to reuse the values removed in this fashion. Also,
222    /// this one removes the value if the predicate evaluates to `true`.
223    ///
224    /// Note that this lets the filter closure mutate every value, regardless of whether or not it
225    /// shall be kept in the map.
226    ///
227    /// If the returned iterator is not exhausted, like if it was dropped without iterating or the
228    /// iteration short-circuits, then the remaining elements will be retained.
229    pub fn extract_if<F>(&mut self, mut f: F) -> ExtractIf<'_, V, impl FnMut(&mut (u64, V)) -> bool>
230    where
231        F: FnMut(&u64, &mut V) -> bool,
232    {
233        ExtractIf(self.inner.extract_if(move |(k, v)| f(&*k, v)))
234    }
235
236    /// Consumes self and returns an iterator over its keys.
237    pub fn into_keys(self) -> impl Iterator<Item = u64> {
238        self.into_iter().map(|(k, _)| k)
239    }
240
241    /// Consumes self and returns an iterator over its values.
242    pub fn into_values(self) -> impl Iterator<Item = V> {
243        self.into_iter().map(|(_, v)| v)
244    }
245}
246
247impl<V> FromIterator<(u64, V)> for IntTable<V> {
248    /// Constructs an IntTable from an iterator. Note that this deduplicates the values and keeps
249    /// the *last* value.
250    fn from_iter<T: IntoIterator<Item = (u64, V)>>(iter: T) -> Self {
251        let mut res = Self::new();
252        res.extend(iter);
253        res
254    }
255}
256
257impl<V> Default for IntTable<V> {
258    fn default() -> Self {
259        Self::new()
260    }
261}
262
263impl<V> IntoIterator for IntTable<V> {
264    type Item = (u64, V);
265
266    type IntoIter = IntTableIter<Self::Item>;
267
268    fn into_iter(self) -> Self::IntoIter {
269        let it = self.inner.into_iter();
270        IntTableIter(it)
271    }
272}
273
274impl<V> Index<u64> for IntTable<V> {
275    type Output = V;
276
277    fn index(&self, index: u64) -> &Self::Output {
278        self.get(index).expect("Key not in map")
279    }
280}
281
282impl<V> IntTable<V> {
283    /// Returns the inner hashtable for your viewing pleasure.
284    pub fn inner(&self) -> &HashTable<(u64, V)> {
285        &self.inner
286    }
287
288    /// Unwraps the inner hashtable.
289    pub fn into_inner(self) -> HashTable<(u64, V)> {
290        self.inner
291    }
292}
293
294/// Iterator over extracted values.
295pub struct ExtractIf<'a, T, F: FnMut(&mut (u64, T)) -> bool>(
296    ::hashbrown::hash_table::ExtractIf<'a, (u64, T), F>,
297);
298
299impl<V, F> Iterator for ExtractIf<'_, V, F>
300where
301    F: FnMut(&mut (u64, V)) -> bool,
302{
303    type Item = (u64, V);
304
305    fn next(&mut self) -> Option<Self::Item> {
306        self.0.next()
307    }
308
309    fn size_hint(&self) -> (usize, Option<usize>) {
310        self.0.size_hint()
311    }
312}
313
314/// An IntTable entry
315#[derive(Debug)]
316pub enum Entry<'a, V> {
317    /// Entry was occupied
318    Occupied(OccupiedEntry<'a, V>),
319    /// Entry was empty
320    Vacant(VacantEntry<'a, V>),
321}
322
323impl<'a, V> Entry<'a, V> {
324    /// Ensures a value is in the entry by inserting the default if empty, and returns a mutable
325    /// reference to the value in the entry.
326    pub fn or_insert(self, default: V) -> &'a mut V {
327        match self {
328            Entry::Occupied(o) => o.into_mut(),
329            Entry::Vacant(v) => v.insert(default),
330        }
331    }
332
333    /// Ensures a value is in the entry by inserting the default if empty, and returns a mutable
334    /// reference to the value in the entry. Only calls the closure if the entry is empty.
335    pub fn or_insert_with<F>(self, default: F) -> &'a mut V
336    where
337        F: FnOnce() -> V,
338    {
339        match self {
340            Entry::Occupied(o) => o.into_mut(),
341            Entry::Vacant(v) => v.insert(default()),
342        }
343    }
344
345    /// Ensures a value is in the entry by inserting the default if empty, and returns a mutable
346    /// reference to the value in the entry. Only calls the closure if the entry is empty.
347    pub fn or_insert_with_key<F>(self, default: F) -> &'a mut V
348    where
349        F: FnOnce(&u64) -> V,
350    {
351        match self {
352            Entry::Occupied(o) => o.into_mut(),
353            Entry::Vacant(v) => {
354                let key = v.1;
355                v.insert(default(&key))
356            }
357        }
358    }
359
360    /// Returns the key for this entry
361    pub fn key(&self) -> &u64 {
362        match self {
363            Entry::Occupied(o) => &o.0.get().0,
364            Entry::Vacant(v) => &v.1,
365        }
366    }
367
368    /// Provides in-place mutable access to an occupied entry before any potential inserts into the
369    /// map
370    pub fn and_modify<F>(mut self, f: F) -> Self
371    where
372        F: FnOnce(&mut V),
373    {
374        if let Entry::Occupied(o) = &mut self {
375            f(o.get_mut())
376        };
377        self
378    }
379
380    /// Sets the value of the entry and returns an [`OccupiedEntry`].
381    pub fn insert_entry(self, value: V) -> OccupiedEntry<'a, V> {
382        match self {
383            Entry::Occupied(mut o) => {
384                o.insert(value);
385                o
386            }
387            Entry::Vacant(v) => v.insert_entry(value),
388        }
389    }
390}
391
392impl<'a, V> Entry<'a, V>
393where
394    V: Default,
395{
396    /// Sets the value to the default
397    pub fn or_default(self) -> &'a mut V {
398        #[allow(clippy::unwrap_or_default)] // Thank you clippy, very cool
399        self.or_insert(V::default())
400    }
401}
402
403/// Allows for in-place manipulation of existing table entries
404#[derive(Debug)]
405pub struct OccupiedEntry<'a, V>(::hashbrown::hash_table::OccupiedEntry<'a, (u64, V)>);
406/// Allows for in-place manipulation of vacant table entries
407#[derive(Debug)]
408pub struct VacantEntry<'a, V>(::hashbrown::hash_table::VacantEntry<'a, (u64, V)>, u64);
409
410impl<'a, V> OccupiedEntry<'a, V> {
411    /// Returns the value pointed to by this entry
412    pub fn get(&self) -> &V {
413        &self.0.get().1
414    }
415
416    /// Returns a mutable reference to the value pointed to by this entry
417    pub fn get_mut(&mut self) -> &mut V {
418        &mut self.0.get_mut().1
419    }
420
421    /// Inserts a new value into the entry, returning the old one.
422    pub fn insert(&mut self, new_val: V) -> V {
423        std::mem::replace(self.get_mut(), new_val)
424    }
425
426    /// Consumes this entry and returns the raw mutable reference of the value.
427    pub fn into_mut(self) -> &'a mut V {
428        &mut self.0.into_mut().1
429    }
430
431    /// Removes the value, leaving it empty.
432    pub fn remove(self) -> V {
433        self.0.remove().0 .1
434    }
435
436    /// Take the ownership of the key and value from the map.
437    pub fn remove_entry(self) -> (u64, V) {
438        self.0.remove().0
439    }
440
441    /// Returns the entry's key
442    pub fn key(&self) -> &u64 {
443        &self.0.get().0
444    }
445}
446
447impl<'a, V> VacantEntry<'a, V> {
448    /// Sets the value of the entry, and returns a mutable reference to it.
449    pub fn insert(self, value: V) -> &'a mut V {
450        let key = self.1;
451        &mut self.0.insert((key, value)).into_mut().1
452    }
453
454    /// Sets the value of the entry and returns the [`OccupiedEntry`]
455    fn insert_entry(self, value: V) -> OccupiedEntry<'a, V> {
456        OccupiedEntry(self.0.insert((self.1, value)))
457    }
458
459    /// Returns the key for this entry
460    pub fn key(&self) -> &u64 {
461        &self.1
462    }
463}
464
465/// Convenience function to not have to retype this every time lol
466fn eq<V>(key: u64) -> impl Fn(&(u64, V)) -> bool {
467    move |(other_key, _)| *other_key == key
468}
469
470/// Convenience function
471fn hasher<V>((key, _value): &(u64, V)) -> u64 {
472    *key
473}
474
475/// Wrapper around an owned iterator from an [`IntTable`]
476pub struct IntTableIter<V>(::hashbrown::hash_table::IntoIter<V>);
477impl<V> ExactSizeIterator for IntTableIter<V> {}
478
479impl<V> Iterator for IntTableIter<V> {
480    fn size_hint(&self) -> (usize, Option<usize>) {
481        let l = self.0.len();
482        (l, Some(l))
483    }
484
485    fn count(self) -> usize
486    where
487        Self: Sized,
488    {
489        self.len()
490    }
491
492    type Item = V;
493
494    fn next(&mut self) -> Option<Self::Item> {
495        self.0.next()
496    }
497}
498
499impl<V> Extend<(u64, V)> for IntTable<V> {
500    fn extend<T: IntoIterator<Item = (u64, V)>>(&mut self, iter: T) {
501        let iter = iter.into_iter();
502        let (min, max) = iter.size_hint();
503        self.reserve(max.unwrap_or(min));
504        for (k, v) in iter {
505            self.insert(k, v);
506        }
507    }
508}
509
510impl<V> PartialEq for IntTable<V>
511where
512    V: PartialEq,
513{
514    fn eq(&self, other: &IntTable<V>) -> bool {
515        self.iter().eq(other.iter())
516    }
517}
518
519impl<V> std::fmt::Debug for IntTable<V>
520where
521    V: std::fmt::Debug,
522{
523    fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result {
524        let mut map_debug = fmt.debug_map();
525        for (k, v) in self.iter() {
526            map_debug.key(k);
527            map_debug.value(v);
528        }
529
530        map_debug.finish()
531    }
532}