]> git.lizzy.rs Git - rust.git/blob - src/libcollections/lru_cache.rs
87b1fee1d27d9e1d018fc7dc553578a9a4328274
[rust.git] / src / libcollections / lru_cache.rs
1 // Copyright 2013 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
4 //
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
10
11
12 //! A cache that holds a limited number of key-value pairs. When the
13 //! capacity of the cache is exceeded, the least-recently-used
14 //! (where "used" means a look-up or putting the pair into the cache)
15 //! pair is automatically removed.
16 //!
17 //! # Example
18 //!
19 //! ```rust
20 //! use collections::LruCache;
21 //!
22 //! let mut cache: LruCache<int, int> = LruCache::new(2);
23 //! cache.put(1, 10);
24 //! cache.put(2, 20);
25 //! cache.put(3, 30);
26 //! assert!(cache.get(&1).is_none());
27 //! assert_eq!(*cache.get(&2).unwrap(), 20);
28 //! assert_eq!(*cache.get(&3).unwrap(), 30);
29 //!
30 //! cache.put(2, 22);
31 //! assert_eq!(*cache.get(&2).unwrap(), 22);
32 //!
33 //! cache.put(6, 60);
34 //! assert!(cache.get(&3).is_none());
35 //!
36 //! cache.change_capacity(1);
37 //! assert!(cache.get(&2).is_none());
38 //! ```
39
40 use std::cast;
41 use std::container::Container;
42 use std::hash::Hash;
43 use std::fmt;
44 use std::ptr;
45
46 use HashMap;
47
48 struct KeyRef<K> { k: *K }
49
50 struct LruEntry<K, V> {
51     key: Option<K>,
52     value: Option<V>,
53     next: *mut LruEntry<K, V>,
54     prev: *mut LruEntry<K, V>,
55 }
56
57 /// An LRU Cache.
58 pub struct LruCache<K, V> {
59     map: HashMap<KeyRef<K>, ~LruEntry<K, V>>,
60     max_size: uint,
61     head: *mut LruEntry<K, V>,
62     tail: *mut LruEntry<K, V>,
63 }
64
65 impl<S, K: Hash<S>> Hash<S> for KeyRef<K> {
66     fn hash(&self, state: &mut S) {
67         unsafe { (*self.k).hash(state) }
68     }
69 }
70
71 impl<K: Eq> Eq for KeyRef<K> {
72     fn eq(&self, other: &KeyRef<K>) -> bool {
73         unsafe{ (*self.k).eq(&*other.k) }
74     }
75 }
76
77 impl<K: TotalEq> TotalEq for KeyRef<K> {}
78
79 impl<K, V> LruEntry<K, V> {
80     fn new() -> LruEntry<K, V> {
81         LruEntry {
82             key: None,
83             value: None,
84             next: ptr::mut_null(),
85             prev: ptr::mut_null(),
86         }
87     }
88
89     fn with_key_value(k: K, v: V) -> LruEntry<K, V> {
90         LruEntry {
91             key: Some(k),
92             value: Some(v),
93             next: ptr::mut_null(),
94             prev: ptr::mut_null(),
95         }
96     }
97 }
98
99 impl<K: Hash + TotalEq, V> LruCache<K, V> {
100     /// Create an LRU Cache that holds at most `capacity` items.
101     pub fn new(capacity: uint) -> LruCache<K, V> {
102         let cache = LruCache {
103             map: HashMap::new(),
104             max_size: capacity,
105             head: unsafe{ cast::transmute(~LruEntry::<K, V>::new()) },
106             tail: unsafe{ cast::transmute(~LruEntry::<K, V>::new()) },
107         };
108         unsafe {
109             (*cache.head).next = cache.tail;
110             (*cache.tail).prev = cache.head;
111         }
112         return cache;
113     }
114
115     /// Put a key-value pair into cache.
116     pub fn put(&mut self, k: K, v: V) {
117         let mut key_existed = false;
118         let (node_ptr, node_opt) = match self.map.find_mut(&KeyRef{k: &k}) {
119             Some(node) => {
120                 key_existed = true;
121                 node.value = Some(v);
122                 let node_ptr: *mut LruEntry<K, V> = &mut **node;
123                 (node_ptr, None)
124             }
125             None => {
126                 let mut node = ~LruEntry::with_key_value(k, v);
127                 let node_ptr: *mut LruEntry<K, V> = &mut *node;
128                 (node_ptr, Some(node))
129             }
130         };
131         if key_existed {
132             self.detach(node_ptr);
133             self.attach(node_ptr);
134         } else {
135             let keyref = unsafe { (*node_ptr).key.as_ref().unwrap() };
136             self.map.swap(KeyRef{k: keyref}, node_opt.unwrap());
137             self.attach(node_ptr);
138             if self.len() > self.capacity() {
139                 self.remove_lru();
140             }
141         }
142     }
143
144     /// Return a value corresponding to the key in the cache.
145     pub fn get<'a>(&'a mut self, k: &K) -> Option<&'a V> {
146         let (value, node_ptr_opt) = match self.map.find_mut(&KeyRef{k: k}) {
147             None => (None, None),
148             Some(node) => {
149                 let node_ptr: *mut LruEntry<K, V> = &mut **node;
150                 unsafe {
151                     match (*node_ptr).value {
152                         None => (None, None),
153                         Some(ref value) => (Some(value), Some(node_ptr))
154                     }
155                 }
156             }
157         };
158         match node_ptr_opt {
159             None => (),
160             Some(node_ptr) => {
161                 self.detach(node_ptr);
162                 self.attach(node_ptr);
163             }
164         }
165         return value;
166     }
167
168     /// Remove and return a value corresponding to the key from the cache.
169     pub fn pop(&mut self, k: &K) -> Option<V> {
170         match self.map.pop(&KeyRef{k: k}) {
171             None => None,
172             Some(lru_entry) => lru_entry.value
173         }
174     }
175
176     /// Return the maximum number of key-value pairs the cache can hold.
177     pub fn capacity(&self) -> uint {
178         self.max_size
179     }
180
181     /// Change the number of key-value pairs the cache can hold. Remove
182     /// least-recently-used key-value pairs if necessary.
183     pub fn change_capacity(&mut self, capacity: uint) {
184         for _ in range(capacity, self.len()) {
185             self.remove_lru();
186         }
187         self.max_size = capacity;
188     }
189
190     #[inline]
191     fn remove_lru(&mut self) {
192         if self.len() > 0 {
193             let lru = unsafe { (*self.tail).prev };
194             self.detach(lru);
195             unsafe {
196                 match (*lru).key {
197                     None => (),
198                     Some(ref k) => { self.map.pop(&KeyRef{k: k}); }
199                 }
200             }
201         }
202     }
203
204     #[inline]
205     fn detach(&mut self, node: *mut LruEntry<K, V>) {
206         unsafe {
207             (*(*node).prev).next = (*node).next;
208             (*(*node).next).prev = (*node).prev;
209         }
210     }
211
212     #[inline]
213     fn attach(&mut self, node: *mut LruEntry<K, V>) {
214         unsafe {
215             (*node).next = (*self.head).next;
216             (*node).prev = self.head;
217             (*self.head).next = node;
218             (*(*node).next).prev = node;
219         }
220     }
221 }
222
223 impl<A: fmt::Show + Hash + TotalEq, B: fmt::Show> fmt::Show for LruCache<A, B> {
224     /// Return a string that lists the key-value pairs from most-recently
225     /// used to least-recently used.
226     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
227         try!(write!(f.buf, r"\{"));
228         let mut cur = self.head;
229         for i in range(0, self.len()) {
230             if i > 0 { try!(write!(f.buf, ", ")) }
231             unsafe {
232                 cur = (*cur).next;
233                 match (*cur).key {
234                     // should never print nil
235                     None => try!(write!(f.buf, "nil")),
236                     Some(ref k) => try!(write!(f.buf, "{}", *k)),
237                 }
238             }
239             try!(write!(f.buf, ": "));
240             unsafe {
241                 match (*cur).value {
242                     // should never print nil
243                     None => try!(write!(f.buf, "nil")),
244                     Some(ref value) => try!(write!(f.buf, "{}", *value)),
245                 }
246             }
247         }
248         write!(f.buf, r"\}")
249     }
250 }
251
252 impl<K: Hash + TotalEq, V> Container for LruCache<K, V> {
253     /// Return the number of key-value pairs in the cache.
254     fn len(&self) -> uint {
255         self.map.len()
256     }
257 }
258
259 impl<K: Hash + TotalEq, V> Mutable for LruCache<K, V> {
260     /// Clear the cache of all key-value pairs.
261     fn clear(&mut self) {
262         self.map.clear();
263     }
264 }
265
266 #[unsafe_destructor]
267 impl<K, V> Drop for LruCache<K, V> {
268     fn drop(&mut self) {
269         unsafe {
270             let _: ~LruEntry<K, V> = cast::transmute(self.head);
271             let _: ~LruEntry<K, V> = cast::transmute(self.tail);
272         }
273     }
274 }
275
276 #[cfg(test)]
277 mod tests {
278     use super::LruCache;
279
280     fn assert_opt_eq<V: Eq>(opt: Option<&V>, v: V) {
281         assert!(opt.is_some());
282         assert!(opt.unwrap() == &v);
283     }
284
285     #[test]
286     fn test_put_and_get() {
287         let mut cache: LruCache<int, int> = LruCache::new(2);
288         cache.put(1, 10);
289         cache.put(2, 20);
290         assert_opt_eq(cache.get(&1), 10);
291         assert_opt_eq(cache.get(&2), 20);
292         assert_eq!(cache.len(), 2);
293     }
294
295     #[test]
296     fn test_put_update() {
297         let mut cache: LruCache<~str, Vec<u8>> = LruCache::new(1);
298         cache.put(~"1", vec![10, 10]);
299         cache.put(~"1", vec![10, 19]);
300         assert_opt_eq(cache.get(&~"1"), vec![10, 19]);
301         assert_eq!(cache.len(), 1);
302     }
303
304     #[test]
305     fn test_expire_lru() {
306         let mut cache: LruCache<~str, ~str> = LruCache::new(2);
307         cache.put(~"foo1", ~"bar1");
308         cache.put(~"foo2", ~"bar2");
309         cache.put(~"foo3", ~"bar3");
310         assert!(cache.get(&~"foo1").is_none());
311         cache.put(~"foo2", ~"bar2update");
312         cache.put(~"foo4", ~"bar4");
313         assert!(cache.get(&~"foo3").is_none());
314     }
315
316     #[test]
317     fn test_pop() {
318         let mut cache: LruCache<int, int> = LruCache::new(2);
319         cache.put(1, 10);
320         cache.put(2, 20);
321         assert_eq!(cache.len(), 2);
322         let opt1 = cache.pop(&1);
323         assert!(opt1.is_some());
324         assert_eq!(opt1.unwrap(), 10);
325         assert!(cache.get(&1).is_none());
326         assert_eq!(cache.len(), 1);
327     }
328
329     #[test]
330     fn test_change_capacity() {
331         let mut cache: LruCache<int, int> = LruCache::new(2);
332         assert_eq!(cache.capacity(), 2);
333         cache.put(1, 10);
334         cache.put(2, 20);
335         cache.change_capacity(1);
336         assert!(cache.get(&1).is_none());
337         assert_eq!(cache.capacity(), 1);
338     }
339
340     #[test]
341     fn test_to_str() {
342         let mut cache: LruCache<int, int> = LruCache::new(3);
343         cache.put(1, 10);
344         cache.put(2, 20);
345         cache.put(3, 30);
346         assert_eq!(cache.to_str(), ~"{3: 30, 2: 20, 1: 10}");
347         cache.put(2, 22);
348         assert_eq!(cache.to_str(), ~"{2: 22, 3: 30, 1: 10}");
349         cache.put(6, 60);
350         assert_eq!(cache.to_str(), ~"{6: 60, 2: 22, 3: 30}");
351         cache.get(&3);
352         assert_eq!(cache.to_str(), ~"{3: 30, 6: 60, 2: 22}");
353         cache.change_capacity(2);
354         assert_eq!(cache.to_str(), ~"{3: 30, 6: 60}");
355     }
356
357     #[test]
358     fn test_clear() {
359         let mut cache: LruCache<int, int> = LruCache::new(2);
360         cache.put(1, 10);
361         cache.put(2, 20);
362         cache.clear();
363         assert!(cache.get(&1).is_none());
364         assert!(cache.get(&2).is_none());
365         assert_eq!(cache.to_str(), ~"{}");
366     }
367 }