526 lines
12 KiB
Rust
526 lines
12 KiB
Rust
use flurry::*;
|
|
use std::sync::Arc;
|
|
|
|
#[test]
|
|
fn pin() {
|
|
let map = HashMap::<usize, usize>::new();
|
|
let _pinned = map.pin();
|
|
}
|
|
|
|
#[test]
|
|
fn with_guard() {
|
|
let map = HashMap::<usize, usize>::new();
|
|
let guard = map.guard();
|
|
let _pinned = map.with_guard(&guard);
|
|
}
|
|
|
|
#[test]
|
|
fn clear() {
|
|
let map = HashMap::<usize, usize>::new();
|
|
let map = map.pin();
|
|
{
|
|
map.insert(0, 1);
|
|
map.insert(1, 1);
|
|
map.insert(2, 1);
|
|
map.insert(3, 1);
|
|
map.insert(4, 1);
|
|
}
|
|
map.clear();
|
|
assert!(map.is_empty());
|
|
}
|
|
|
|
#[test]
|
|
fn insert() {
|
|
let map = HashMap::<usize, usize>::new();
|
|
let map = map.pin();
|
|
let old = map.insert(42, 0);
|
|
assert!(old.is_none());
|
|
}
|
|
|
|
#[test]
|
|
fn get_empty() {
|
|
let map = HashMap::<usize, usize>::new();
|
|
let map = map.pin();
|
|
let e = map.get(&42);
|
|
assert!(e.is_none());
|
|
}
|
|
|
|
#[test]
|
|
fn get_key_value_empty() {
|
|
let map = HashMap::<usize, usize>::new();
|
|
let map = map.pin();
|
|
let e = map.get_key_value(&42);
|
|
assert!(e.is_none());
|
|
}
|
|
|
|
#[test]
|
|
fn remove_empty() {
|
|
let map = HashMap::<usize, usize>::new();
|
|
let map = map.pin();
|
|
let old = map.remove(&42);
|
|
assert!(old.is_none());
|
|
}
|
|
|
|
#[test]
|
|
fn insert_and_remove() {
|
|
let map = HashMap::<usize, usize>::new();
|
|
let map = map.pin();
|
|
map.insert(42, 0);
|
|
let old = map.remove(&42).unwrap();
|
|
assert_eq!(old, &0);
|
|
assert!(map.get(&42).is_none());
|
|
}
|
|
|
|
#[test]
|
|
fn insert_and_get() {
|
|
let map = HashMap::<usize, usize>::new();
|
|
map.pin().insert(42, 0);
|
|
{
|
|
let map = map.pin();
|
|
let e = map.get(&42).unwrap();
|
|
assert_eq!(e, &0);
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn insert_and_get_key_value() {
|
|
let map = HashMap::<usize, usize>::new();
|
|
|
|
map.pin().insert(42, 0);
|
|
{
|
|
let map = map.pin();
|
|
let e = map.get_key_value(&42).unwrap();
|
|
assert_eq!(e, (&42, &0));
|
|
}
|
|
}
|
|
|
|
mod hasher;
|
|
use hasher::ZeroHashBuilder;
|
|
|
|
#[test]
|
|
fn one_bucket() {
|
|
let map = HashMap::<&'static str, usize, _>::with_hasher(ZeroHashBuilder);
|
|
let map = map.pin();
|
|
|
|
// we want to check that all operations work regardless on whether
|
|
// we are operating on the head of a bucket, the tail of the bucket,
|
|
// or somewhere in the middle.
|
|
let v = map.insert("head", 0);
|
|
assert_eq!(v, None);
|
|
let v = map.insert("middle", 10);
|
|
assert_eq!(v, None);
|
|
let v = map.insert("tail", 100);
|
|
assert_eq!(v, None);
|
|
let e = map.get("head").unwrap();
|
|
assert_eq!(e, &0);
|
|
let e = map.get("middle").unwrap();
|
|
assert_eq!(e, &10);
|
|
let e = map.get("tail").unwrap();
|
|
assert_eq!(e, &100);
|
|
|
|
// check that replacing the keys returns the correct old value
|
|
let v = map.insert("head", 1);
|
|
assert_eq!(v, Some(&0));
|
|
let v = map.insert("middle", 11);
|
|
assert_eq!(v, Some(&10));
|
|
let v = map.insert("tail", 101);
|
|
assert_eq!(v, Some(&100));
|
|
// and updated the right value
|
|
let e = map.get("head").unwrap();
|
|
assert_eq!(e, &1);
|
|
let e = map.get("middle").unwrap();
|
|
assert_eq!(e, &11);
|
|
let e = map.get("tail").unwrap();
|
|
assert_eq!(e, &101);
|
|
// and that remove produces the right value
|
|
// note that we must remove them in a particular order
|
|
// so that we test all three node positions
|
|
let v = map.remove("middle");
|
|
assert_eq!(v, Some(&11));
|
|
let v = map.remove("tail");
|
|
assert_eq!(v, Some(&101));
|
|
let v = map.remove("head");
|
|
assert_eq!(v, Some(&1));
|
|
}
|
|
|
|
#[test]
|
|
fn update() {
|
|
let map = HashMap::<usize, usize>::new();
|
|
|
|
let map1 = map.pin();
|
|
map1.insert(42, 0);
|
|
let old = map1.insert(42, 1);
|
|
assert_eq!(old, Some(&0));
|
|
{
|
|
let map2 = map.pin();
|
|
let e = map2.get(&42).unwrap();
|
|
assert_eq!(e, &1);
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn compute_if_present() {
|
|
let map = HashMap::<usize, usize>::new();
|
|
|
|
let map1 = map.pin();
|
|
map1.insert(42, 0);
|
|
let new = map1.compute_if_present(&42, |_, v| Some(v + 1));
|
|
assert_eq!(new, Some(&1));
|
|
{
|
|
let map2 = map.pin();
|
|
let e = map2.get(&42).unwrap();
|
|
assert_eq!(e, &1);
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn compute_if_present_empty() {
|
|
let map = HashMap::<usize, usize>::new();
|
|
|
|
let map1 = map.pin();
|
|
let new = map1.compute_if_present(&42, |_, v| Some(v + 1));
|
|
assert!(new.is_none());
|
|
{
|
|
let map2 = map.pin();
|
|
assert!(map2.get(&42).is_none());
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn compute_if_present_remove() {
|
|
let map = HashMap::<usize, usize>::new();
|
|
|
|
let map1 = map.pin();
|
|
map1.insert(42, 0);
|
|
let new = map1.compute_if_present(&42, |_, _| None);
|
|
assert!(new.is_none());
|
|
{
|
|
let map2 = map.pin();
|
|
assert!(map2.get(&42).is_none());
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn empty_maps_equal() {
|
|
let map1 = HashMap::<usize, usize>::new();
|
|
let map2 = HashMap::<usize, usize>::new();
|
|
assert_eq!(map1, map2.pin());
|
|
assert_eq!(map1.pin(), map2);
|
|
assert_eq!(map1.pin(), map2.pin());
|
|
assert_eq!(map2.pin(), map1.pin());
|
|
}
|
|
|
|
#[test]
|
|
fn different_size_maps_not_equal() {
|
|
let map1 = HashMap::<usize, usize>::new();
|
|
let map2 = HashMap::<usize, usize>::new();
|
|
{
|
|
let map1 = map1.pin();
|
|
let map2 = map2.pin();
|
|
map1.insert(1, 0);
|
|
map1.insert(2, 0);
|
|
map2.insert(1, 0);
|
|
}
|
|
|
|
assert_ne!(map1, map2.pin());
|
|
assert_ne!(map1.pin(), map2);
|
|
assert_ne!(map1.pin(), map2.pin());
|
|
assert_ne!(map2.pin(), map1.pin());
|
|
}
|
|
|
|
#[test]
|
|
fn same_values_equal() {
|
|
let map1 = HashMap::<usize, usize>::new();
|
|
let map2 = HashMap::<usize, usize>::new();
|
|
{
|
|
let map1 = map1.pin();
|
|
let map2 = map2.pin();
|
|
map1.insert(1, 0);
|
|
map2.insert(1, 0);
|
|
}
|
|
|
|
assert_eq!(map1, map2.pin());
|
|
assert_eq!(map1.pin(), map2);
|
|
assert_eq!(map1.pin(), map2.pin());
|
|
assert_eq!(map2.pin(), map1.pin());
|
|
}
|
|
|
|
#[test]
|
|
fn different_values_not_equal() {
|
|
let map1 = HashMap::<usize, usize>::new();
|
|
let map2 = HashMap::<usize, usize>::new();
|
|
{
|
|
let map1 = map1.pin();
|
|
let map2 = map2.pin();
|
|
map1.insert(1, 0);
|
|
map2.insert(1, 1);
|
|
}
|
|
|
|
assert_ne!(map1, map2.pin());
|
|
assert_ne!(map1.pin(), map2);
|
|
assert_ne!(map1.pin(), map2.pin());
|
|
assert_ne!(map2.pin(), map1.pin());
|
|
}
|
|
|
|
#[test]
|
|
#[ignore]
|
|
// ignored because we cannot control when destructors run
|
|
fn drop_value() {
|
|
let dropped1 = Arc::new(0);
|
|
let dropped2 = Arc::new(1);
|
|
|
|
let map = HashMap::<usize, Arc<usize>>::new();
|
|
let map = map.pin();
|
|
|
|
map.insert(42, dropped1.clone());
|
|
assert_eq!(Arc::strong_count(&dropped1), 2);
|
|
assert_eq!(Arc::strong_count(&dropped2), 1);
|
|
|
|
map.insert(42, dropped2.clone());
|
|
assert_eq!(Arc::strong_count(&dropped2), 2);
|
|
|
|
drop(map);
|
|
|
|
// First NotifyOnDrop was dropped when it was replaced by the second
|
|
assert_eq!(Arc::strong_count(&dropped1), 1);
|
|
// Second NotifyOnDrop was dropped when the map was dropped
|
|
assert_eq!(Arc::strong_count(&dropped2), 1);
|
|
}
|
|
|
|
#[test]
|
|
fn clone_map_empty() {
|
|
let map = HashMap::<&'static str, u32>::new();
|
|
let map = map.pin();
|
|
let cloned_map = map.clone();
|
|
assert_eq!(map.len(), cloned_map.len());
|
|
assert_eq!(&map, &cloned_map);
|
|
assert_eq!(cloned_map.len(), 0);
|
|
}
|
|
|
|
#[test]
|
|
// Test that same values exists in both maps (original and cloned)
|
|
fn clone_map_filled() {
|
|
let map_ref = HashMap::<&'static str, u32>::new();
|
|
let map_ref = map_ref.pin();
|
|
map_ref.insert("FooKey", 0);
|
|
map_ref.insert("BarKey", 10);
|
|
let cloned_map_ref = map_ref.clone();
|
|
assert_eq!(map_ref.len(), cloned_map_ref.len());
|
|
assert_eq!(&map_ref, &cloned_map_ref);
|
|
|
|
// test that both maps are equal,
|
|
// because the ref and the cloned ref, point to the same map
|
|
map_ref.insert("NewItem", 100);
|
|
assert_eq!(&map_ref, &cloned_map_ref);
|
|
}
|
|
|
|
#[test]
|
|
fn default() {
|
|
let map: HashMap<usize, usize> = Default::default();
|
|
let map = map.pin();
|
|
map.insert(42, 0);
|
|
assert_eq!(map.get(&42), Some(&0));
|
|
}
|
|
|
|
#[test]
|
|
fn debug() {
|
|
let map: HashMap<usize, usize> = HashMap::new();
|
|
let map = map.pin();
|
|
map.insert(42, 0);
|
|
map.insert(16, 8);
|
|
|
|
let formatted = format!("{:?}", map);
|
|
|
|
assert!(formatted == "{42: 0, 16: 8}" || formatted == "{16: 8, 42: 0}");
|
|
}
|
|
|
|
#[test]
|
|
fn from_iter_ref() {
|
|
use std::iter::FromIterator;
|
|
|
|
let mut entries: Vec<(&usize, &usize)> = vec![(&42, &0), (&16, &6), (&38, &42)];
|
|
entries.sort();
|
|
|
|
let map: HashMap<usize, usize> = HashMap::from_iter(entries.clone().into_iter());
|
|
let map = map.pin();
|
|
let mut collected: Vec<(&usize, &usize)> = map.iter().collect();
|
|
collected.sort();
|
|
|
|
assert_eq!(entries, entries)
|
|
}
|
|
|
|
#[test]
|
|
fn from_iter_empty() {
|
|
use std::iter::FromIterator;
|
|
|
|
let entries: Vec<(usize, usize)> = Vec::new();
|
|
let map: HashMap<usize, usize> = HashMap::from_iter(entries.into_iter());
|
|
let map = map.pin();
|
|
assert_eq!(map.len(), 0)
|
|
}
|
|
|
|
#[test]
|
|
fn retain_empty() {
|
|
let map = HashMap::<&'static str, u32>::new();
|
|
let map = map.pin();
|
|
map.retain(|_, _| false);
|
|
assert_eq!(map.len(), 0);
|
|
}
|
|
|
|
#[test]
|
|
fn retain_all_false() {
|
|
let map: HashMap<u32, u32> = (0..10 as u32).map(|x| (x, x)).collect();
|
|
let map = map.pin();
|
|
map.retain(|_, _| false);
|
|
assert_eq!(map.len(), 0);
|
|
}
|
|
|
|
#[test]
|
|
fn retain_all_true() {
|
|
let size = 10usize;
|
|
let map: HashMap<usize, usize> = (0..size).map(|x| (x, x)).collect();
|
|
let map = map.pin();
|
|
map.retain(|_, _| true);
|
|
assert_eq!(map.len(), size);
|
|
}
|
|
|
|
#[test]
|
|
fn retain_some() {
|
|
let map: HashMap<u32, u32> = (0..10).map(|x| (x, x)).collect();
|
|
let map = map.pin();
|
|
let expected_map: HashMap<u32, u32> = (5..10).map(|x| (x, x)).collect();
|
|
let expected_map = expected_map.pin();
|
|
map.retain(|_, v| *v >= 5);
|
|
assert_eq!(map.len(), 5);
|
|
assert_eq!(map, expected_map);
|
|
}
|
|
|
|
#[test]
|
|
fn retain_force_empty() {
|
|
let map = HashMap::<&'static str, u32>::new();
|
|
let map = map.pin();
|
|
map.retain_force(|_, _| false);
|
|
assert_eq!(map.len(), 0);
|
|
}
|
|
|
|
#[test]
|
|
fn retain_force_some() {
|
|
let map: HashMap<u32, u32> = (0..10).map(|x| (x, x)).collect();
|
|
let map = map.pin();
|
|
let expected_map: HashMap<u32, u32> = (5..10).map(|x| (x, x)).collect();
|
|
map.retain_force(|_, v| *v >= 5);
|
|
assert_eq!(map.len(), 5);
|
|
assert_eq!(map, expected_map);
|
|
}
|
|
|
|
#[test]
|
|
#[cfg_attr(miri, ignore)]
|
|
fn concurrent_insert() {
|
|
let map = Arc::new(HashMap::<usize, usize>::new());
|
|
|
|
let map1 = map.clone();
|
|
let t1 = std::thread::spawn(move || {
|
|
for i in 0..64 {
|
|
map1.pin().insert(i, 0);
|
|
}
|
|
});
|
|
let map2 = map.clone();
|
|
let t2 = std::thread::spawn(move || {
|
|
for i in 0..64 {
|
|
map2.pin().insert(i, 0);
|
|
}
|
|
});
|
|
|
|
t1.join().unwrap();
|
|
t2.join().unwrap();
|
|
|
|
let map = map.pin();
|
|
for i in 0..64 {
|
|
let v = map.get(&i).unwrap();
|
|
assert!(v == &0 || v == &1);
|
|
|
|
let kv = map.get_key_value(&i).unwrap();
|
|
assert!(kv == (&i, &0) || kv == (&i, &1));
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
#[cfg_attr(miri, ignore)]
|
|
fn concurrent_remove() {
|
|
let map = Arc::new(HashMap::<usize, usize>::new());
|
|
|
|
{
|
|
let map = map.pin();
|
|
for i in 0..64 {
|
|
map.insert(i, i);
|
|
}
|
|
}
|
|
|
|
let map1 = map.clone();
|
|
let t1 = std::thread::spawn(move || {
|
|
let map1 = map1.pin();
|
|
for i in 0..64 {
|
|
if let Some(v) = map1.remove(&i) {
|
|
assert_eq!(v, &i);
|
|
}
|
|
}
|
|
});
|
|
let map2 = map.clone();
|
|
let t2 = std::thread::spawn(move || {
|
|
let map2 = map2.pin();
|
|
for i in 0..64 {
|
|
if let Some(v) = map2.remove(&i) {
|
|
assert_eq!(v, &i);
|
|
}
|
|
}
|
|
});
|
|
|
|
t1.join().unwrap();
|
|
t2.join().unwrap();
|
|
|
|
// after joining the threads, the map should be empty
|
|
let map = map.pin();
|
|
for i in 0..64 {
|
|
assert!(map.get(&i).is_none());
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
#[cfg_attr(miri, ignore)]
|
|
fn concurrent_compute_if_present() {
|
|
let map = Arc::new(HashMap::<usize, usize>::new());
|
|
|
|
{
|
|
let map = map.pin();
|
|
for i in 0..64 {
|
|
map.insert(i, i);
|
|
}
|
|
}
|
|
|
|
let map1 = map.clone();
|
|
let t1 = std::thread::spawn(move || {
|
|
let map1 = map1.pin();
|
|
for i in 0..64 {
|
|
let new = map1.compute_if_present(&i, |_, _| None);
|
|
assert!(new.is_none());
|
|
}
|
|
});
|
|
let map2 = map.clone();
|
|
let t2 = std::thread::spawn(move || {
|
|
let map2 = map2.pin();
|
|
for i in 0..64 {
|
|
let new = map2.compute_if_present(&i, |_, _| None);
|
|
assert!(new.is_none());
|
|
}
|
|
});
|
|
|
|
t1.join().unwrap();
|
|
t2.join().unwrap();
|
|
|
|
// after joining the threads, the map should be empty
|
|
let map = map.pin();
|
|
for i in 0..64 {
|
|
assert!(map.get(&i).is_none());
|
|
}
|
|
}
|