1#![allow(dead_code)]
11#[cfg(test)]
12extern crate quickcheck;
13#[cfg(test)]
14#[macro_use(quickcheck)]
15extern crate quickcheck_macros;
16
17mod bitmap;
18mod collision;
19mod hamt;
20mod hash;
21mod immutable;
22mod mutable;
23mod node;
24
25pub use hamt::*;
26
27#[cfg(test)]
28mod tests {
29 use super::*;
30
31 use quickcheck::{Arbitrary, Gen};
32
33 use std::cmp;
34 use std::collections::hash_map::DefaultHasher;
35 use std::collections::BTreeMap;
36 use std::hash::Hash;
37
38 #[derive(Debug, Clone)]
39 enum PlanOperation<K, V> {
40 Insert(K, V),
41 DeleteOneMatching(usize),
42 DeleteOne(usize),
43 Update(usize),
44 UpdateRemoval(usize),
45 Replace(usize, V),
46 ReplaceWith(usize),
47 }
48
49 #[derive(Debug, Clone)]
50 struct Plan<K, V>(Vec<PlanOperation<K, V>>);
51
52 const SIZE_LIMIT: usize = 5120;
53
54 impl<K: Arbitrary + Clone + Send, V: Arbitrary + Clone + Send> Arbitrary for Plan<K, V> {
55 fn arbitrary<G: Gen>(g: &mut G) -> Plan<K, V> {
56 let nb_ops = 1000 + cmp::min(SIZE_LIMIT, Arbitrary::arbitrary(g));
57 let mut v = Vec::new();
58 for _ in 0..nb_ops {
59 let op_nb: u32 = Arbitrary::arbitrary(g);
60 let op = match op_nb % 7u32 {
61 0 => PlanOperation::Insert(Arbitrary::arbitrary(g), Arbitrary::arbitrary(g)),
62 1 => PlanOperation::DeleteOne(Arbitrary::arbitrary(g)),
63 2 => PlanOperation::DeleteOneMatching(Arbitrary::arbitrary(g)),
64 3 => PlanOperation::Update(Arbitrary::arbitrary(g)),
65 4 => PlanOperation::UpdateRemoval(Arbitrary::arbitrary(g)),
66 5 => PlanOperation::Replace(Arbitrary::arbitrary(g), Arbitrary::arbitrary(g)),
67 6 => PlanOperation::ReplaceWith(Arbitrary::arbitrary(g)),
68 _ => panic!("test internal error: quickcheck tag code is invalid"),
69 };
70 v.push(op)
71 }
72 Plan(v)
73 }
74 }
75
76 #[test]
77 fn insert_lookup() {
78 let h: Hamt<String, u32, DefaultHasher> = Hamt::new();
79
80 let k1 = "ABC".to_string();
81 let v1 = 12u32;
82
83 let k2 = "DEF".to_string();
84 let v2 = 24u32;
85
86 let k3 = "XYZ".to_string();
87 let v3 = 42u32;
88
89 let h1 = h.mutate_freeze(|hm| hm.insert(k1.clone(), v1)).unwrap();
90 let h2 = h.mutate_freeze(|hm| hm.insert(k2.clone(), v2)).unwrap();
91
92 assert_eq!(h1.lookup(&k1), Some(&v1));
93 assert_eq!(h2.lookup(&k2), Some(&v2));
94 assert_eq!(h1.lookup(&k2), None);
95 assert_eq!(h2.lookup(&k1), None);
96
97 let h3 = h1.mutate_freeze(|hm| hm.insert(k3.clone(), v3)).unwrap();
98
99 assert_eq!(h1.lookup(&k3), None);
100 assert_eq!(h2.lookup(&k3), None);
101
102 assert_eq!(h3.lookup(&k1), Some(&v1));
103 assert_eq!(h3.lookup(&k2), None);
104 assert_eq!(h3.lookup(&k3), Some(&v3));
105
106 let (h4, oldk1) = h3.mutate_freeze_ret(|hm| hm.replace(&k1, v3)).unwrap();
107 assert_eq!(oldk1, v1);
108 assert_eq!(h4.lookup(&k1), Some(&v3));
109 }
110
111 #[test]
112 fn dup_insert() {
113 let mut h: Hamt<&String, u32, DefaultHasher> = Hamt::new();
114 let dkey = "A".to_string();
115 h = h.mutate_freeze(|hm| hm.insert(&dkey, 1)).unwrap();
116 assert_eq!(
117 h.mutate_freeze(|hm| hm.insert(&dkey, 2)).and(Ok(())),
118 Err(InsertError::EntryExists)
119 )
120 }
121
122 #[test]
123 fn empty_size() {
124 let h: Hamt<&String, u32, DefaultHasher> = Hamt::new();
125 assert_eq!(h.size(), 0)
126 }
127
128 #[test]
129 fn delete_key_not_exist() {
130 let mut h: Hamt<&String, u32, DefaultHasher> = Hamt::new();
131 let dkey = "A".to_string();
132 h = h.mutate_freeze(|hm| hm.insert(&dkey, 1)).unwrap();
133 assert_eq!(
134 h.mutate_freeze(|hm| hm.remove_match(&&dkey, &2))
135 .and(Ok(())),
136 Err(RemoveError::ValueNotMatching)
137 )
138 }
139
140 #[test]
141 fn delete_value_not_match() {
142 let mut h: Hamt<&String, u32, DefaultHasher> = Hamt::new();
143 let dkey = "A".to_string();
144 h = h.mutate_freeze(|hm| hm.insert(&dkey, 1)).unwrap();
145 assert_eq!(
146 h.mutate_freeze(|hm| hm.remove_match(&&dkey, &2))
147 .and(Ok(())),
148 Err(RemoveError::ValueNotMatching)
149 )
150 }
151
152 #[allow(clippy::trivially_copy_pass_by_ref)]
153 fn next_u32(x: &u32) -> Result<Option<u32>, ()> {
154 Ok(Some(*x + 1))
155 }
156
157 #[test]
158 fn delete() {
159 let mut h: Hamt<String, u32, DefaultHasher> = Hamt::new();
160
161 let keys = [
162 ("KEY1", 10000u32),
163 ("KEY2", 20000),
164 ("KEY3", 30000),
165 ("KEY4", 40000),
166 ("KEY5", 50000),
167 ("KEY6", 60000),
168 ("KEY7", 70000),
169 ("KEY8", 80000),
170 ("KEY9", 10000),
171 ("KEY10", 20000),
172 ("KEY11", 30000),
173 ("KEY12", 40000),
174 ("KEY13", 50000),
175 ("KEY14", 60000),
176 ("KEY15", 70000),
177 ("KEY16", 80000),
178 ];
179
180 let k1 = "ABC".to_string();
181 let v1 = 12u32;
182
183 let k2 = "DEF".to_string();
184 let v2 = 24u32;
185
186 let k3 = "XYZ".to_string();
187 let v3 = 42u32;
188
189 h = h
190 .mutate_freeze::<InsertError, _>(|hm| {
191 for (k, v) in keys.iter() {
192 hm.insert((*k).to_owned(), *v)?;
193 }
194 Ok(())
195 })
196 .unwrap();
197
198 h = h
199 .mutate_freeze(|hm| {
200 hm.insert(k1.clone(), v1)?;
201 hm.insert(k2.clone(), v2)?;
202 hm.insert(k3.clone(), v3)
203 })
204 .unwrap();
205
206 let h2 = h
207 .mutate_freeze(|hm| hm.remove_match(&k1, &v1))
208 .expect("cannot remove from already inserted");
209
210 assert_eq!(h.size(), keys.len() + 3);
211 assert_eq!(h2.size(), keys.len() + 2);
212
213 assert_eq!(h.lookup(&k1), Some(&v1));
214 assert_eq!(h2.lookup(&k1), None);
215
216 h = h
217 .mutate_freeze(|hm| {
218 hm.remove_match(&k2, &v2)?;
219 hm.remove_match(&k3, &v3)
220 })
221 .unwrap();
222
223 assert_eq!(
224 h.mutate_freeze(|hm| hm.remove_match(&k3, &v3)).and(Ok(())),
225 Err(RemoveError::KeyNotFound),
226 );
227 assert_eq!(
228 h.mutate_freeze(|hm| hm.remove_match(&k1, &v2)).and(Ok(())),
229 Err(RemoveError::ValueNotMatching),
230 );
231 assert_eq!(
232 h2.mutate_freeze(|hm| hm.insert(k2, v3)).and(Ok(())),
233 Err(InsertError::EntryExists)
234 );
235
236 assert_eq!(
237 h2.mutate_freeze(|hm| hm.update(&"ZZZ".to_string(), next_u32))
238 .and(Ok(())),
239 Err(UpdateError::KeyNotFound)
240 );
241
242 assert_eq!(h.size(), keys.len() + 1);
243 assert_eq!(h2.size(), keys.len() + 2);
244 }
245
246 fn property_btreemap_eq<A: Eq + Ord + Hash, B: PartialEq>(
293 reference: &BTreeMap<A, B>,
294 h: &Hamt<A, B, DefaultHasher>,
295 ) -> bool {
296 for (k, v) in reference.iter() {
298 if h.lookup(&k) != Some(v) {
299 return false;
300 }
301 }
302 for (k, v) in h.iter() {
304 if reference.get(&k) != Some(v) {
305 return false;
306 }
307 }
308 true
309 }
310
311 #[quickcheck]
312 fn insert_equivalent(xs: Vec<(String, u32)>) -> bool {
313 let mut reference = BTreeMap::new();
314 let mut h: HamtMut<String, u32, DefaultHasher> = HamtMut::new();
315 for (k, v) in xs.iter() {
316 if reference.get(k).is_some() {
317 continue;
318 }
319 reference.insert(k.clone(), *v);
320 h.insert(k.clone(), *v).expect("insert error");
321 }
322 property_btreemap_eq(&reference, &h.freeze())
323 }
324
325 #[derive(Clone, Debug, PartialEq, Eq)]
326 pub struct LargeVec<A>(Vec<A>);
327
328 const LARGE_MIN: usize = 1000;
329 const LARGE_DIFF: usize = 1000;
330
331 impl<A: Arbitrary + Clone + PartialEq + Send + 'static> Arbitrary for LargeVec<A> {
332 fn arbitrary<G: Gen>(g: &mut G) -> Self {
333 let nb = LARGE_MIN + (usize::arbitrary(g) % LARGE_DIFF);
334 let mut v = Vec::with_capacity(nb);
335 for _ in 0..nb {
336 v.push(Arbitrary::arbitrary(g))
337 }
338 LargeVec(v)
339 }
340 }
341
342 #[quickcheck]
343 fn large_insert_equivalent(xs: LargeVec<(String, u32)>) -> bool {
344 let xs = xs.0;
345 let mut reference = BTreeMap::new();
346 let mut h: HamtMut<String, u32, DefaultHasher> = HamtMut::new();
347 for (k, v) in xs.iter() {
348 if reference.get(k).is_some() {
349 continue;
350 }
351 reference.insert(k.clone(), *v);
352 h.insert(k.clone(), *v).expect("insert error");
353 }
354
355 property_btreemap_eq(&reference, &h.freeze())
356 }
357
358 fn get_key_nth<K: Clone, V>(b: &BTreeMap<K, V>, n: usize) -> Option<K> {
359 let keys_nb = b.len();
360 if keys_nb == 0 {
361 return None;
362 }
363 let mut keys = b.keys();
364 Some(keys.nth(n % keys_nb).unwrap().clone())
365 }
366
367 fn arbitrary_hamt_and_btree<K, V, F, G>(
368 xs: Plan<K, V>,
369 update_f: F,
370 replace_with_f: G,
371 ) -> (Hamt<K, V, DefaultHasher>, BTreeMap<K, V>)
372 where
373 K: Hash + Clone + Eq + Ord + Sync,
374 V: Clone + PartialEq + Sync,
375 F: Fn(&V) -> Result<Option<V>, ()> + Copy,
376 G: Fn(&V) -> V + Copy,
377 {
378 let mut reference = BTreeMap::new();
379 let mut h: HamtMut<K, V, DefaultHasher> = HamtMut::new();
380 for op in xs.0.iter() {
382 match op {
383 PlanOperation::Insert(k, v) => {
384 if reference.get(k).is_some() {
385 continue;
386 }
387 reference.insert(k.clone(), v.clone());
388 h.insert(k.clone(), v.clone()).expect("insert error")
389 }
390 PlanOperation::DeleteOne(r) => match get_key_nth(&reference, *r) {
391 None => continue,
392 Some(k) => {
393 reference.remove(&k);
394 h.remove(&k).expect("remove error");
395 }
396 },
397 PlanOperation::DeleteOneMatching(r) => match get_key_nth(&reference, *r) {
398 None => continue,
399 Some(k) => {
400 let v = reference.get(&k).unwrap().clone();
401 reference.remove(&k);
402 h.remove_match(&k, &v).expect("remove match error");
403 }
404 },
405 PlanOperation::Replace(r, newv) => match get_key_nth(&reference, *r) {
406 None => continue,
407 Some(k) => {
408 let v = reference.get_mut(&k).unwrap();
409 *v = newv.clone();
410
411 h.replace(&k, newv.clone()).expect("replace error");
412 }
413 },
414 PlanOperation::ReplaceWith(r) => match get_key_nth(&reference, *r) {
415 None => continue,
416 Some(k) => {
417 let v = reference.get_mut(&k).unwrap();
418 *v = replace_with_f(v);
419
420 h.replace_with(&k, replace_with_f)
421 .expect("replace with error");
422 }
423 },
424 PlanOperation::Update(r) => match get_key_nth(&reference, *r) {
425 None => continue,
426 Some(k) => {
427 let v = reference.get_mut(&k).unwrap();
428 match update_f(v).unwrap() {
429 None => {
430 reference.remove(&k);
431 }
432 Some(newv) => *v = newv,
433 }
434
435 h.update(&k, update_f).expect("update error");
436 }
437 },
438 PlanOperation::UpdateRemoval(r) => match get_key_nth(&reference, *r) {
439 None => continue,
440 Some(k) => {
441 reference.remove(&k);
442 h.update::<_, ()>(&k, |_| Ok(None))
443 .expect("update removal error");
444 }
445 },
446 }
447 }
448 (h.freeze(), reference)
449 }
450
451 #[quickcheck]
452 fn plan_equivalent(xs: Plan<String, u32>) -> bool {
453 let (h, reference) = arbitrary_hamt_and_btree(xs, next_u32, |v| v.wrapping_mul(2));
454 property_btreemap_eq(&reference, &h)
455 }
456
457 #[quickcheck]
458 fn iter_equivalent(xs: Plan<String, u32>) -> bool {
459 use std::iter::FromIterator;
460 let (h, reference) = arbitrary_hamt_and_btree(xs, next_u32, |v| v.wrapping_mul(2));
461 let after_iter = BTreeMap::from_iter(h.iter().map(|(k, v)| (k.clone(), *v)));
462 reference == after_iter
463 }
464}