Skip to content

Commit

Permalink
add arc
Browse files Browse the repository at this point in the history
  • Loading branch information
tickbh committed Jun 18, 2024
1 parent ec5168f commit b0a2706
Show file tree
Hide file tree
Showing 6 changed files with 256 additions and 54 deletions.
2 changes: 1 addition & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
[package]
name = "algorithm"
version = "0.1.5"
version = "0.1.6"
edition = "2021"
authors = ["tickbh <[email protected]>"]
description = "about algorithm data structure, now has lru/lru-k/lfu/slab/rbtree/roaring_bitmap/timer_wheelss, 关于算法常用的数据结构"
repository = "https://github.com/tickbh/algorithm-rs"
license = "Apache-2.0"
keywords = ["algorithm", "lru", "lfu", "timerwheel", "slab"]
keywords = ["arc", "lru", "lfu", "timerwheel", "slab"]

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

Expand Down
68 changes: 53 additions & 15 deletions src/cache/arc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -264,42 +264,80 @@ impl<K: Hash + Eq, V, S: BuildHasher> ArcCache<K, V, S> {
// Drain { base: self }
// }

/// 弹出栈顶上的数据, 最近使用的数据
/// 弹出栈顶上的数据, 最常使用的数据
///
/// ```
/// use algorithm::ArcCache;
/// fn main() {
/// let mut arc = ArcCache::new(3);
/// arc.insert("hello", "algorithm");
/// arc.insert("this", "arc");
/// assert!(arc.pop()==Some(("this", "arc")));
/// assert!(arc.pop_usual()==Some(("this", "arc")));
/// assert!(arc.len() == 1);
/// }
/// ```
pub fn pop(&mut self) -> Option<(K, V)> {
pub fn pop_usual(&mut self) -> Option<(K, V)> {
if self.main_lru.len() != 0 {
return self.main_lru.pop();
return self.main_lru.pop_usual();
}
self.main_lfu.pop()
self.main_lfu.pop_usual()
}

/// 弹出栈尾上的数据, 最久未使用的数据
/// 弹出栈尾上的数据, 最不常使用的数据
///
/// ```
/// use algorithm::ArcCache;
/// fn main() {
/// let mut arc = ArcCache::new(3);
/// arc.insert("hello", "algorithm");
/// arc.insert("this", "arc");
/// assert!(arc.pop_last()==Some(("hello", "algorithm")));
/// assert!(arc.pop_unusual()==Some(("hello", "algorithm")));
/// assert!(arc.len() == 1);
/// }
/// ```
pub fn pop_last(&mut self) -> Option<(K, V)> {
pub fn pop_unusual(&mut self) -> Option<(K, V)> {
if self.main_lru.len() != 0 {
return self.main_lru.pop_last();
return self.main_lru.pop_unusual();
}
self.main_lfu.pop_last()
self.main_lfu.pop_unusual()
}

/// 取出栈顶上的数据, 最常使用的数据
///
/// ```
/// use algorithm::ArcCache;
/// fn main() {
/// let mut arc = ArcCache::new(3);
/// arc.insert("hello", "algorithm");
/// arc.insert("this", "arc");
/// assert!(arc.peek_usual()==Some((&"this", &"arc")));
/// assert!(arc.len() == 2);
/// }
/// ```
pub fn peek_usual(&mut self) -> Option<(&K, &V)> {
if self.main_lru.len() != 0 {
return self.main_lru.peek_usual();
}
self.main_lfu.peek_usual()
}

/// 取出栈尾上的数据, 最不常使用的数据
///
/// ```
/// use algorithm::ArcCache;
/// fn main() {
/// let mut arc = ArcCache::new(3);
/// arc.insert("hello", "algorithm");
/// arc.insert("this", "arc");
/// assert!(arc.peek_last()==Some((&"hello", &"algorithm")));
/// assert!(arc.len() == 2);
/// }
/// ```
pub fn peek_last(&mut self) -> Option<(&K, &V)> {
if self.main_lru.len() != 0 {
return self.main_lru.peek_unusual();
}
self.main_lfu.peek_unusual()
}

pub fn contains_key<Q>(&mut self, k: &Q) -> bool
Expand Down Expand Up @@ -483,7 +521,7 @@ impl<K: Hash + Eq, V, S: BuildHasher> ArcCache<K, V, S> {
}

if self.main_lru.is_full() {
let (pk, pv) = self.main_lru.pop_last().unwrap();
let (pk, pv) = self.main_lru.pop_unusual().unwrap();
self.ghost_lru.insert(pk, pv);
}
self.get_or_insert_mut(k, f)
Expand Down Expand Up @@ -585,7 +623,7 @@ impl<K: Hash + Eq, V, S: BuildHasher> Iterator for IntoIter<K, V, S> {
type Item = (K, V);

fn next(&mut self) -> Option<(K, V)> {
self.base.pop()
self.base.pop_usual()
}

fn size_hint(&self) -> (usize, Option<usize>) {
Expand Down Expand Up @@ -638,7 +676,7 @@ impl<'a, K: Hash + Eq, V, S: BuildHasher> DoubleEndedIterator for Iter<'a, K, V,
impl<K: Hash + Eq, V, S: BuildHasher> DoubleEndedIterator for IntoIter<K, V, S> {
#[inline]
fn next_back(&mut self) -> Option<(K, V)> {
self.base.pop_last()
self.base.pop_unusual()
}
}

Expand Down Expand Up @@ -983,9 +1021,9 @@ mod tests {
m.insert(2, 4);
m.insert(1, 2);
assert_eq!(m.len(), 3);
assert_eq!(m.pop(), Some((1, 2)));
assert_eq!(m.pop_usual(), Some((1, 2)));
assert_eq!(m.len(), 2);
assert_eq!(m.pop_last(), Some((3, 6)));
assert_eq!(m.pop_unusual(), Some((3, 6)));
assert_eq!(m.len(), 1);
}

Expand Down
90 changes: 77 additions & 13 deletions src/cache/lfu.rs
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,7 @@ impl<K, V> LfuEntry<K, V> {
/// ```
pub struct LfuCache<K, V, S> {
map: HashMap<KeyRef<K>, NonNull<LfuEntry<K, V>>, S>,
/// 因为HashSet的pop耗时太长, 所以取LruCache暂时做为平替
times_map: HashMap<u8, LruCache<KeyRef<K>, (), DefaultHasher>>,
cap: usize,
max_freq: u8,
Expand Down Expand Up @@ -362,7 +363,7 @@ impl<K: Hash + Eq, V, S: BuildHasher> LfuCache<K, V, S> {

pub fn full_decrease(&mut self) -> Option<(K, V)> {
if self.cap == self.len() {
let ret = self.pop_last();
let ret = self.pop_unusual();
self.cap = self.cap.saturating_sub(1);
ret
} else {
Expand Down Expand Up @@ -460,7 +461,7 @@ impl<K: Hash + Eq, V, S: BuildHasher> LfuCache<K, V, S> {
Drain { base: self }
}

/// 弹出栈顶上的数据, 最近使用的数据
/// 弹出栈顶上的数据, 最常使用的数据
///
/// ```
/// use algorithm::LfuCache;
Expand All @@ -469,11 +470,11 @@ impl<K: Hash + Eq, V, S: BuildHasher> LfuCache<K, V, S> {
/// lru.insert("hello", "algorithm");
/// lru.insert("this", "lru");
/// let _ = lru.get("this");
/// assert!(lru.pop()==Some(("this", "lru")));
/// assert!(lru.pop_usual()==Some(("this", "lru")));
/// assert!(lru.len() == 1);
/// }
/// ```
pub fn pop(&mut self) -> Option<(K, V)> {
pub fn pop_usual(&mut self) -> Option<(K, V)> {
if self.len() == 0 {
return None;
}
Expand All @@ -488,14 +489,13 @@ impl<K: Hash + Eq, V, S: BuildHasher> LfuCache<K, V, S> {
let node = *Box::from_raw(value.as_ptr());
let LfuEntry { key, val, .. } = node;
return Some((key.assume_init(), val.assume_init()));
// val.take(value)
}
}
None
}
}

/// 弹出栈尾上的数据, 最久未使用的数据
/// 弹出栈尾上的数据, 最不常使用的数据
///
/// ```
/// use algorithm::LfuCache;
Expand All @@ -504,11 +504,11 @@ impl<K: Hash + Eq, V, S: BuildHasher> LfuCache<K, V, S> {
/// lru.insert("hello", "algorithm");
/// lru.insert("this", "lru");
/// let _ = lru.get("this");
/// assert!(lru.pop_last()==Some(("hello", "algorithm")));
/// assert!(lru.pop_unusual()==Some(("hello", "algorithm")));
/// assert!(lru.len() == 1);
/// }
/// ```
pub fn pop_last(&mut self) -> Option<(K, V)> {
pub fn pop_unusual(&mut self) -> Option<(K, V)> {
if self.len() == 0 {
return None;
}
Expand All @@ -531,6 +531,70 @@ impl<K: Hash + Eq, V, S: BuildHasher> LfuCache<K, V, S> {
}
}

/// 取出栈顶上的数据, 最常使用的数据
///
/// ```
/// use algorithm::LfuCache;
/// fn main() {
/// let mut lru = LfuCache::new(3);
/// lru.insert("hello", "algorithm");
/// lru.insert("this", "lru");
/// let _ = lru.get("this");
/// assert!(lru.peek_usual()==Some((&"this", &"lru")));
/// assert!(lru.len() == 2);
/// }
/// ```
pub fn peek_usual(&mut self) -> Option<(&K, &V)> {
if self.len() == 0 {
return None;
}
unsafe {
for i in (self.min_freq..=self.max_freq).rev() {
if let Some(val) = self.times_map.get_mut(&i) {
if val.is_empty() {
continue;
}
let key = val.peek_usual().unwrap().0;
let val = self.map.get(key).unwrap().as_ptr();
return Some((&*(*val).key.as_ptr(), &*(*val).val.as_ptr()));
}
}
None
}
}

/// 取出栈尾上的数据, 最不常使用的数据
///
/// ```
/// use algorithm::LfuCache;
/// fn main() {
/// let mut lru = LfuCache::new(3);
/// lru.insert("hello", "algorithm");
/// lru.insert("this", "lru");
/// let _ = lru.get("this");
/// assert!(lru.peek_unusual()==Some((&"hello", &"algorithm")));
/// assert!(lru.len() == 2);
/// }
/// ```
pub fn peek_unusual(&mut self) -> Option<(&K, &V)> {
if self.len() == 0 {
return None;
}

unsafe {
for i in self.min_freq..=self.max_freq {
if let Some(val) = self.times_map.get_mut(&i) {
if val.is_empty() {
continue;
}
let key = val.peek_usual().unwrap().0;
let val = self.map.get(key).unwrap().as_ptr();
return Some((&*(*val).key.as_ptr(), &*(*val).val.as_ptr()));
}
}
None
}
}
pub fn contains_key<Q>(&mut self, k: &Q) -> bool
where
K: Borrow<Q>,
Expand Down Expand Up @@ -837,7 +901,7 @@ impl<K: Hash + Eq, V, S: BuildHasher> LfuCache<K, V, S> {
}

fn _pop_one(keys: &mut LruCache<KeyRef<K>, (), DefaultHasher>) -> Option<KeyRef<K>> {
keys.pop().map(|(k, _)| k)
keys.pop_usual().map(|(k, _)| k)
// let k = if let Some(k) = keys.iter().next() {
// KeyRef { k: k.k }
// } else {
Expand Down Expand Up @@ -894,7 +958,7 @@ impl<K: Hash + Eq, V, S: BuildHasher> Iterator for IntoIter<K, V, S> {
type Item = (K, V);

fn next(&mut self) -> Option<(K, V)> {
self.base.pop()
self.base.pop_usual()
}

fn size_hint(&self) -> (usize, Option<usize>) {
Expand Down Expand Up @@ -1117,7 +1181,7 @@ impl<'a, K: Hash + Eq, V, S: BuildHasher> Iterator for Drain<'a, K, V, S> {
if self.base.len() == 0 {
return None;
}
self.base.pop_last()
self.base.pop_unusual()
}
}

Expand Down Expand Up @@ -1430,9 +1494,9 @@ mod tests {
let _ = m.get(&2);
m.insert(1, 2);
assert_eq!(m.len(), 3);
assert_eq!(m.pop_last(), Some((1, 2)));
assert_eq!(m.pop_unusual(), Some((1, 2)));
assert_eq!(m.len(), 2);
assert_eq!(m.pop_last(), Some((3, 6)));
assert_eq!(m.pop_unusual(), Some((3, 6)));
assert_eq!(m.len(), 1);
}

Expand Down
Loading

0 comments on commit b0a2706

Please sign in to comment.