Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(781)

Side by Side Diff: base/containers/mru_cache.h

Issue 1647803004: Move base to DEPS (Closed) Base URL: git@github.com:domokit/mojo.git@master
Patch Set: Created 4 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « base/containers/linked_list_unittest.cc ('k') | base/containers/mru_cache_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 // This file contains a template for a Most Recently Used cache that allows
6 // constant-time access to items using a key, but easy identification of the
7 // least-recently-used items for removal. Each key can only be associated with
8 // one payload item at a time.
9 //
10 // The key object will be stored twice, so it should support efficient copying.
11 //
12 // NOTE: While all operations are O(1), this code is written for
13 // legibility rather than optimality. If future profiling identifies this as
14 // a bottleneck, there is room for smaller values of 1 in the O(1). :]
15
16 #ifndef BASE_CONTAINERS_MRU_CACHE_H_
17 #define BASE_CONTAINERS_MRU_CACHE_H_
18
19 #include <list>
20 #include <map>
21 #include <utility>
22
23 #include "base/basictypes.h"
24 #include "base/containers/hash_tables.h"
25 #include "base/logging.h"
26
27 namespace base {
28
29 // MRUCacheBase ----------------------------------------------------------------
30
31 // This template is used to standardize map type containers that can be used
32 // by MRUCacheBase. This level of indirection is necessary because of the way
33 // that template template params and default template params interact.
34 template <class KeyType, class ValueType>
35 struct MRUCacheStandardMap {
36 typedef std::map<KeyType, ValueType> Type;
37 };
38
39 // Base class for the MRU cache specializations defined below.
40 // The deletor will get called on all payloads that are being removed or
41 // replaced.
42 template <class KeyType, class PayloadType, class DeletorType,
43 template <typename, typename> class MapType = MRUCacheStandardMap>
44 class MRUCacheBase {
45 public:
46 // The payload of the list. This maintains a copy of the key so we can
47 // efficiently delete things given an element of the list.
48 typedef std::pair<KeyType, PayloadType> value_type;
49
50 private:
51 typedef std::list<value_type> PayloadList;
52 typedef typename MapType<KeyType,
53 typename PayloadList::iterator>::Type KeyIndex;
54
55 public:
56 typedef typename PayloadList::size_type size_type;
57
58 typedef typename PayloadList::iterator iterator;
59 typedef typename PayloadList::const_iterator const_iterator;
60 typedef typename PayloadList::reverse_iterator reverse_iterator;
61 typedef typename PayloadList::const_reverse_iterator const_reverse_iterator;
62
63 enum { NO_AUTO_EVICT = 0 };
64
65 // The max_size is the size at which the cache will prune its members to when
66 // a new item is inserted. If the caller wants to manager this itself (for
67 // example, maybe it has special work to do when something is evicted), it
68 // can pass NO_AUTO_EVICT to not restrict the cache size.
69 explicit MRUCacheBase(size_type max_size) : max_size_(max_size) {
70 }
71
72 MRUCacheBase(size_type max_size, const DeletorType& deletor)
73 : max_size_(max_size), deletor_(deletor) {
74 }
75
76 virtual ~MRUCacheBase() {
77 iterator i = begin();
78 while (i != end())
79 i = Erase(i);
80 }
81
82 size_type max_size() const { return max_size_; }
83
84 // Inserts a payload item with the given key. If an existing item has
85 // the same key, it is removed prior to insertion. An iterator indicating the
86 // inserted item will be returned (this will always be the front of the list).
87 //
88 // The payload will be copied. In the case of an OwningMRUCache, this function
89 // will take ownership of the pointer.
90 iterator Put(const KeyType& key, const PayloadType& payload) {
91 // Remove any existing payload with that key.
92 typename KeyIndex::iterator index_iter = index_.find(key);
93 if (index_iter != index_.end()) {
94 // Erase the reference to it. This will call the deletor on the removed
95 // element. The index reference will be replaced in the code below.
96 Erase(index_iter->second);
97 } else if (max_size_ != NO_AUTO_EVICT) {
98 // New item is being inserted which might make it larger than the maximum
99 // size: kick the oldest thing out if necessary.
100 ShrinkToSize(max_size_ - 1);
101 }
102
103 ordering_.push_front(value_type(key, payload));
104 index_.insert(std::make_pair(key, ordering_.begin()));
105 return ordering_.begin();
106 }
107
108 // Retrieves the contents of the given key, or end() if not found. This method
109 // has the side effect of moving the requested item to the front of the
110 // recency list.
111 //
112 // TODO(brettw) We may want a const version of this function in the future.
113 iterator Get(const KeyType& key) {
114 typename KeyIndex::iterator index_iter = index_.find(key);
115 if (index_iter == index_.end())
116 return end();
117 typename PayloadList::iterator iter = index_iter->second;
118
119 // Move the touched item to the front of the recency ordering.
120 ordering_.splice(ordering_.begin(), ordering_, iter);
121 return ordering_.begin();
122 }
123
124 // Retrieves the payload associated with a given key and returns it via
125 // result without affecting the ordering (unlike Get).
126 iterator Peek(const KeyType& key) {
127 typename KeyIndex::const_iterator index_iter = index_.find(key);
128 if (index_iter == index_.end())
129 return end();
130 return index_iter->second;
131 }
132
133 const_iterator Peek(const KeyType& key) const {
134 typename KeyIndex::const_iterator index_iter = index_.find(key);
135 if (index_iter == index_.end())
136 return end();
137 return index_iter->second;
138 }
139
140 // Erases the item referenced by the given iterator. An iterator to the item
141 // following it will be returned. The iterator must be valid.
142 iterator Erase(iterator pos) {
143 deletor_(pos->second);
144 index_.erase(pos->first);
145 return ordering_.erase(pos);
146 }
147
148 // MRUCache entries are often processed in reverse order, so we add this
149 // convenience function (not typically defined by STL containers).
150 reverse_iterator Erase(reverse_iterator pos) {
151 // We have to actually give it the incremented iterator to delete, since
152 // the forward iterator that base() returns is actually one past the item
153 // being iterated over.
154 return reverse_iterator(Erase((++pos).base()));
155 }
156
157 // Shrinks the cache so it only holds |new_size| items. If |new_size| is
158 // bigger or equal to the current number of items, this will do nothing.
159 void ShrinkToSize(size_type new_size) {
160 for (size_type i = size(); i > new_size; i--)
161 Erase(rbegin());
162 }
163
164 // Deletes everything from the cache.
165 void Clear() {
166 for (typename PayloadList::iterator i(ordering_.begin());
167 i != ordering_.end(); ++i)
168 deletor_(i->second);
169 index_.clear();
170 ordering_.clear();
171 }
172
173 // Returns the number of elements in the cache.
174 size_type size() const {
175 // We don't use ordering_.size() for the return value because
176 // (as a linked list) it can be O(n).
177 DCHECK(index_.size() == ordering_.size());
178 return index_.size();
179 }
180
181 // Allows iteration over the list. Forward iteration starts with the most
182 // recent item and works backwards.
183 //
184 // Note that since these iterators are actually iterators over a list, you
185 // can keep them as you insert or delete things (as long as you don't delete
186 // the one you are pointing to) and they will still be valid.
187 iterator begin() { return ordering_.begin(); }
188 const_iterator begin() const { return ordering_.begin(); }
189 iterator end() { return ordering_.end(); }
190 const_iterator end() const { return ordering_.end(); }
191
192 reverse_iterator rbegin() { return ordering_.rbegin(); }
193 const_reverse_iterator rbegin() const { return ordering_.rbegin(); }
194 reverse_iterator rend() { return ordering_.rend(); }
195 const_reverse_iterator rend() const { return ordering_.rend(); }
196
197 bool empty() const { return ordering_.empty(); }
198
199 private:
200 PayloadList ordering_;
201 KeyIndex index_;
202
203 size_type max_size_;
204
205 DeletorType deletor_;
206
207 DISALLOW_COPY_AND_ASSIGN(MRUCacheBase);
208 };
209
210 // MRUCache --------------------------------------------------------------------
211
212 // A functor that does nothing. Used by the MRUCache.
213 template<class PayloadType>
214 class MRUCacheNullDeletor {
215 public:
216 void operator()(const PayloadType& payload) {}
217 };
218
219 // A container that does not do anything to free its data. Use this when storing
220 // value types (as opposed to pointers) in the list.
221 template <class KeyType, class PayloadType>
222 class MRUCache : public MRUCacheBase<KeyType,
223 PayloadType,
224 MRUCacheNullDeletor<PayloadType> > {
225 private:
226 typedef MRUCacheBase<KeyType, PayloadType,
227 MRUCacheNullDeletor<PayloadType> > ParentType;
228
229 public:
230 // See MRUCacheBase, noting the possibility of using NO_AUTO_EVICT.
231 explicit MRUCache(typename ParentType::size_type max_size)
232 : ParentType(max_size) {
233 }
234 virtual ~MRUCache() {
235 }
236
237 private:
238 DISALLOW_COPY_AND_ASSIGN(MRUCache);
239 };
240
241 // OwningMRUCache --------------------------------------------------------------
242
243 template<class PayloadType>
244 class MRUCachePointerDeletor {
245 public:
246 void operator()(const PayloadType& payload) { delete payload; }
247 };
248
249 // A cache that owns the payload type, which must be a non-const pointer type.
250 // The pointers will be deleted when they are removed, replaced, or when the
251 // cache is destroyed.
252 template <class KeyType, class PayloadType>
253 class OwningMRUCache
254 : public MRUCacheBase<KeyType,
255 PayloadType,
256 MRUCachePointerDeletor<PayloadType> > {
257 private:
258 typedef MRUCacheBase<KeyType, PayloadType,
259 MRUCachePointerDeletor<PayloadType> > ParentType;
260
261 public:
262 // See MRUCacheBase, noting the possibility of using NO_AUTO_EVICT.
263 explicit OwningMRUCache(typename ParentType::size_type max_size)
264 : ParentType(max_size) {
265 }
266 virtual ~OwningMRUCache() {
267 }
268
269 private:
270 DISALLOW_COPY_AND_ASSIGN(OwningMRUCache);
271 };
272
273 // HashingMRUCache ------------------------------------------------------------
274
275 template <class KeyType, class ValueType>
276 struct MRUCacheHashMap {
277 typedef base::hash_map<KeyType, ValueType> Type;
278 };
279
280 // This class is similar to MRUCache, except that it uses base::hash_map as
281 // the map type instead of std::map. Note that your KeyType must be hashable
282 // to use this cache.
283 template <class KeyType, class PayloadType>
284 class HashingMRUCache : public MRUCacheBase<KeyType,
285 PayloadType,
286 MRUCacheNullDeletor<PayloadType>,
287 MRUCacheHashMap> {
288 private:
289 typedef MRUCacheBase<KeyType, PayloadType,
290 MRUCacheNullDeletor<PayloadType>,
291 MRUCacheHashMap> ParentType;
292
293 public:
294 // See MRUCacheBase, noting the possibility of using NO_AUTO_EVICT.
295 explicit HashingMRUCache(typename ParentType::size_type max_size)
296 : ParentType(max_size) {
297 }
298 virtual ~HashingMRUCache() {
299 }
300
301 private:
302 DISALLOW_COPY_AND_ASSIGN(HashingMRUCache);
303 };
304
305 } // namespace base
306
307 #endif // BASE_CONTAINERS_MRU_CACHE_H_
OLDNEW
« no previous file with comments | « base/containers/linked_list_unittest.cc ('k') | base/containers/mru_cache_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698