Skip to content

Commit

Permalink
Merge pull request #492 from moka-rs/support-equivalent-trait
Browse files Browse the repository at this point in the history
Support `Equivalent` trait for the cache key type `K`
  • Loading branch information
tatsuya6502 authored Jan 19, 2025
2 parents dc7368a + fd68e80 commit 2d932ef
Show file tree
Hide file tree
Showing 13 changed files with 121 additions and 161 deletions.
9 changes: 9 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,13 @@
# Moka Cache — Change Log

## Version 0.12.11

### Added

- Support `Equivalent` trait for the key type `K` of the caches.
([#492][gh-pull-0492])


## Version 0.12.10

### Changed
Expand Down Expand Up @@ -959,6 +967,7 @@ The minimum supported Rust version (MSRV) is now 1.51.0 (Mar 25, 2021).
[gh-issue-0034]: https://github.com/moka-rs/moka/issues/34/
[gh-issue-0031]: https://github.com/moka-rs/moka/issues/31/

[gh-pull-0492]: https://github.com/moka-rs/moka/pull/492/
[gh-pull-0482]: https://github.com/moka-rs/moka/pull/482/
[gh-pull-0481]: https://github.com/moka-rs/moka/pull/481/
[gh-pull-0480]: https://github.com/moka-rs/moka/pull/480/
Expand Down
5 changes: 3 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "moka"
version = "0.12.10"
version = "0.12.11"
edition = "2021"
# Rust 1.70 was released on June 1, 2023.
rust-version = "1.70"
Expand Down Expand Up @@ -48,14 +48,15 @@ unstable-debug-counters = ["future", "once_cell"]
crossbeam-channel = "0.5.5"
crossbeam-epoch = "0.9.9"
crossbeam-utils = "0.8"
equivalent = "1.0"
parking_lot = "0.12"
portable-atomic = "1.6"
smallvec = "1.8"
tagptr = "0.2"
thiserror = "1.0"
uuid = { version = "1.1", features = ["v4"] }

# Optional dependencies (enabled by default)
# Optional dependencies (quanta)
quanta = { version = "0.12.2", optional = true }

# Optional dependencies (future)
Expand Down
5 changes: 2 additions & 3 deletions src/cht/segment.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,13 +38,13 @@ use crate::cht::map::{
use super::iter::{Iter, ScanningGet};

use std::{
borrow::Borrow,
hash::{BuildHasher, Hash},
ptr,
sync::atomic::{self, AtomicUsize, Ordering},
};

use crossbeam_epoch::Atomic;
use equivalent::Equivalent;

/// A lock-free hash map implemented with segmented bucket pointer arrays, open
/// addressing, and linear probing.
Expand Down Expand Up @@ -500,8 +500,7 @@ impl<K: Hash + Eq, V, S: BuildHasher> HashMap<K, V, S> {
#[inline]
pub(crate) fn hash<Q>(&self, key: &Q) -> u64
where
Q: Hash + Eq + ?Sized,
K: Borrow<Q>,
Q: Equivalent<K> + Hash + ?Sized,
{
bucket::hash(&self.build_hasher, key)
}
Expand Down
40 changes: 16 additions & 24 deletions src/future/base_cache.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ use common::concurrent::debug_counters::CacheDebugStats;
use async_lock::{Mutex, MutexGuard, RwLock};
use crossbeam_channel::{Receiver, Sender, TrySendError};
use crossbeam_utils::atomic::AtomicCell;
use equivalent::Equivalent;
use futures_util::future::BoxFuture;
use smallvec::SmallVec;
use std::{
Expand Down Expand Up @@ -215,16 +216,14 @@ where
#[inline]
pub(crate) fn hash<Q>(&self, key: &Q) -> u64
where
K: Borrow<Q>,
Q: Hash + Eq + ?Sized,
Q: Equivalent<K> + Hash + ?Sized,
{
self.inner.hash(key)
}

pub(crate) fn contains_key_with_hash<Q>(&self, key: &Q, hash: u64) -> bool
where
K: Borrow<Q>,
Q: Hash + Eq + ?Sized,
Q: Equivalent<K> + Hash + ?Sized,
{
// TODO: Maybe we can just call ScanningGet::scanning_get.
self.inner
Expand All @@ -250,8 +249,7 @@ where
record_read: bool,
) -> Option<Entry<K, V>>
where
K: Borrow<Q>,
Q: Hash + Eq + ?Sized,
Q: Equivalent<K> + Hash + ?Sized,
I: FnMut(&V) -> bool,
{
if self.is_map_disabled() {
Expand Down Expand Up @@ -367,8 +365,7 @@ where

pub(crate) fn get_key_with_hash<Q>(&self, key: &Q, hash: u64) -> Option<Arc<K>>
where
K: Borrow<Q>,
Q: Hash + Eq + ?Sized,
Q: Equivalent<K> + Hash + ?Sized,
{
self.inner
.get_key_value_and(key, hash, |k, _entry| Arc::clone(k))
Expand All @@ -377,8 +374,7 @@ where
#[inline]
pub(crate) fn remove_entry<Q>(&self, key: &Q, hash: u64) -> Option<KvEntry<K, V>>
where
K: Borrow<Q>,
Q: Hash + Eq + ?Sized,
Q: Equivalent<K> + Hash + ?Sized,
{
self.inner.remove_entry(key, hash)
}
Expand Down Expand Up @@ -427,8 +423,8 @@ where
}

fn scanning_get(&self, key: &Arc<K>) -> Option<V> {
let hash = self.hash(key);
self.inner.get_key_value_and_then(key, hash, |k, entry| {
let hash = self.hash(&**key);
self.inner.get_key_value_and_then(&**key, hash, |k, entry| {
let i = &self.inner;
let (ttl, tti, va) = (&i.time_to_live(), &i.time_to_idle(), &i.valid_after());
let now = self.current_time();
Expand Down Expand Up @@ -1208,8 +1204,7 @@ where
#[inline]
fn hash<Q>(&self, key: &Q) -> u64
where
K: Borrow<Q>,
Q: Hash + Eq + ?Sized,
Q: Equivalent<K> + Hash + ?Sized,
{
let mut hasher = self.build_hasher.build_hasher();
key.hash(&mut hasher);
Expand All @@ -1219,33 +1214,30 @@ where
#[inline]
fn get_key_value_and<Q, F, T>(&self, key: &Q, hash: u64, with_entry: F) -> Option<T>
where
K: Borrow<Q>,
Q: Hash + Eq + ?Sized,
Q: Equivalent<K> + Hash + ?Sized,
F: FnOnce(&Arc<K>, &MiniArc<ValueEntry<K, V>>) -> T,
{
self.cache
.get_key_value_and(hash, |k| (k as &K).borrow() == key, with_entry)
.get_key_value_and(hash, |k| key.equivalent(k as &K), with_entry)
}

#[inline]
fn get_key_value_and_then<Q, F, T>(&self, key: &Q, hash: u64, with_entry: F) -> Option<T>
where
K: Borrow<Q>,
Q: Hash + Eq + ?Sized,
Q: Equivalent<K> + Hash + ?Sized,
F: FnOnce(&Arc<K>, &MiniArc<ValueEntry<K, V>>) -> Option<T>,
{
self.cache
.get_key_value_and_then(hash, |k| (k as &K).borrow() == key, with_entry)
.get_key_value_and_then(hash, |k| key.equivalent(k as &K), with_entry)
}

#[inline]
fn remove_entry<Q>(&self, key: &Q, hash: u64) -> Option<KvEntry<K, V>>
where
K: Borrow<Q>,
Q: Hash + Eq + ?Sized,
Q: Equivalent<K> + Hash + ?Sized,
{
self.cache
.remove_entry(hash, |k| (k as &K).borrow() == key)
.remove_entry(hash, |k| key.equivalent(k as &K))
.map(|(key, entry)| KvEntry::new(key, entry))
}

Expand Down Expand Up @@ -2363,7 +2355,7 @@ where
if !kd.is_dirty() {
if let Some(ts) = kd.last_modified() {
let key = kd.key();
let hash = self.hash(key);
let hash = self.hash(&**key);
candidates.push(KeyDateLite::new(key, hash, ts));
len += 1;
}
Expand Down
50 changes: 19 additions & 31 deletions src/future/cache.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
use equivalent::Equivalent;

use super::{
base_cache::BaseCache,
value_initializer::{InitResult, ValueInitializer},
Expand All @@ -16,7 +18,6 @@ use crate::{
use crate::common::concurrent::debug_counters::CacheDebugStats;

use std::{
borrow::Borrow,
collections::hash_map::RandomState,
fmt,
future::Future,
Expand Down Expand Up @@ -858,8 +859,7 @@ where
/// on the borrowed form _must_ match those for the key type.
pub fn contains_key<Q>(&self, key: &Q) -> bool
where
K: Borrow<Q>,
Q: Hash + Eq + ?Sized,
Q: Equivalent<K> + Hash + ?Sized,
{
self.base.contains_key_with_hash(key, self.base.hash(key))
}
Expand All @@ -876,8 +876,7 @@ where
/// [rustdoc-std-arc]: https://doc.rust-lang.org/stable/std/sync/struct.Arc.html
pub async fn get<Q>(&self, key: &Q) -> Option<V>
where
K: Borrow<Q>,
Q: Hash + Eq + ?Sized,
Q: Equivalent<K> + Hash + ?Sized,
{
let ignore_if = None as Option<&mut fn(&V) -> bool>;

Expand Down Expand Up @@ -961,8 +960,7 @@ where
/// ```
pub fn entry_by_ref<'a, Q>(&'a self, key: &'a Q) -> RefKeyEntrySelector<'a, K, Q, V, S>
where
K: Borrow<Q>,
Q: ToOwned<Owned = K> + Hash + Eq + ?Sized,
Q: Equivalent<K> + ToOwned<Owned = K> + Hash + ?Sized,
{
let hash = self.base.hash(key);
RefKeyEntrySelector::new(key, hash, self)
Expand Down Expand Up @@ -1065,8 +1063,7 @@ where
/// cache, the key will be cloned to create new entry in the cache.
pub async fn get_with_by_ref<Q>(&self, key: &Q, init: impl Future<Output = V>) -> V
where
K: Borrow<Q>,
Q: ToOwned<Owned = K> + Hash + Eq + ?Sized,
Q: Equivalent<K> + ToOwned<Owned = K> + Hash + ?Sized,
{
futures_util::pin_mut!(init);
let hash = self.base.hash(key);
Expand Down Expand Up @@ -1204,8 +1201,7 @@ where
pub async fn optionally_get_with_by_ref<F, Q>(&self, key: &Q, init: F) -> Option<V>
where
F: Future<Output = Option<V>>,
K: Borrow<Q>,
Q: ToOwned<Owned = K> + Hash + Eq + ?Sized,
Q: Equivalent<K> + ToOwned<Owned = K> + Hash + ?Sized,
{
futures_util::pin_mut!(init);
let hash = self.base.hash(key);
Expand Down Expand Up @@ -1328,8 +1324,7 @@ where
where
F: Future<Output = Result<V, E>>,
E: Send + Sync + 'static,
K: Borrow<Q>,
Q: ToOwned<Owned = K> + Hash + Eq + ?Sized,
Q: Equivalent<K> + ToOwned<Owned = K> + Hash + ?Sized,
{
futures_util::pin_mut!(init);
let hash = self.base.hash(key);
Expand All @@ -1356,8 +1351,7 @@ where
/// on the borrowed form _must_ match those for the key type.
pub async fn invalidate<Q>(&self, key: &Q)
where
K: Borrow<Q>,
Q: Hash + Eq + ?Sized,
Q: Equivalent<K> + Hash + ?Sized,
{
let hash = self.base.hash(key);
self.invalidate_with_hash(key, hash, false).await;
Expand All @@ -1372,8 +1366,7 @@ where
/// on the borrowed form _must_ match those for the key type.
pub async fn remove<Q>(&self, key: &Q) -> Option<V>
where
K: Borrow<Q>,
Q: Hash + Eq + ?Sized,
Q: Equivalent<K> + Hash + ?Sized,
{
let hash = self.base.hash(key);
self.invalidate_with_hash(key, hash, true).await
Expand Down Expand Up @@ -1542,7 +1535,7 @@ where
) -> Entry<K, V> {
let maybe_entry = self
.base
.get_with_hash(&key, hash, replace_if.as_mut(), need_key, true)
.get_with_hash(&*key, hash, replace_if.as_mut(), need_key, true)
.await;
if let Some(entry) = maybe_entry {
entry
Expand All @@ -1561,8 +1554,7 @@ where
need_key: bool,
) -> Entry<K, V>
where
K: Borrow<Q>,
Q: ToOwned<Owned = K> + Hash + Eq + ?Sized,
Q: Equivalent<K> + ToOwned<Owned = K> + Hash + ?Sized,
{
let maybe_entry = self
.base
Expand Down Expand Up @@ -1616,7 +1608,7 @@ where
) -> Entry<K, V> {
match self
.base
.get_with_hash(&key, hash, never_ignore(), true, true)
.get_with_hash(&*key, hash, never_ignore(), true, true)
.await
{
Some(entry) => entry,
Expand All @@ -1636,8 +1628,7 @@ where
init: impl FnOnce() -> V,
) -> Entry<K, V>
where
K: Borrow<Q>,
Q: ToOwned<Owned = K> + Hash + Eq + ?Sized,
Q: Equivalent<K> + ToOwned<Owned = K> + Hash + ?Sized,
{
match self
.base
Expand Down Expand Up @@ -1667,7 +1658,7 @@ where
{
let entry = self
.base
.get_with_hash(&key, hash, never_ignore(), need_key, true)
.get_with_hash(&*key, hash, never_ignore(), need_key, true)
.await;
if entry.is_some() {
return entry;
Expand All @@ -1686,8 +1677,7 @@ where
) -> Option<Entry<K, V>>
where
F: Future<Output = Option<V>>,
K: Borrow<Q>,
Q: ToOwned<Owned = K> + Hash + Eq + ?Sized,
Q: Equivalent<K> + ToOwned<Owned = K> + Hash + ?Sized,
{
let entry = self
.base
Expand Down Expand Up @@ -1748,7 +1738,7 @@ where
{
if let Some(entry) = self
.base
.get_with_hash(&key, hash, never_ignore(), need_key, true)
.get_with_hash(&*key, hash, never_ignore(), need_key, true)
.await
{
return Ok(entry);
Expand All @@ -1768,8 +1758,7 @@ where
where
F: Future<Output = Result<V, E>>,
E: Send + Sync + 'static,
K: Borrow<Q>,
Q: ToOwned<Owned = K> + Hash + Eq + ?Sized,
Q: Equivalent<K> + ToOwned<Owned = K> + Hash + ?Sized,
{
if let Some(entry) = self
.base
Expand Down Expand Up @@ -1939,8 +1928,7 @@ where
need_value: bool,
) -> Option<V>
where
K: Borrow<Q>,
Q: Hash + Eq + ?Sized,
Q: Equivalent<K> + Hash + ?Sized,
{
use futures_util::FutureExt;

Expand Down
Loading

0 comments on commit 2d932ef

Please sign in to comment.