Skip to content

Commit 8ae53e9

Browse files
committed
---
yaml --- r: 92124 b: refs/heads/auto c: f9aecdb h: refs/heads/master v: v3
1 parent 82ee965 commit 8ae53e9

File tree

14 files changed

+518
-29
lines changed

14 files changed

+518
-29
lines changed

[refs]

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ refs/heads/try3: 9387340aab40a73e8424c48fd42f0c521a4875c0
1313
refs/tags/release-0.3.1: 495bae036dfe5ec6ceafd3312b4dca48741e845b
1414
refs/tags/release-0.4: e828ea2080499553b97dfe33b3f4d472b4562ad7
1515
refs/tags/release-0.5: 7e3bcfbf21278251ee936ad53e92e9b719702d73
16-
refs/heads/auto: 17a951c7bf8c302a964a611c6ee1d46c461c50a3
16+
refs/heads/auto: f9aecdb22ad95c7be37c6e2e45dce2242f6a59d9
1717
refs/heads/servo: af82457af293e2a842ba6b7759b70288da276167
1818
refs/tags/release-0.6: b4ebcfa1812664df5e142f0134a5faea3918544c
1919
refs/tags/0.1: b19db808c2793fe2976759b85a355c3ad8c8b336

branches/auto/src/libextra/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@ pub mod sort;
7070
pub mod dlist;
7171
pub mod treemap;
7272
pub mod btree;
73+
pub mod lru_cache;
7374

7475
// And ... other stuff
7576

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

branches/auto/src/librustc/middle/typeck/check/vtable.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,6 @@ fn lookup_vtables(vcx: &VtableContext,
9494
location_info,
9595
type_param_defs.repr(vcx.tcx()),
9696
substs.repr(vcx.tcx()));
97-
let _i = indenter();
9897

9998
// We do this backwards for reasons discussed above.
10099
assert_eq!(substs.tps.len(), type_param_defs.len());

0 commit comments

Comments
 (0)