lru_st/collections/
hashset.rs1use std::{collections::HashMap, hash::Hash};
2
3#[cfg(not(feature = "sync"))]
4use std::rc::{Rc, Weak};
5
6#[cfg(feature = "sync")]
7use {std::sync::Arc as Rc, std::sync::Weak};
8
9use crate::{Cursor, DoublyLinkedList, DoublyLinkedListIter};
10
11pub struct Iter<'a, K>
13where
14 K: Hash + Eq,
15{
16 lru_iter: DoublyLinkedListIter<'a, Weak<K>>,
17}
18
19impl<'a, K> Iterator for Iter<'a, K>
20where
21 K: Hash + Eq,
22{
23 type Item = Rc<K>;
24 fn next(&mut self) -> Option<Self::Item> {
25 if let Some(item) = self.lru_iter.next() {
26 return item.upgrade();
27 }
28 None
29 }
30}
31
32impl<'a, K> DoubleEndedIterator for Iter<'a, K>
33where
34 K: Hash + Eq,
35{
36 fn next_back(&mut self) -> Option<Self::Item> {
37 if let Some(item) = self.lru_iter.next_back() {
38 return item.upgrade();
39 }
40 None
41 }
42}
43
44pub struct LruHashSet<K> {
46 map: HashMap<Rc<K>, Cursor>,
47 lru: DoublyLinkedList<Weak<K>>,
48 max_entries: usize,
49}
50
51impl<K> LruHashSet<K>
52where
53 K: Hash + Eq,
54{
55 pub fn with_max_entries(max_entries: usize) -> Self {
57 LruHashSet {
58 map: HashMap::with_capacity(max_entries),
59 lru: DoublyLinkedList::with_capacity(max_entries),
60 max_entries,
61 }
62 }
63
64 #[inline]
66 pub fn get(&mut self, k: &K) -> Option<Rc<K>> {
67 if let Some(k) = self.map.get(k).and_then(|cursor| {
68 self.lru.move_front(*cursor).unwrap();
69 self.lru.front()
70 }) {
71 return k.upgrade();
72 }
73 None
74 }
75
76 pub fn iter(&mut self) -> Iter<K> {
83 Iter {
84 lru_iter: self.lru.iter(),
85 }
86 }
87
88 #[inline]
90 pub fn contains(&mut self, k: &K) -> bool {
91 self.get(k).is_some()
92 }
93
94 #[inline]
103 pub fn insert(&mut self, k: K) -> bool {
104 if self.contains(&k) {
106 return false;
107 }
108
109 if self.map.len() == self.max_entries {
112 if let Some(k) = self.lru.pop_back() {
113 {
115 let key = k.upgrade().expect("weak reference must be valid");
116 self.map.remove(&key);
117 }
118 debug_assert!(k.upgrade().is_none());
120 };
121 }
122 let k = Rc::new(k);
123 let cursor = self.lru.push_front(Rc::downgrade(&k));
124 self.map.insert(k, cursor);
125 true
126 }
127
128 #[inline]
131 pub fn remove(&mut self, k: &K) -> bool {
132 if let Some(c) = self.map.remove(k) {
133 if self.lru.pop(c).is_some() {
134 return true;
135 }
136 }
137 false
138 }
139
140 #[inline(always)]
142 pub fn len(&self) -> usize {
143 self.map.len()
144 }
145
146 #[inline(always)]
148 pub fn cap(&self) -> usize {
149 self.max_entries
150 }
151
152 #[inline(always)]
154 pub fn is_empty(&self) -> bool {
155 self.map.is_empty()
156 }
157
158 #[inline(always)]
160 pub fn is_full(&self) -> bool {
161 self.max_entries == self.map.len()
162 }
163}
164
165#[cfg(test)]
166mod tests {
167 use super::*;
168
169 #[test]
170 fn basic_hashset_test() {
171 let max_entries = 1000;
172 let mut lru = LruHashSet::with_max_entries(max_entries);
173 assert!(lru.is_empty());
174
175 for i in 0..max_entries * 2 {
176 assert!(lru.insert(i));
177 assert!(lru.contains(&i));
178 }
179
180 for i in 0..max_entries {
183 assert!(!lru.contains(&i));
184 }
185
186 for i in max_entries + 1..max_entries * 2 {
188 assert!(lru.contains(&i));
189 }
190 }
191
192 #[test]
193 fn hashset_get_test() {
194 let mut lru = LruHashSet::with_max_entries(10);
195
196 lru.insert(42);
197 assert_eq!(lru.get(&42), Some(Rc::new(42)));
198 }
199
200 #[test]
201 #[allow(clippy::bool_assert_comparison)]
202 fn hashset_remove_test() {
203 let mut lru = LruHashSet::with_max_entries(10);
204
205 assert_eq!(lru.insert(42), true);
206 assert_eq!(lru.insert(42), false);
207 assert_eq!(lru.remove(&42), true);
208 assert_eq!(lru.remove(&42), false);
209 }
210
211 #[test]
212 fn hashset_iter() {
213 let mut lru = LruHashSet::with_max_entries(10);
214
215 lru.insert(41);
216 lru.insert(42);
217 lru.insert(43);
218 let mut iter = lru.iter();
219 assert_eq!(iter.next(), Some(Rc::new(43)));
220 assert_eq!(iter.next(), Some(Rc::new(42)));
221 assert_eq!(iter.next(), Some(Rc::new(41)));
222 assert_eq!(iter.next(), None);
223
224 lru.remove(&42);
226 let mut iter = lru.iter().rev();
227 assert_eq!(iter.next(), Some(Rc::new(41)));
228 assert_eq!(iter.next(), Some(Rc::new(43)));
229 assert_eq!(iter.next(), None);
230 }
231}