Skip to content

Commit 65b9d1f

Browse files
committed
feat: enhance ClockCache with iterators and documentation
Added `iter` and `iter_mut` methods to `ClockCache`, providing access to key-value pairs in slot order without setting reference bits. Updated documentation throughout the `ClockCache` struct to include examples for new methods, improved clarity on cache behavior, and ensured consistency in usage. Enhanced the `metrics_snapshot` method documentation with an example to illustrate its functionality. This change aims to improve usability and understanding of the `ClockCache` API.
1 parent 3f3d7a4 commit 65b9d1f

1 file changed

Lines changed: 187 additions & 7 deletions

File tree

src/policy/clock.rs

Lines changed: 187 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,7 @@
110110
use std::hash::Hash;
111111

112112
use crate::ds::ClockRing;
113+
use crate::ds::clock_ring::{IntoIter, Iter, IterMut};
113114
use crate::traits::{CoreCache, MutableCache, ReadOnlyCache};
114115

115116
#[cfg(feature = "metrics")]
@@ -143,10 +144,7 @@ use crate::metrics::traits::MetricsSnapshotProvider;
143144
/// assert_eq!(cache.get(&"key1"), Some(&"value1"));
144145
/// assert_eq!(cache.len(), 2);
145146
/// ```
146-
pub struct ClockCache<K, V>
147-
where
148-
K: Clone + Eq + Hash,
149-
{
147+
pub struct ClockCache<K, V> {
150148
ring: ClockRing<K, V>,
151149
#[cfg(feature = "metrics")]
152150
metrics: ClockMetrics,
@@ -158,6 +156,10 @@ where
158156
{
159157
/// Creates a new Clock cache with the specified capacity.
160158
///
159+
/// A capacity of `0` is valid and produces a cache that accepts no entries;
160+
/// all [`insert`](CoreCache::insert) calls will return `None` and the
161+
/// value is silently dropped.
162+
///
161163
/// # Example
162164
///
163165
/// ```
@@ -178,21 +180,106 @@ where
178180
}
179181

180182
/// Returns `true` if the cache is empty.
183+
///
184+
/// # Example
185+
///
186+
/// ```
187+
/// use cachekit::policy::clock::ClockCache;
188+
/// use cachekit::traits::{CoreCache, ReadOnlyCache};
189+
///
190+
/// let mut cache = ClockCache::new(10);
191+
/// assert!(cache.is_empty());
192+
///
193+
/// cache.insert("a", 1);
194+
/// assert!(!cache.is_empty());
195+
/// ```
181196
#[inline]
182197
pub fn is_empty(&self) -> bool {
183198
self.ring.is_empty()
184199
}
185200

201+
/// Returns an iterator over `(&K, &V)` pairs in slot order.
202+
///
203+
/// Does **not** set reference bits.
204+
///
205+
/// # Example
206+
///
207+
/// ```
208+
/// use cachekit::policy::clock::ClockCache;
209+
/// use cachekit::traits::CoreCache;
210+
///
211+
/// let mut cache = ClockCache::new(10);
212+
/// cache.insert("a", 1);
213+
/// cache.insert("b", 2);
214+
///
215+
/// let pairs: Vec<_> = cache.iter().collect();
216+
/// assert_eq!(pairs.len(), 2);
217+
/// ```
218+
#[inline]
219+
pub fn iter(&self) -> Iter<'_, K, V> {
220+
self.ring.iter()
221+
}
222+
223+
/// Returns an iterator over `(&K, &mut V)` pairs in slot order.
224+
///
225+
/// Does **not** set reference bits.
226+
///
227+
/// # Example
228+
///
229+
/// ```
230+
/// use cachekit::policy::clock::ClockCache;
231+
/// use cachekit::traits::CoreCache;
232+
///
233+
/// let mut cache = ClockCache::new(10);
234+
/// cache.insert("a", 1);
235+
/// cache.insert("b", 2);
236+
///
237+
/// for (_key, value) in cache.iter_mut() {
238+
/// *value += 10;
239+
/// }
240+
/// ```
241+
#[inline]
242+
pub fn iter_mut(&mut self) -> IterMut<'_, K, V> {
243+
self.ring.iter_mut()
244+
}
245+
186246
/// Returns the underlying [`ClockRing`] for advanced operations.
187247
///
188-
/// This provides access to additional methods like `peek()`, `touch()`,
189-
/// `peek_victim()`, and `pop_victim()`.
248+
/// Provides access to additional methods like [`ClockRing::peek`],
249+
/// [`ClockRing::touch`], [`ClockRing::peek_victim`], and
250+
/// [`ClockRing::pop_victim`].
251+
///
252+
/// # Example
253+
///
254+
/// ```
255+
/// use cachekit::policy::clock::ClockCache;
256+
/// use cachekit::traits::CoreCache;
257+
///
258+
/// let mut cache = ClockCache::new(10);
259+
/// cache.insert("a", 1);
260+
///
261+
/// // peek reads without setting the reference bit
262+
/// assert_eq!(cache.as_ring().peek(&"a"), Some(&1));
263+
/// ```
190264
#[inline]
191265
pub fn as_ring(&self) -> &ClockRing<K, V> {
192266
&self.ring
193267
}
194268

195269
/// Returns a mutable reference to the underlying [`ClockRing`].
270+
///
271+
/// # Example
272+
///
273+
/// ```
274+
/// use cachekit::policy::clock::ClockCache;
275+
/// use cachekit::traits::CoreCache;
276+
///
277+
/// let mut cache = ClockCache::new(10);
278+
/// cache.insert("a", 1);
279+
///
280+
/// // touch sets the reference bit without returning the value
281+
/// assert!(cache.as_ring_mut().touch(&"a"));
282+
/// ```
196283
#[inline]
197284
pub fn as_ring_mut(&mut self) -> &mut ClockRing<K, V> {
198285
&mut self.ring
@@ -317,6 +404,20 @@ where
317404
}
318405

319406
/// Clears all entries from the cache.
407+
///
408+
/// # Example
409+
///
410+
/// ```
411+
/// use cachekit::policy::clock::ClockCache;
412+
/// use cachekit::traits::{CoreCache, ReadOnlyCache};
413+
///
414+
/// let mut cache = ClockCache::new(10);
415+
/// cache.insert("a", 1);
416+
/// cache.insert("b", 2);
417+
///
418+
/// cache.clear();
419+
/// assert!(cache.is_empty());
420+
/// ```
320421
fn clear(&mut self) {
321422
self.ring.clear();
322423
#[cfg(feature = "metrics")]
@@ -358,6 +459,20 @@ where
358459
K: Clone + Eq + Hash,
359460
{
360461
/// Returns a snapshot of cache metrics.
462+
///
463+
/// # Example
464+
///
465+
/// ```
466+
/// use cachekit::policy::clock::ClockCache;
467+
/// use cachekit::traits::CoreCache;
468+
///
469+
/// let mut cache = ClockCache::new(10);
470+
/// cache.insert("a", 1);
471+
/// cache.get(&"a");
472+
///
473+
/// let snap = cache.metrics_snapshot();
474+
/// assert_eq!(snap.get_hits, 1);
475+
/// ```
361476
pub fn metrics_snapshot(&self) -> ClockMetricsSnapshot {
362477
ClockMetricsSnapshot {
363478
get_calls: self.metrics.get_calls,
@@ -388,7 +503,7 @@ where
388503

389504
impl<K, V> std::fmt::Debug for ClockCache<K, V>
390505
where
391-
K: Clone + Eq + Hash + std::fmt::Debug,
506+
K: Clone + Eq + Hash,
392507
{
393508
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
394509
f.debug_struct("ClockCache")
@@ -398,6 +513,71 @@ where
398513
}
399514
}
400515

516+
impl<K, V> Clone for ClockCache<K, V>
517+
where
518+
K: Clone + Eq + Hash,
519+
V: Clone,
520+
{
521+
fn clone(&self) -> Self {
522+
Self {
523+
ring: self.ring.clone(),
524+
#[cfg(feature = "metrics")]
525+
metrics: self.metrics,
526+
}
527+
}
528+
}
529+
530+
impl<K, V> AsRef<ClockRing<K, V>> for ClockCache<K, V> {
531+
fn as_ref(&self) -> &ClockRing<K, V> {
532+
&self.ring
533+
}
534+
}
535+
536+
impl<K, V> AsMut<ClockRing<K, V>> for ClockCache<K, V> {
537+
fn as_mut(&mut self) -> &mut ClockRing<K, V> {
538+
&mut self.ring
539+
}
540+
}
541+
542+
impl<K, V> IntoIterator for ClockCache<K, V>
543+
where
544+
K: Clone + Eq + Hash,
545+
{
546+
type Item = (K, V);
547+
type IntoIter = IntoIter<K, V>;
548+
549+
fn into_iter(self) -> Self::IntoIter {
550+
self.ring.into_iter()
551+
}
552+
}
553+
554+
impl<'a, K, V> IntoIterator for &'a ClockCache<K, V> {
555+
type Item = (&'a K, &'a V);
556+
type IntoIter = Iter<'a, K, V>;
557+
558+
fn into_iter(self) -> Self::IntoIter {
559+
self.ring.iter()
560+
}
561+
}
562+
563+
impl<'a, K, V> IntoIterator for &'a mut ClockCache<K, V> {
564+
type Item = (&'a K, &'a mut V);
565+
type IntoIter = IterMut<'a, K, V>;
566+
567+
fn into_iter(self) -> Self::IntoIter {
568+
self.ring.iter_mut()
569+
}
570+
}
571+
572+
impl<K, V> Extend<(K, V)> for ClockCache<K, V>
573+
where
574+
K: Clone + Eq + Hash,
575+
{
576+
fn extend<I: IntoIterator<Item = (K, V)>>(&mut self, iter: I) {
577+
self.ring.extend(iter);
578+
}
579+
}
580+
401581
#[cfg(test)]
402582
mod tests {
403583
use super::*;

0 commit comments

Comments
 (0)