use idr_ebr::{Config, EbrGuard, Idr, Key};
#[test]
fn smoke() {
let idr: Idr<_> = Idr::default();
assert_eq!(idr.iter(&EbrGuard::new()).count(), 0);
let mut keys = (0..100)
.map(|i| (idr.insert(i).unwrap(), i))
.collect::<Vec<_>>();
for (key, value) in &keys {
assert_eq!(&*idr.get(*key, &EbrGuard::new()).unwrap(), value);
}
check_iter(&idr, keys.clone());
for (key, value) in &keys {
if value % 2 == 0 {
assert!(idr.remove(*key));
}
}
keys.retain(|(key, value)| {
let guard = EbrGuard::new();
let actual = idr.get(*key, &guard);
if value % 2 == 0 {
assert!(actual.is_none());
false
} else {
assert_eq!(actual.unwrap(), *value);
true
}
});
check_iter(&idr, keys);
fn check_iter(idr: &Idr<i32>, mut expected: Vec<(Key, i32)>) {
let mut actual = idr
.iter(&EbrGuard::new())
.map(|(key, entry)| (key, *entry))
.collect::<Vec<_>>();
actual.sort();
expected.sort();
assert_eq!(actual, expected);
}
}
#[test]
fn extension() {
struct TinyConfig;
impl Config for TinyConfig {
const INITIAL_PAGE_SIZE: u32 = 4;
const MAX_PAGES: u32 = 5;
const RESERVED_BITS: u32 = 32;
}
let idr: Idr<_, TinyConfig> = Idr::new();
assert_pages(&idr, 0);
for expected_pages in 1..=TinyConfig::MAX_PAGES {
let capacity = ((1 << (expected_pages - 1)) - 1) * TinyConfig::INITIAL_PAGE_SIZE;
for i in 0..(2 << expected_pages) {
idr.insert(capacity + i).unwrap();
}
assert_pages(&idr, expected_pages);
let len = idr
.iter(&EbrGuard::new())
.enumerate()
.inspect(|(i, (_, value))| assert_eq!(*value, u32::try_from(*i).unwrap()))
.count();
assert_eq!(
u32::try_from(len).unwrap(),
capacity + (2 << expected_pages)
);
}
assert!(idr.insert(42).is_none());
fn assert_pages(idr: impl std::fmt::Debug, expected: u32) {
assert!(format!("{idr:?}").contains(&format!("allocated_pages: {expected}")));
}
}
#[test]
fn reuse() {
struct TinyConfig;
impl Config for TinyConfig {
const INITIAL_PAGE_SIZE: u32 = 4;
const MAX_PAGES: u32 = 29;
const RESERVED_BITS: u32 = 32;
}
assert!(format!("{:?}", TinyConfig::debug()).contains("GENERATION_BITS: 1"));
let idr: Idr<_, TinyConfig> = Idr::new();
let key = idr.insert(0).unwrap();
assert!(idr.remove(key));
let key2 = idr.insert(1).unwrap();
assert!(!idr.contains(key));
assert!(idr.remove(key2));
let key3 = idr.insert(2).unwrap();
assert_eq!(key3, key);
assert_eq!(idr.get(key, &EbrGuard::new()).unwrap(), 2);
assert!(idr.remove(key));
assert!(!idr.contains(key3));
}
#[test]
fn invalid_key() {
let idr = Idr::<i32>::default();
let invalid_key = Key::try_from(1).unwrap();
idr.get(invalid_key, &EbrGuard::new());
}
#[test]
fn to_owned() {
let idr = Idr::<i32>::default();
let key = idr.insert(42).unwrap();
let guard = EbrGuard::new();
let entry = idr.get(key, &guard).unwrap();
let owned = entry.to_owned();
assert_eq!(owned.clone().unwrap(), 42);
assert!(idr.remove(key));
assert!(entry.to_owned().is_some());
#[allow(clippy::clone_on_copy)]
{
assert_eq!(owned.unwrap(), *entry.clone());
}
assert!(entry.to_owned().is_none()); }
#[test]
fn unused_vacant_entry() {
let idr = Idr::<i32>::default();
let key1 = idr.vacant_entry().unwrap().key();
let key2 = idr.vacant_entry().unwrap().key();
assert_eq!(key1, key2);
}
#[test]
fn debug() {
let idr = Idr::<i32>::default();
let guard = EbrGuard::new();
assert_eq!(format!("{guard:?}"), "EbrGuard");
let iter = idr.iter(&guard);
assert_eq!(format!("{iter:?}"), "Iter { .. }");
let key = idr.insert(42).unwrap();
assert_eq!(format!("{:?}", idr.get_owned(key)), "Some(42)");
assert_eq!(format!("{:?}", idr.get(key, &guard)), "Some(42)");
let vacant = idr.vacant_entry().unwrap();
assert!(format!("{vacant:?}").starts_with("VacantEntry { key: "));
}