nekolib/ds/
cuckoo_hash_map.rs1use std::collections::hash_map::RandomState;
4use std::fmt::Debug;
5use std::hash::{BuildHasher, Hash, Hasher};
6use std::iter::FromIterator;
7
8#[derive(Clone, Debug)]
16pub struct CuckooHashMap<K, V> {
17 rs: [RandomState; 2],
18 buf: [Vec<Vec<(K, V)>>; 2],
19 len: usize,
20}
21
22const LOOP_THRESHOLD: usize = 8;
23const LEN_THRESHOLD: usize = 32;
24
25impl<K: Eq + Hash, V> CuckooHashMap<K, V> {
26 pub fn new() -> Self {
27 let r0 = RandomState::new();
28 let r1 = RandomState::new();
29 Self {
30 rs: [r0, r1],
31 buf: [vec![vec![]], vec![vec![]]],
32 len: 0,
33 }
34 }
35
36 pub fn contains_key(&self, key: &K) -> bool { self.find(key).is_some() }
37
38 pub fn insert(&mut self, key: K, val: V) -> Option<V> {
39 if let Some((i, j, k)) = self.find(&key) {
40 let old = std::mem::replace(&mut self.buf[i][j][k].1, val);
41 return Some(old);
42 }
43
44 if let Some(elts) = self.try_insert((key, val), LOOP_THRESHOLD) {
45 self.rehash(elts);
46 }
47 self.len += 1;
48 None
49 }
50
51 pub fn remove(&mut self, key: &K) -> Option<V> {
52 self.find(key).map(|(i, j, k)| {
53 self.len -= 1;
54 self.buf[i][j].swap_remove(k).1
55 })
56 }
57
58 pub fn len(&self) -> usize { self.len }
59 pub fn is_empty(&self) -> bool { self.len == 0 }
60
61 fn try_insert(
62 &mut self,
63 mut keyval: (K, V),
64 thresh: usize,
65 ) -> Option<Vec<(K, V)>> {
66 for _ in 0..thresh {
67 for i in 0..=1 {
68 let j = self.get_hash(&keyval.0, i);
69 if self.buf[i][j].len() < LEN_THRESHOLD {
70 self.buf[i][j].push(keyval);
71 return None;
72 }
73 std::mem::swap(&mut keyval, self.buf[i][j].last_mut().unwrap());
74 }
75 }
76
77 let mut elts = vec![keyval];
78 elts.extend(self.buf[0].drain(..).flatten());
79 elts.extend(self.buf[1].drain(..).flatten());
80 Some(elts)
81 }
82
83 fn rehash(&mut self, mut elts: Vec<(K, V)>) {
84 let len = Self::calc_len(elts.len());
85
86 'outer: loop {
87 for i in 0..=1 {
88 self.buf[i] = (0..len).map(|_| vec![]).collect();
89 self.rs[i] = RandomState::new();
90 }
91 while let Some((k, v)) = elts.pop() {
92 if let Some(tmp) = self.try_insert((k, v), LOOP_THRESHOLD) {
93 elts.extend(tmp);
94 continue 'outer;
95 }
96 }
97 return;
98 }
99 }
100
101 fn calc_len(n: usize) -> usize { n }
102
103 fn find(&self, key: &K) -> Option<(usize, usize, usize)> {
104 (0..=1).find_map(|i| {
105 let j = self.get_hash(key, i);
106 self.buf[i][j]
107 .iter()
108 .enumerate()
109 .find(|(_, (key0, _))| key0 == key)
110 .map(|(k, _)| (i, j, k))
111 })
112 }
113
114 fn get_hash(&self, key: &K, i: usize) -> usize {
115 let mut h = self.rs[i].build_hasher();
116 key.hash(&mut h);
117 h.finish() as usize % self.buf[i].len()
118 }
119}
120
121impl<K: Eq + Hash, V> FromIterator<(K, V)> for CuckooHashMap<K, V> {
122 fn from_iter<I>(iter: I) -> Self
123 where
124 I: IntoIterator<Item = (K, V)>,
125 {
126 let mut res = CuckooHashMap::new();
127 for (k, v) in iter {
128 res.insert(k, v);
129 }
130 res
131 }
132}
133
134impl<K: Eq + Hash, V> Extend<(K, V)> for CuckooHashMap<K, V> {
135 fn extend<I>(&mut self, iter: I)
136 where
137 I: IntoIterator<Item = (K, V)>,
138 {
139 for (k, v) in iter {
140 self.insert(k, v);
141 }
142 }
143}