Skip to main content

axhash_map/
lib.rs

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