#lru-cache #cache #lru #hash-map #constant-time

clru

一个具有常量时间操作和加权语义的 LRU 缓存实现

9 个版本 (5 个破坏性更新)

0.6.2 2024 年 5 月 2 日
0.6.1 2022 年 11 月 27 日
0.6.0 2022 年 9 月 23 日
0.5.0 2021 年 6 月 20 日
0.1.0 2020 年 10 月 27 日

#6缓存

Download history 98652/week @ 2024-05-03 105411/week @ 2024-05-10 99935/week @ 2024-05-17 97350/week @ 2024-05-24 104747/week @ 2024-05-31 107545/week @ 2024-06-07 116537/week @ 2024-06-14 109332/week @ 2024-06-21 104570/week @ 2024-06-28 102481/week @ 2024-07-05 103319/week @ 2024-07-12 101605/week @ 2024-07-19 107717/week @ 2024-07-26 97643/week @ 2024-08-02 103185/week @ 2024-08-09 85801/week @ 2024-08-16

413,466 每月下载量
216 个 Crates 中使用 (12 个直接使用)

MIT 许可证

98KB
2K SLoC

CLru

Actions Crate Docs License

CLru 是 Rust 中的另一个 LRU 缓存 实现。它有两个主要特点,使其与其他实现不同

  1. 它背后有一个 HashMap:它为常见的操作如

    • get / get_mut
    • put / pop
    • peek / peek_mut
  2. 提供 O(1) 时间复杂度(摊销平均时间)

    • 它是一个加权缓存:每个键值对都有一个权重,容量同时作为
    • 元素数量的限制

    以及其元素总权重的限制

    使用以下公式

CLruCache::len + CLruCache::weight <= CLruCache::capacity

对于元素没有权重的常见 LRU 缓存情况,提供了一个默认的 ZeroWeightScale,并解锁了一些有用的 API,例如

免责声明

大部分的API、文档、示例和测试都受到了lru crate的很大启发。我想感谢jeromefroe,没有他的工作,这个crate可能永远不会发布。

lru的差异

主要差异包括

  • 更少的unsafe代码。只要经过彻底审查和理解,unsafe代码本身并没有什么不好,但可能很难正确实现。减少unsafe代码的数量应该可以减少错误或未定义的行为。
  • API更接近标准HashMap集合,允许使用通过Borrow-ed版本的键进行查找。

示例

以下是如何实例化和使用这个LRU缓存的简单示例。

使用默认的ZeroWeightScale


use std::num::NonZeroUsize;
use clru::CLruCache;

let mut cache = CLruCache::new(NonZeroUsize::new(2).unwrap());
cache.put("apple".to_string(), 3);
cache.put("banana".to_string(), 2);

assert_eq!(cache.get("apple"), Some(&3));
assert_eq!(cache.get("banana"), Some(&2));
assert!(cache.get("pear").is_none());

assert_eq!(cache.put("banana".to_string(), 4), Some(2));
assert_eq!(cache.put("pear".to_string(), 5), None);

assert_eq!(cache.get("pear"), Some(&5));
assert_eq!(cache.get("banana"), Some(&4));
assert!(cache.get("apple").is_none());

{
    let v = cache.get_mut("banana").unwrap();
    *v = 6;
}

assert_eq!(cache.get("banana"), Some(&6));

使用自定义的WeightScale实现


use std::num::NonZeroUsize;
use clru::{CLruCache, CLruCacheConfig, WeightScale};

struct CustomScale;

impl WeightScale<String, &str> for CustomScale {
    fn weight(&self, _key: &String, value: &&str) -> usize {
        value.len()
    }
}

let mut cache = CLruCache::with_config(
    CLruCacheConfig::new(NonZeroUsize::new(6).unwrap()).with_scale(CustomScale),
);

assert_eq!(cache.put_with_weight("apple".to_string(), "red").unwrap(), None);
assert_eq!(
    cache.put_with_weight("apple".to_string(), "green").unwrap(),
    Some("red")
);

assert_eq!(cache.len(), 1);
assert_eq!(cache.get("apple"), Some(&"green"));

测试

每个贡献都通过常规编译器、miri和4种sanitizer(地址、内存、线程和泄漏)进行测试。这应该有助于尽早捕捉到错误。

待办事项

  • 改进文档并添加示例

无运行时依赖