Skip to main content

axhash_map/
lib.rs

1use core::fmt;
2use core::hash::{BuildHasher, Hash};
3use core::ops::{Deref, DerefMut, Index};
4
5pub use axhash_core::AxBuildHasher;
6pub use hashbrown::{HashMap as RawHashMap, HashSet as RawHashSet};
7
8// ── AxHashMap ────────────────────────────────────────────────────────────────
9pub struct AxHashMap<K, V, S = AxBuildHasher>(RawHashMap<K, V, S>);
10
11impl<K, V> AxHashMap<K, V, AxBuildHasher> {
12    /// Creates an empty map with the default [`AxBuildHasher`].
13    ///
14    /// The map is initially created with a capacity of 0 and will reallocate
15    /// as elements are inserted.
16    #[inline]
17    pub fn new() -> Self {
18        Self(RawHashMap::with_hasher(AxBuildHasher::new()))
19    }
20
21    /// Creates an empty map with at least the given capacity and the default
22    /// [`AxBuildHasher`].
23    ///
24    /// The map will be able to hold at least `capacity` elements without
25    /// reallocating.
26    #[inline]
27    pub fn with_capacity(capacity: usize) -> Self {
28        Self(RawHashMap::with_capacity_and_hasher(
29            capacity,
30            AxBuildHasher::new(),
31        ))
32    }
33}
34
35impl<K, V, S: BuildHasher> AxHashMap<K, V, S> {
36    /// Creates an empty map that uses the supplied `hasher`.
37    ///
38    /// Use this when you need a custom seed or a completely different
39    /// [`BuildHasher`].
40    #[inline]
41    pub fn with_hasher(hasher: S) -> Self {
42        Self(RawHashMap::with_hasher(hasher))
43    }
44
45    /// Creates an empty map with at least the given capacity that uses the
46    /// supplied `hasher`.
47    #[inline]
48    pub fn with_capacity_and_hasher(capacity: usize, hasher: S) -> Self {
49        Self(RawHashMap::with_capacity_and_hasher(capacity, hasher))
50    }
51
52    /// Consumes the wrapper and returns the underlying [`RawHashMap`].
53    #[inline]
54    pub fn into_inner(self) -> RawHashMap<K, V, S> {
55        self.0
56    }
57}
58
59// ── Deref / DerefMut ─────────────────────────────────────────────────────────
60
61impl<K, V, S> Deref for AxHashMap<K, V, S> {
62    type Target = RawHashMap<K, V, S>;
63
64    #[inline]
65    fn deref(&self) -> &Self::Target {
66        &self.0
67    }
68}
69
70impl<K, V, S> DerefMut for AxHashMap<K, V, S> {
71    #[inline]
72    fn deref_mut(&mut self) -> &mut Self::Target {
73        &mut self.0
74    }
75}
76
77// ── Standard traits ───────────────────────────────────────────────────────────
78
79impl<K, V> Default for AxHashMap<K, V, AxBuildHasher> {
80    #[inline]
81    fn default() -> Self {
82        Self::new()
83    }
84}
85
86impl<K: fmt::Debug, V: fmt::Debug, S> fmt::Debug for AxHashMap<K, V, S> {
87    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
88        self.0.fmt(f)
89    }
90}
91
92impl<K: Clone, V: Clone, S: Clone> Clone for AxHashMap<K, V, S> {
93    #[inline]
94    fn clone(&self) -> Self {
95        Self(self.0.clone())
96    }
97}
98
99impl<K: Hash + Eq, V: PartialEq, S: BuildHasher> PartialEq for AxHashMap<K, V, S> {
100    fn eq(&self, other: &Self) -> bool {
101        self.0 == other.0
102    }
103}
104
105impl<K: Hash + Eq, V: Eq, S: BuildHasher> Eq for AxHashMap<K, V, S> {}
106
107impl<K, Q, V, S> Index<&Q> for AxHashMap<K, V, S>
108where
109    K: Hash + Eq + core::borrow::Borrow<Q>,
110    Q: Hash + Eq + ?Sized,
111    S: BuildHasher,
112{
113    type Output = V;
114
115    #[inline]
116    fn index(&self, key: &Q) -> &Self::Output {
117        self.0.index(key)
118    }
119}
120
121// ── FromIterator / Extend ─────────────────────────────────────────────────────
122
123impl<K: Hash + Eq, V> FromIterator<(K, V)> for AxHashMap<K, V, AxBuildHasher> {
124    fn from_iter<I: IntoIterator<Item = (K, V)>>(iter: I) -> Self {
125        let iter = iter.into_iter();
126        let (lower, _) = iter.size_hint();
127        let mut map = Self::with_capacity(lower);
128        map.extend(iter);
129        map
130    }
131}
132
133impl<K: Hash + Eq, V, S: BuildHasher> Extend<(K, V)> for AxHashMap<K, V, S> {
134    #[inline]
135    fn extend<I: IntoIterator<Item = (K, V)>>(&mut self, iter: I) {
136        self.0.extend(iter);
137    }
138}
139
140impl<'a, K: Hash + Eq + Copy, V: Copy, S: BuildHasher> Extend<(&'a K, &'a V)>
141    for AxHashMap<K, V, S>
142{
143    #[inline]
144    fn extend<I: IntoIterator<Item = (&'a K, &'a V)>>(&mut self, iter: I) {
145        self.0.extend(iter);
146    }
147}
148
149// ── IntoIterator ──────────────────────────────────────────────────────────────
150
151impl<K, V, S> IntoIterator for AxHashMap<K, V, S> {
152    type Item = (K, V);
153    type IntoIter = hashbrown::hash_map::IntoIter<K, V>;
154
155    #[inline]
156    fn into_iter(self) -> Self::IntoIter {
157        self.0.into_iter()
158    }
159}
160
161impl<'a, K, V, S> IntoIterator for &'a AxHashMap<K, V, S> {
162    type Item = (&'a K, &'a V);
163    type IntoIter = hashbrown::hash_map::Iter<'a, K, V>;
164
165    #[inline]
166    fn into_iter(self) -> Self::IntoIter {
167        self.0.iter()
168    }
169}
170
171impl<'a, K, V, S> IntoIterator for &'a mut AxHashMap<K, V, S> {
172    type Item = (&'a K, &'a mut V);
173    type IntoIter = hashbrown::hash_map::IterMut<'a, K, V>;
174
175    #[inline]
176    fn into_iter(self) -> Self::IntoIter {
177        self.0.iter_mut()
178    }
179}
180
181// ── From conversions ──────────────────────────────────────────────────────────
182
183impl<K, V, S> From<RawHashMap<K, V, S>> for AxHashMap<K, V, S> {
184    #[inline]
185    fn from(inner: RawHashMap<K, V, S>) -> Self {
186        Self(inner)
187    }
188}
189
190impl<K, V, S> From<AxHashMap<K, V, S>> for RawHashMap<K, V, S> {
191    #[inline]
192    fn from(wrapper: AxHashMap<K, V, S>) -> Self {
193        wrapper.0
194    }
195}
196
197// ── AxHashSet ────────────────────────────────────────────────────────────────
198pub struct AxHashSet<T, S = AxBuildHasher>(RawHashSet<T, S>);
199
200impl<T> AxHashSet<T, AxBuildHasher> {
201    /// Creates an empty set with the default [`AxBuildHasher`].
202    #[inline]
203    pub fn new() -> Self {
204        Self(RawHashSet::with_hasher(AxBuildHasher::new()))
205    }
206
207    /// Creates an empty set with at least the given capacity and the default
208    /// [`AxBuildHasher`].
209    #[inline]
210    pub fn with_capacity(capacity: usize) -> Self {
211        Self(RawHashSet::with_capacity_and_hasher(
212            capacity,
213            AxBuildHasher::new(),
214        ))
215    }
216}
217
218impl<T, S: BuildHasher> AxHashSet<T, S> {
219    /// Creates an empty set that uses the supplied `hasher`.
220    #[inline]
221    pub fn with_hasher(hasher: S) -> Self {
222        Self(RawHashSet::with_hasher(hasher))
223    }
224
225    /// Creates an empty set with at least the given capacity that uses the
226    /// supplied `hasher`.
227    #[inline]
228    pub fn with_capacity_and_hasher(capacity: usize, hasher: S) -> Self {
229        Self(RawHashSet::with_capacity_and_hasher(capacity, hasher))
230    }
231
232    /// Consumes the wrapper and returns the underlying [`RawHashSet`].
233    #[inline]
234    pub fn into_inner(self) -> RawHashSet<T, S> {
235        self.0
236    }
237}
238
239// ── Deref / DerefMut ─────────────────────────────────────────────────────────
240
241impl<T, S> Deref for AxHashSet<T, S> {
242    type Target = RawHashSet<T, S>;
243
244    #[inline]
245    fn deref(&self) -> &Self::Target {
246        &self.0
247    }
248}
249
250impl<T, S> DerefMut for AxHashSet<T, S> {
251    #[inline]
252    fn deref_mut(&mut self) -> &mut Self::Target {
253        &mut self.0
254    }
255}
256
257// ── Standard traits ───────────────────────────────────────────────────────────
258
259impl<T> Default for AxHashSet<T, AxBuildHasher> {
260    #[inline]
261    fn default() -> Self {
262        Self::new()
263    }
264}
265
266impl<T: fmt::Debug, S> fmt::Debug for AxHashSet<T, S> {
267    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
268        self.0.fmt(f)
269    }
270}
271
272impl<T: Clone, S: Clone> Clone for AxHashSet<T, S> {
273    #[inline]
274    fn clone(&self) -> Self {
275        Self(self.0.clone())
276    }
277}
278
279impl<T: Hash + Eq, S: BuildHasher> PartialEq for AxHashSet<T, S> {
280    fn eq(&self, other: &Self) -> bool {
281        self.0 == other.0
282    }
283}
284
285impl<T: Hash + Eq, S: BuildHasher> Eq for AxHashSet<T, S> {}
286
287// ── FromIterator / Extend ─────────────────────────────────────────────────────
288
289impl<T: Hash + Eq> FromIterator<T> for AxHashSet<T, AxBuildHasher> {
290    fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> Self {
291        let iter = iter.into_iter();
292        let (lower, _) = iter.size_hint();
293        let mut set = Self::with_capacity(lower);
294        set.extend(iter);
295        set
296    }
297}
298
299impl<T: Hash + Eq, S: BuildHasher> Extend<T> for AxHashSet<T, S> {
300    #[inline]
301    fn extend<I: IntoIterator<Item = T>>(&mut self, iter: I) {
302        self.0.extend(iter);
303    }
304}
305
306impl<'a, T: Hash + Eq + Copy, S: BuildHasher> Extend<&'a T> for AxHashSet<T, S> {
307    #[inline]
308    fn extend<I: IntoIterator<Item = &'a T>>(&mut self, iter: I) {
309        self.0.extend(iter);
310    }
311}
312
313// ── IntoIterator ──────────────────────────────────────────────────────────────
314
315impl<T, S> IntoIterator for AxHashSet<T, S> {
316    type Item = T;
317    type IntoIter = hashbrown::hash_set::IntoIter<T>;
318
319    #[inline]
320    fn into_iter(self) -> Self::IntoIter {
321        self.0.into_iter()
322    }
323}
324
325impl<'a, T, S> IntoIterator for &'a AxHashSet<T, S> {
326    type Item = &'a T;
327    type IntoIter = hashbrown::hash_set::Iter<'a, T>;
328
329    #[inline]
330    fn into_iter(self) -> Self::IntoIter {
331        self.0.iter()
332    }
333}
334
335// ── From conversions ──────────────────────────────────────────────────────────
336
337impl<T, S> From<RawHashSet<T, S>> for AxHashSet<T, S> {
338    #[inline]
339    fn from(inner: RawHashSet<T, S>) -> Self {
340        Self(inner)
341    }
342}
343
344impl<T, S> From<AxHashSet<T, S>> for RawHashSet<T, S> {
345    #[inline]
346    fn from(wrapper: AxHashSet<T, S>) -> Self {
347        wrapper.0
348    }
349}
350
351// ── Tests ─────────────────────────────────────────────────────────────────────
352
353#[cfg(test)]
354mod tests {
355    use super::*;
356
357    #[test]
358    fn map_basic_operations() {
359        let mut map: AxHashMap<&str, u32> = AxHashMap::new();
360        assert!(map.is_empty());
361
362        map.insert("one", 1);
363        map.insert("two", 2);
364        map.insert("three", 3);
365
366        assert_eq!(map.len(), 3);
367        assert_eq!(map["one"], 1);
368        assert_eq!(map.get("two"), Some(&2));
369        assert_eq!(map.get("missing"), None);
370
371        map.remove("two");
372        assert_eq!(map.len(), 2);
373    }
374
375    #[test]
376    fn map_with_capacity() {
377        let map: AxHashMap<u32, u32> = AxHashMap::with_capacity(128);
378        assert!(map.capacity() >= 128);
379    }
380
381    #[test]
382    fn map_default() {
383        let map: AxHashMap<u64, u64> = AxHashMap::default();
384        assert!(map.is_empty());
385    }
386
387    #[test]
388    fn map_from_iterator() {
389        let pairs = vec![("a", 1u32), ("b", 2), ("c", 3)];
390        let map: AxHashMap<&str, u32> = pairs.into_iter().collect();
391        assert_eq!(map.len(), 3);
392        assert_eq!(map["b"], 2);
393    }
394
395    #[test]
396    fn map_extend() {
397        let mut map: AxHashMap<u32, u32> = AxHashMap::new();
398        map.extend([(1, 10), (2, 20)]);
399        map.extend([(3, 30)]);
400        assert_eq!(map.len(), 3);
401        assert_eq!(map[&2], 20);
402    }
403
404    #[test]
405    fn map_iter() {
406        let map: AxHashMap<u32, u32> = [(1, 10), (2, 20)].into_iter().collect();
407        let mut sum = 0u32;
408        for (_, v) in &map {
409            sum += v;
410        }
411        assert_eq!(sum, 30);
412    }
413
414    #[test]
415    fn map_into_inner_roundtrip() {
416        let mut map: AxHashMap<&str, i32> = AxHashMap::new();
417        map.insert("x", 99);
418        let raw: RawHashMap<&str, i32, AxBuildHasher> = map.into_inner();
419        assert_eq!(raw["x"], 99);
420        let wrapped: AxHashMap<&str, i32> = raw.into();
421        assert_eq!(wrapped["x"], 99);
422    }
423
424    #[test]
425    fn map_seeded_hasher() {
426        let hasher = AxBuildHasher::with_seed(0x1234_5678_9abc_def0);
427        let mut map: AxHashMap<&str, u32> = AxHashMap::with_hasher(hasher);
428        map.insert("seeded", 7);
429        assert_eq!(map["seeded"], 7);
430    }
431
432    #[test]
433    fn set_basic_operations() {
434        let mut set: AxHashSet<u32> = AxHashSet::new();
435        assert!(set.is_empty());
436
437        set.insert(1);
438        set.insert(2);
439        set.insert(2); // duplicate
440        set.insert(3);
441
442        assert_eq!(set.len(), 3);
443        assert!(set.contains(&1));
444        assert!(!set.contains(&99));
445
446        set.remove(&2);
447        assert_eq!(set.len(), 2);
448    }
449
450    #[test]
451    fn set_with_capacity() {
452        let set: AxHashSet<u64> = AxHashSet::with_capacity(64);
453        assert!(set.capacity() >= 64);
454    }
455
456    #[test]
457    fn set_default() {
458        let set: AxHashSet<u64> = AxHashSet::default();
459        assert!(set.is_empty());
460    }
461
462    #[test]
463    fn set_from_iterator() {
464        let set: AxHashSet<u32> = [1u32, 2, 3, 2, 1].into_iter().collect();
465        assert_eq!(set.len(), 3);
466    }
467
468    #[test]
469    fn set_extend() {
470        let mut set: AxHashSet<u32> = AxHashSet::new();
471        set.extend([1u32, 2, 3]);
472        set.extend([3u32, 4, 5]);
473        assert_eq!(set.len(), 5);
474    }
475
476    #[test]
477    fn set_set_operations() {
478        let a: AxHashSet<u32> = [1, 2, 3].into_iter().collect();
479        let b: AxHashSet<u32> = [2, 3, 4].into_iter().collect();
480
481        // union, intersection, difference via deref
482        let union: AxHashSet<u32> = a.union(&b).copied().collect();
483        assert_eq!(union.len(), 4);
484
485        let inter: AxHashSet<u32> = a.intersection(&b).copied().collect();
486        assert_eq!(inter.len(), 2);
487    }
488
489    #[test]
490    fn set_into_inner_roundtrip() {
491        let mut set: AxHashSet<i32> = AxHashSet::new();
492        set.insert(42);
493        let raw: RawHashSet<i32, AxBuildHasher> = set.into_inner();
494        assert!(raw.contains(&42));
495        let wrapped: AxHashSet<i32> = raw.into();
496        assert!(wrapped.contains(&42));
497    }
498}