use std::sync::atomic::{
AtomicI64,
Ordering::{Acquire, Release},
};
pub struct WatchVersionMap {
map: Box<[AtomicI64]>,
size_mask: u64,
}
impl WatchVersionMap {
pub fn new(size: u64) -> Self {
assert!(
size.is_power_of_two(),
"WatchVersionMap size must be a power of two"
);
let map = (0..size).map(|_| AtomicI64::new(0)).collect::<Box<[_]>>();
Self {
map,
size_mask: size - 1,
}
}
#[inline]
pub fn read_version(&self, key_hash: u64) -> u64 {
self.map[(key_hash & self.size_mask) as usize].load(Acquire) as u64
}
#[inline]
pub fn increment_version(&self, key_hash: u64) {
self.map[(key_hash & self.size_mask) as usize].fetch_add(1, Release);
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
#[should_panic(expected = "power of two")]
fn rejects_non_power_of_two() {
let _ = WatchVersionMap::new(3);
}
#[test]
fn read_starts_at_zero_and_increment_bumps_only_own_bucket() {
let map = WatchVersionMap::new(4);
assert_eq!(map.read_version(0), 0);
assert_eq!(map.read_version(u64::MAX), 0);
map.increment_version(0);
map.increment_version(0);
map.increment_version(u64::MAX); assert_eq!(map.read_version(0), 2);
assert_eq!(map.read_version(3), 1);
assert_eq!(map.read_version(7), 1); }
}