use super::*;
use fnv::FnvHasher;
struct CustomHasher {
key: u64,
hasher: FnvHasher
}
impl Clone for CustomHasher {
fn clone(&self) -> CustomHasher {
CustomHasher {
key: self.key,
hasher: FnvHasher::with_key(self.key)
}
}
}
impl core::hash::Hasher for CustomHasher {
fn write(&mut self, input: &[u8]) {
self.hasher.write(input);
}
fn finish(&self) -> u64 {
self.hasher.finish()
}
}
#[test]
fn make_array_hash() {
let mut ah = ArrayHashBuilder::default().build();
const MAX :usize = 1_000_000;
for i in 0..MAX { ah.put(i, i);
}
let mut counter = 0;
for _ in ah { counter += 1;
}
assert_eq!(counter, MAX);
}
#[test]
fn put_get_xx() {
let mut ah = ArrayHashBuilder::default().max_load_factor(10_000).build();
const MAX :usize = 1_000_000;
for i in 0..MAX { ah.put(i, i);
}
let begin = std::time::Instant::now();
for j in 0..MAX {
if let Some(v) = ah.get(&j) {
assert_eq!(*v, j);
} else {
panic!("Cannot retrieve value back using existing key")
}
}
dbg!(begin.elapsed().as_millis());
}
#[test]
fn put_smart_get_xx() {
let mut ah = ArrayHashBuilder::default().max_load_factor(10_000).build();
const MAX :usize = 1_000_000;
for i in 0..MAX { ah.put(Box::new(i), i); }
let begin = std::time::Instant::now();
for j in 0..MAX {
if let Some(v) = ah.smart_get(&j) { assert_eq!(*v, j);
} else {
panic!("Cannot retrieve value back using existing key")
}
}
dbg!(begin.elapsed().as_millis());
}
#[test]
fn put_contractual_get_xx() {
let mut ah = ArrayHashBuilder::default().build();
#[derive(Hash, PartialEq)]
struct A(usize);
#[derive(Hash)]
struct B(usize);
impl PartialEq<A> for B {
fn eq(&self, rhs: &A) -> bool {
self.0 == rhs.0
}
}
const MAX :usize = 1_000_000;
for i in 0..MAX { ah.put(A(i), i); }
assert!(ah.get(&A(MAX + 1)).is_none());
let begin = std::time::Instant::now();
for j in 0..MAX {
if let Some(v) = ah.get(&B(j)) { assert_eq!(*v, j);
} else {
panic!("Cannot retrieve value back using existing key")
}
}
dbg!(begin.elapsed().as_millis());
}
#[test]
fn try_put() {
let mut ah = ArrayHashBuilder::default().build();
assert_eq!(ah.try_put(1u8, 1u8).unwrap(), &1u8);
assert_eq!(ah.try_put(1u8, 1u8).unwrap_err(), (1u8, 1u8, &1u8));
assert_eq!(ah.try_put(0u8, 1u8).unwrap(), &1u8);
assert_eq!(ah.try_put(0u8, 1u8).unwrap_err(), (0u8, 1u8, &1u8));
}
#[test]
fn put_coalesced_get_xx() {
let mut ah = ArrayHashBuilder::default().max_load_factor(10_000).build();
const MAX :usize = 1_000_000;
for i in 0..MAX { ah.put(vec![i], i); }
assert!(ah.coerce_get::<[usize]>(&[MAX + 1]).is_none());
let begin = std::time::Instant::now();
for j in 0..MAX {
if let Some(v) = ah.coerce_get::<[usize]>(&[j]) { assert_eq!(*v, j);
} else {
panic!("Cannot retrieve value back using existing key")
}
}
dbg!(begin.elapsed().as_millis());
}
#[test]
fn contains_all() {
let mut ah = ArrayHashBuilder::default().max_load_factor(10_000).build();
let mut another = ah.clone();
let mut partly_eq = ah.clone();
const MAX :usize = 1_000_000;
for i in 0..MAX { ah.put(vec![i], i); }
for i in 0..(MAX / 2) {
another.put(vec![i], i);
partly_eq.put(vec![i], 0);
}
let begin = std::time::Instant::now();
assert!(ah.contains_iter(&another));
assert!(!ah.contains_iter(&partly_eq));
dbg!(begin.elapsed().as_millis());
}
#[test]
fn partial_eq() {
let mut ah = ArrayHashBuilder::default().max_load_factor(8).buckets_size(8).build();
let mut ah_2 = ArrayHashBuilder::default().max_load_factor(8).buckets_size(8).build();
const MAX :usize = 16;
for i in 0..MAX { ah.put(vec![i], i);
ah_2.put(vec![i], i); }
assert_ne!(ah, ah_2);
let ah_3 = ah.clone();
assert_eq!(ah, ah_3);
let mut ah_4 = ah.to_builder().build();
let mut ah_5 = ah.to_builder().build();
for i in 0..MAX {
ah_4.put(vec![i], i); ah_5.put(vec![i], 0); }
assert_eq!(ah, ah_4);
assert_ne!(ah, ah_5);
}
#[test]
fn hasher_eq() {
let ah = ArrayHashBuilder::default().max_load_factor(8).buckets_size(8).build::<u8, u8>();
let ah_2 = ArrayHashBuilder::default().max_load_factor(8).buckets_size(8).build::<u8, u8>();
assert!(!ah.is_hasher_eq(&ah_2));
let ah_3 = ah.clone();
assert!(ah.is_hasher_eq(&ah_3));
let ah_4 = ah.to_builder().build::<u8, u8>();
let ah_5 = ah.to_builder().build::<u8, u8>();
assert!(ah.is_hasher_eq(&ah_4));
assert!(ah_5.is_hasher_eq(&ah_4));
}
#[test]
fn make_custom_hasher() {
let seed = 0u64;
let hasher = CustomHasher {
key: seed,
hasher: FnvHasher::with_key(seed)
};
let mut ah = ArrayHashBuilder::with_hasher(hasher).build();
const MAX :usize = 1_000_000;
for i in 0..MAX { ah.put(i, i);
}
let mut counter = 0;
for _ in ah { counter += 1;
}
assert_eq!(counter, MAX);
}
#[test]
fn put_get_fnv() {
let seed = 0u64;
let hasher = CustomHasher {
key: seed,
hasher: FnvHasher::with_key(seed)
};
let mut ah = ArrayHashBuilder::with_hasher(hasher).build();
const MAX :usize = 1_000_000;
for i in 0..MAX { ah.put(i, i);
}
for j in 0..MAX {
if let Some(v) = ah.get(&j) {
assert_eq!(*v, j);
} else {
panic!("Cannot retrieve value back using existing key")
}
}
}
#[test]
fn test_iter() {
let mut ah = ArrayHashBuilder::default().build();
const MAX :usize = 100_000;
for i in 0..MAX { ah.put(i, i);
}
let mut ah_vec = ah.iter().map(|(k, _)| *k).collect::<Vec<usize>>();
ah_vec.sort();
for i in 0..ah_vec.len() {
assert_eq!(i, ah_vec[i]);
}
}
#[test]
fn test_iter_mut() {
let mut ah = ArrayHashBuilder::default().build();
const MAX :usize = 100_000;
for i in 0..MAX { ah.put(i, i);
}
ah.iter_mut().enumerate().for_each(|(i, entry)| {entry.1 = i;});
for (i, (_, v)) in ah.iter().enumerate() {
assert_eq!(i, *v);
}
let mut sorted: Vec<usize> = ah.into_iter().map(|(k, _)| k).collect();
sorted.sort();
for (i, k) in sorted.into_iter().enumerate() {
assert_eq!(i, k);
}
}
#[test]
fn test_drain() {
let mut ah = ArrayHashBuilder::default().build();
const MAX :usize = 100_000;
for i in 0..MAX { ah.put(i, i);
}
let mut keys : Vec<usize> = ah.drain().map(|(k, _)| k).collect();
keys.sort_unstable();
keys.into_iter().enumerate().for_each(|(i, k)| assert_eq!(i, k));
assert_eq!(ah.len(), 0);
}
#[test]
fn test_drain_with() {
let mut ah = ArrayHashBuilder::default().build();
const MAX :usize = 100_000;
for i in 0..MAX { ah.put(i, i);
}
let mut keys : Vec<usize> = ah.drain_with(|(_, v)| {
*v >= MAX / 2
}).map(|(k, _)| k).collect();
keys.sort_unstable();
keys.into_iter().enumerate().for_each(|(i, k)| assert_eq!(i + MAX / 2, k));
assert_eq!(ah.len(), MAX / 2);
}
#[test]
fn test_split_with() {
let mut ah = ArrayHashBuilder::default().build();
const MAX :usize = 100_000;
for i in 0..MAX { ah.put(i, i);
}
let ah2 = ah.split_by(|(k, _)| {
*k >= MAX / 2
});
assert_eq!(ah.len(), 50_000);
assert_eq!(ah2.len(), 50_000);
for i in 0..(MAX / 2) {
if let Some(v) = ah.get(&i) {
assert_eq!(*v, i);
} else {
panic!("Value missing for {}", i)
}
}
for i in (MAX / 2)..MAX {
if let Some(v) = ah2.get(&i) {
assert_eq!(*v, i);
} else {
panic!("Value missing for {}", i)
}
}
}
#[test]
#[ignore]
fn bench_compound_key() {
let start = std::time::Instant::now();
let mut ah = ArrayHashBuilder::default().buckets_size(4096).build();
for i in 0..100_000 {
let v: Vec<usize> = (i..(i + 100)).collect();
ah.put(v.clone(), v);
}
let created = start.elapsed().as_millis();
println!("Created in {}s {}ms", created / 1000, created % 1000);
for i in 0..100_000 {
let v: Vec<usize> = (i..(i + 100)).collect();
if let Some(value) = ah.get(&v) {
assert_eq!(*value, v);
}
}
let created = start.elapsed().as_millis();
println!("Got in {}s {}ms", created / 1000, created);
}