extern crate bit_vec;
use std::collections::HashMap;
use std::hash::{Hash, Hasher};
use bit_vec::BitVec;
struct KeyRef<K> {
k: *const K,
}
impl<K: Hash> Hash for KeyRef<K> {
fn hash<H: Hasher>(&self, state: &mut H) {
unsafe { (*self.k).hash(state) }
}
}
impl<K: PartialEq> PartialEq for KeyRef<K> {
fn eq(&self, other: &KeyRef<K>) -> bool {
unsafe { (*self.k).eq(&*other.k) }
}
}
impl<K: Eq> Eq for KeyRef<K> {}
struct ClockEntry<K, V> {
key: K,
val: V,
}
impl<K, V> ClockEntry<K, V> {
fn new(key: K, val: V) -> Self {
ClockEntry {
key: key,
val: val,
}
}
}
pub struct ClockCache<K, V> {
map: HashMap<KeyRef<K>, usize>,
entries: Vec<ClockEntry<K, V>>,
bits: BitVec,
cap: usize,
idx: usize,
}
impl<K: Hash + Eq, V> ClockCache<K, V> {
pub fn new(cap: usize) -> ClockCache<K, V> {
ClockCache {
map: HashMap::with_capacity(cap),
entries: Vec::with_capacity(cap),
bits: BitVec::from_fn(cap, |_| false),
cap: cap,
idx: 0,
}
}
pub fn put(&mut self, k: K, v: V) {
match self.map.get(&KeyRef { k: &k }) {
Some(idx) => {
self.entries.get_mut(*idx).map(|entry| entry.val = v);
return;
}
None => (),
};
let entry = if self.entries.len() < self.cap {
self.entries.push(ClockEntry::new(k, v));
self.entries.get_mut(self.idx).unwrap()
} else {
let mut usage_bit = self.bits.get(self.idx).unwrap();
while usage_bit {
self.bits.set(self.idx, false);
self.idx = (self.idx + 1) % self.cap;
usage_bit = self.bits.get(self.idx).unwrap();
}
self.bits.set(self.idx, true);
let entry = self.entries.get_mut(self.idx).unwrap();
let old_key = KeyRef { k: &entry.key };
self.map.remove(&old_key);
entry.key = k;
entry.val = v;
entry
};
let key = KeyRef { k: &entry.key };
self.map.insert(key, self.idx);
self.idx = (self.idx + 1) % self.cap;
}
pub fn get<'a>(&'a mut self, k: &K) -> Option<&'a V> {
let key = KeyRef { k: k };
match self.map.get(&key) {
None => None,
Some(idx) => {
self.bits.set(*idx, true);
Some(self.entries.get(*idx).map(|entry| &entry.val).unwrap())
}
}
}
pub fn peek<'a>(&'a mut self, k: &K) -> Option<&'a V> {
let key = KeyRef { k: k };
match self.map.get(&key) {
None => None,
Some(idx) => Some(self.entries.get(*idx).map(|entry| &entry.val).unwrap()),
}
}
pub fn contains(&self, k: &K) -> bool {
let key = KeyRef { k: k };
self.map.contains_key(&key)
}
pub fn pop(&mut self, k: &K) -> bool {
let key = KeyRef { k: k };
match self.map.remove(&key) {
None => false,
Some(_) => true,
}
}
pub fn len(&self) -> usize {
self.map.len()
}
pub fn cap(&self) -> usize {
self.cap
}
}
#[cfg(test)]
mod tests {
use std::fmt::Debug;
use super::ClockCache;
fn assert_opt_eq<V: PartialEq + Debug>(opt: Option<&V>, v: V) {
assert!(opt.is_some());
assert_eq!(opt.unwrap(), &v);
}
#[test]
fn test_put_and_get() {
let mut cache = ClockCache::new(2);
cache.put("apple", "red");
cache.put("banana", "yellow");
assert_eq!(cache.cap(), 2);
assert_eq!(cache.len(), 2);
assert_opt_eq(cache.get(&"apple"), "red");
assert_opt_eq(cache.get(&"banana"), "yellow");
}
#[test]
fn test_put_update() {
let mut cache = ClockCache::new(1);
cache.put("apple", "red");
cache.put("apple", "green");
assert_eq!(cache.len(), 1);
assert_opt_eq(cache.get(&"apple"), "green");
}
#[test]
fn test_peek() {
let mut cache = ClockCache::new(2);
cache.put("apple", "red");
cache.put("banana", "yellow");
assert_opt_eq(cache.peek(&"banana"), "yellow");
assert_opt_eq(cache.peek(&"apple"), "red");
cache.put("pear", "green");
assert!(cache.peek(&"apple").is_none());
assert_opt_eq(cache.peek(&"banana"), "yellow");
assert_opt_eq(cache.peek(&"pear"), "green");
}
#[test]
fn test_contains() {
let mut cache = ClockCache::new(2);
cache.put("apple", "red");
cache.put("banana", "yellow");
cache.put("pear", "green");
assert!(!cache.contains(&"apple"));
assert!(cache.contains(&"banana"));
assert!(cache.contains(&"pear"));
}
#[test]
fn test_pop() {
let mut cache = ClockCache::new(2);
cache.put("apple", "red");
cache.put("banana", "yellow");
assert!(cache.pop(&"apple"));
assert!(cache.pop(&"banana"));
assert!(!cache.pop(&"apple"));
assert!(!cache.pop(&"apple"));
assert_eq!(cache.len(), 0);
}
}