Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 // This file contains a template for a Most Recently Used cache that allows | 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 | 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 | 7 // least-recently-used items for removal. Each key can only be associated with |
| 8 // one payload item at a time. | 8 // one payload item at a time. |
| 9 // | 9 // |
| 10 // The key object will be stored twice, so it should support efficient copying. | 10 // The key object will be stored twice, so it should support efficient copying. |
| (...skipping 23 matching lines...) Expand all Loading... | |
| 34 | 34 |
| 35 // This template is used to standardize map type containers that can be used | 35 // This template is used to standardize map type containers that can be used |
| 36 // by MRUCacheBase. This level of indirection is necessary because of the way | 36 // by MRUCacheBase. This level of indirection is necessary because of the way |
| 37 // that template template params and default template params interact. | 37 // that template template params and default template params interact. |
| 38 template <class KeyType, class ValueType, class CompareType> | 38 template <class KeyType, class ValueType, class CompareType> |
| 39 struct MRUCacheStandardMap { | 39 struct MRUCacheStandardMap { |
| 40 typedef std::map<KeyType, ValueType, CompareType> Type; | 40 typedef std::map<KeyType, ValueType, CompareType> Type; |
| 41 }; | 41 }; |
| 42 | 42 |
| 43 // Base class for the MRU cache specializations defined below. | 43 // Base class for the MRU cache specializations defined below. |
| 44 // The deletor will get called on all payloads that are being removed or | |
| 45 // replaced. | |
| 46 template <class KeyType, | 44 template <class KeyType, |
| 47 class PayloadType, | 45 class PayloadType, |
| 48 class HashOrCompareType, | 46 class HashOrCompareType, |
| 49 class DeletorType, | |
| 50 template <typename, typename, typename> class MapType = | 47 template <typename, typename, typename> class MapType = |
| 51 MRUCacheStandardMap> | 48 MRUCacheStandardMap> |
| 52 class MRUCacheBase { | 49 class MRUCacheBase { |
| 53 public: | 50 public: |
| 54 // The payload of the list. This maintains a copy of the key so we can | 51 // The payload of the list. This maintains a copy of the key so we can |
| 55 // efficiently delete things given an element of the list. | 52 // efficiently delete things given an element of the list. |
| 56 typedef std::pair<KeyType, PayloadType> value_type; | 53 typedef std::pair<KeyType, PayloadType> value_type; |
| 57 | 54 |
| 58 private: | 55 private: |
| 59 typedef std::list<value_type> PayloadList; | 56 typedef std::list<value_type> PayloadList; |
| 60 typedef typename MapType<KeyType, | 57 typedef typename MapType<KeyType, |
| 61 typename PayloadList::iterator, | 58 typename PayloadList::iterator, |
| 62 HashOrCompareType>::Type KeyIndex; | 59 HashOrCompareType>::Type KeyIndex; |
| 63 | 60 |
| 64 public: | 61 public: |
| 65 typedef typename PayloadList::size_type size_type; | 62 typedef typename PayloadList::size_type size_type; |
| 66 | 63 |
| 67 typedef typename PayloadList::iterator iterator; | 64 typedef typename PayloadList::iterator iterator; |
| 68 typedef typename PayloadList::const_iterator const_iterator; | 65 typedef typename PayloadList::const_iterator const_iterator; |
| 69 typedef typename PayloadList::reverse_iterator reverse_iterator; | 66 typedef typename PayloadList::reverse_iterator reverse_iterator; |
| 70 typedef typename PayloadList::const_reverse_iterator const_reverse_iterator; | 67 typedef typename PayloadList::const_reverse_iterator const_reverse_iterator; |
| 71 | 68 |
| 72 enum { NO_AUTO_EVICT = 0 }; | 69 enum { NO_AUTO_EVICT = 0 }; |
| 73 | 70 |
| 74 // The max_size is the size at which the cache will prune its members to when | 71 // The max_size is the size at which the cache will prune its members to when |
| 75 // a new item is inserted. If the caller wants to manager this itself (for | 72 // a new item is inserted. If the caller wants to manager this itself (for |
| 76 // example, maybe it has special work to do when something is evicted), it | 73 // example, maybe it has special work to do when something is evicted), it |
| 77 // can pass NO_AUTO_EVICT to not restrict the cache size. | 74 // can pass NO_AUTO_EVICT to not restrict the cache size. |
| 78 explicit MRUCacheBase(size_type max_size) : max_size_(max_size) { | 75 explicit MRUCacheBase(size_type max_size) : max_size_(max_size) {} |
| 79 } | |
| 80 | 76 |
| 81 MRUCacheBase(size_type max_size, const DeletorType& deletor) | 77 virtual ~MRUCacheBase() {} |
| 82 : max_size_(max_size), deletor_(deletor) { | |
| 83 } | |
| 84 | |
| 85 virtual ~MRUCacheBase() { | |
| 86 iterator i = begin(); | |
| 87 while (i != end()) | |
| 88 i = Erase(i); | |
| 89 } | |
| 90 | 78 |
| 91 size_type max_size() const { return max_size_; } | 79 size_type max_size() const { return max_size_; } |
| 92 | 80 |
| 93 // Inserts a payload item with the given key. If an existing item has | 81 // Inserts a payload item with the given key. If an existing item has |
| 94 // the same key, it is removed prior to insertion. An iterator indicating the | 82 // the same key, it is removed prior to insertion. An iterator indicating the |
| 95 // inserted item will be returned (this will always be the front of the list). | 83 // inserted item will be returned (this will always be the front of the list). |
| 96 // | 84 // |
| 97 // The payload will be copied. In the case of an OwningMRUCache, this function | 85 // The payload will be forwarded. |
| 98 // will take ownership of the pointer. | 86 template <typename Payload> |
| 99 iterator Put(const KeyType& key, const PayloadType& payload) { | 87 iterator Put(const KeyType& key, Payload&& payload) { |
| 100 // Remove any existing payload with that key. | 88 // Remove any existing payload with that key. |
| 101 typename KeyIndex::iterator index_iter = index_.find(key); | 89 typename KeyIndex::iterator index_iter = index_.find(key); |
| 102 if (index_iter != index_.end()) { | 90 if (index_iter != index_.end()) { |
| 103 // Erase the reference to it. This will call the deletor on the removed | 91 // Erase the reference to it. The index reference will be replaced in the |
| 104 // element. The index reference will be replaced in the code below. | 92 // code below. |
| 105 Erase(index_iter->second); | 93 Erase(index_iter->second); |
| 106 } else if (max_size_ != NO_AUTO_EVICT) { | 94 } else if (max_size_ != NO_AUTO_EVICT) { |
| 107 // New item is being inserted which might make it larger than the maximum | 95 // New item is being inserted which might make it larger than the maximum |
| 108 // size: kick the oldest thing out if necessary. | 96 // size: kick the oldest thing out if necessary. |
| 109 ShrinkToSize(max_size_ - 1); | 97 ShrinkToSize(max_size_ - 1); |
| 110 } | 98 } |
| 111 | 99 |
| 112 ordering_.push_front(value_type(key, payload)); | 100 ordering_.push_front(value_type(key, std::forward<Payload>(payload))); |
| 113 index_.insert(std::make_pair(key, ordering_.begin())); | 101 index_.insert(std::make_pair(key, ordering_.begin())); |
| 114 return ordering_.begin(); | 102 return ordering_.begin(); |
| 115 } | 103 } |
| 116 | 104 |
| 117 // Retrieves the contents of the given key, or end() if not found. This method | 105 // Retrieves the contents of the given key, or end() if not found. This method |
| 118 // has the side effect of moving the requested item to the front of the | 106 // has the side effect of moving the requested item to the front of the |
| 119 // recency list. | 107 // recency list. |
| 120 // | 108 // |
| 121 // TODO(brettw) We may want a const version of this function in the future. | 109 // TODO(brettw) We may want a const version of this function in the future. |
| 122 iterator Get(const KeyType& key) { | 110 iterator Get(const KeyType& key) { |
| (...skipping 20 matching lines...) Expand all Loading... | |
| 143 typename KeyIndex::const_iterator index_iter = index_.find(key); | 131 typename KeyIndex::const_iterator index_iter = index_.find(key); |
| 144 if (index_iter == index_.end()) | 132 if (index_iter == index_.end()) |
| 145 return end(); | 133 return end(); |
| 146 return index_iter->second; | 134 return index_iter->second; |
| 147 } | 135 } |
| 148 | 136 |
| 149 // Exchanges the contents of |this| by the contents of the |other|. | 137 // Exchanges the contents of |this| by the contents of the |other|. |
| 150 void Swap(MRUCacheBase& other) { | 138 void Swap(MRUCacheBase& other) { |
| 151 ordering_.swap(other.ordering_); | 139 ordering_.swap(other.ordering_); |
| 152 index_.swap(other.index_); | 140 index_.swap(other.index_); |
| 153 std::swap(deletor_, other.deletor_); | |
| 154 std::swap(max_size_, other.max_size_); | 141 std::swap(max_size_, other.max_size_); |
| 155 } | 142 } |
| 156 | 143 |
| 157 // Erases the item referenced by the given iterator. An iterator to the item | 144 // Erases the item referenced by the given iterator. An iterator to the item |
| 158 // following it will be returned. The iterator must be valid. | 145 // following it will be returned. The iterator must be valid. |
| 159 iterator Erase(iterator pos) { | 146 iterator Erase(iterator pos) { |
| 160 deletor_(pos->second); | |
| 161 index_.erase(pos->first); | 147 index_.erase(pos->first); |
| 162 return ordering_.erase(pos); | 148 return ordering_.erase(pos); |
| 163 } | 149 } |
| 164 | 150 |
| 165 // MRUCache entries are often processed in reverse order, so we add this | 151 // MRUCache entries are often processed in reverse order, so we add this |
| 166 // convenience function (not typically defined by STL containers). | 152 // convenience function (not typically defined by STL containers). |
| 167 reverse_iterator Erase(reverse_iterator pos) { | 153 reverse_iterator Erase(reverse_iterator pos) { |
| 168 // We have to actually give it the incremented iterator to delete, since | 154 // We have to actually give it the incremented iterator to delete, since |
| 169 // the forward iterator that base() returns is actually one past the item | 155 // the forward iterator that base() returns is actually one past the item |
| 170 // being iterated over. | 156 // being iterated over. |
| 171 return reverse_iterator(Erase((++pos).base())); | 157 return reverse_iterator(Erase((++pos).base())); |
| 172 } | 158 } |
| 173 | 159 |
| 174 // Shrinks the cache so it only holds |new_size| items. If |new_size| is | 160 // Shrinks the cache so it only holds |new_size| items. If |new_size| is |
| 175 // bigger or equal to the current number of items, this will do nothing. | 161 // bigger or equal to the current number of items, this will do nothing. |
| 176 void ShrinkToSize(size_type new_size) { | 162 void ShrinkToSize(size_type new_size) { |
| 177 for (size_type i = size(); i > new_size; i--) | 163 for (size_type i = size(); i > new_size; i--) |
| 178 Erase(rbegin()); | 164 Erase(rbegin()); |
| 179 } | 165 } |
| 180 | 166 |
| 181 // Deletes everything from the cache. | 167 // Deletes everything from the cache. |
| 182 void Clear() { | 168 void Clear() { |
| 183 for (typename PayloadList::iterator i(ordering_.begin()); | |
| 184 i != ordering_.end(); ++i) | |
| 185 deletor_(i->second); | |
| 186 index_.clear(); | 169 index_.clear(); |
| 187 ordering_.clear(); | 170 ordering_.clear(); |
| 188 } | 171 } |
| 189 | 172 |
| 190 // Returns the number of elements in the cache. | 173 // Returns the number of elements in the cache. |
| 191 size_type size() const { | 174 size_type size() const { |
| 192 // We don't use ordering_.size() for the return value because | 175 // We don't use ordering_.size() for the return value because |
| 193 // (as a linked list) it can be O(n). | 176 // (as a linked list) it can be O(n). |
| 194 DCHECK(index_.size() == ordering_.size()); | 177 DCHECK(index_.size() == ordering_.size()); |
| 195 return index_.size(); | 178 return index_.size(); |
| (...skipping 16 matching lines...) Expand all Loading... | |
| 212 const_reverse_iterator rend() const { return ordering_.rend(); } | 195 const_reverse_iterator rend() const { return ordering_.rend(); } |
| 213 | 196 |
| 214 bool empty() const { return ordering_.empty(); } | 197 bool empty() const { return ordering_.empty(); } |
| 215 | 198 |
| 216 private: | 199 private: |
| 217 PayloadList ordering_; | 200 PayloadList ordering_; |
| 218 KeyIndex index_; | 201 KeyIndex index_; |
| 219 | 202 |
| 220 size_type max_size_; | 203 size_type max_size_; |
| 221 | 204 |
| 222 DeletorType deletor_; | |
| 223 | |
| 224 DISALLOW_COPY_AND_ASSIGN(MRUCacheBase); | 205 DISALLOW_COPY_AND_ASSIGN(MRUCacheBase); |
| 225 }; | 206 }; |
| 226 | 207 |
| 227 // MRUCache -------------------------------------------------------------------- | 208 // MRUCache -------------------------------------------------------------------- |
| 228 | 209 |
| 229 // A functor that does nothing. Used by the MRUCache. | |
| 230 template<class PayloadType> | |
| 231 class MRUCacheNullDeletor { | |
| 232 public: | |
| 233 void operator()(const PayloadType& payload) {} | |
| 234 }; | |
| 235 | |
| 236 // A container that does not do anything to free its data. Use this when storing | 210 // A container that does not do anything to free its data. Use this when storing |
| 237 // value types (as opposed to pointers) in the list. | 211 // value types (as opposed to pointers) in the list. |
| 238 template <class KeyType, class PayloadType> | 212 template <class KeyType, class PayloadType> |
| 239 class MRUCache : public MRUCacheBase<KeyType, | 213 class MRUCache : public MRUCacheBase<KeyType, PayloadType, std::less<KeyType>> { |
| 240 PayloadType, | |
| 241 std::less<KeyType>, | |
| 242 MRUCacheNullDeletor<PayloadType>> { | |
| 243 private: | 214 private: |
| 244 typedef MRUCacheBase<KeyType, | 215 typedef MRUCacheBase<KeyType, PayloadType, std::less<KeyType>> ParentType; |
|
danakj
2016/03/07 21:27:10
can you change "typedef" to "using" when you touch
vmpstr
2016/03/07 21:45:32
Done.
| |
| 245 PayloadType, | |
| 246 std::less<KeyType>, | |
| 247 MRUCacheNullDeletor<PayloadType>> | |
| 248 ParentType; | |
| 249 | 216 |
| 250 public: | 217 public: |
| 251 // See MRUCacheBase, noting the possibility of using NO_AUTO_EVICT. | 218 // See MRUCacheBase, noting the possibility of using NO_AUTO_EVICT. |
| 252 explicit MRUCache(typename ParentType::size_type max_size) | 219 explicit MRUCache(typename ParentType::size_type max_size) |
| 253 : ParentType(max_size) { | 220 : ParentType(max_size) {} |
| 254 } | 221 virtual ~MRUCache() {} |
| 255 virtual ~MRUCache() { | |
| 256 } | |
| 257 | 222 |
| 258 private: | 223 private: |
| 259 DISALLOW_COPY_AND_ASSIGN(MRUCache); | 224 DISALLOW_COPY_AND_ASSIGN(MRUCache); |
| 260 }; | 225 }; |
| 261 | 226 |
| 262 // OwningMRUCache -------------------------------------------------------------- | |
| 263 | |
| 264 template<class PayloadType> | |
| 265 class MRUCachePointerDeletor { | |
| 266 public: | |
| 267 void operator()(const PayloadType& payload) { delete payload; } | |
| 268 }; | |
| 269 | |
| 270 // A cache that owns the payload type, which must be a non-const pointer type. | |
| 271 // The pointers will be deleted when they are removed, replaced, or when the | |
| 272 // cache is destroyed. | |
| 273 // TODO(vmpstr): This should probably go away in favor of storing scoped_ptrs. | |
| 274 template <class KeyType, class PayloadType> | |
| 275 class OwningMRUCache | |
| 276 : public MRUCacheBase<KeyType, | |
| 277 PayloadType, | |
| 278 std::less<KeyType>, | |
| 279 MRUCachePointerDeletor<PayloadType>> { | |
| 280 private: | |
| 281 typedef MRUCacheBase<KeyType, | |
| 282 PayloadType, | |
| 283 std::less<KeyType>, | |
| 284 MRUCachePointerDeletor<PayloadType>> | |
| 285 ParentType; | |
| 286 | |
| 287 public: | |
| 288 // See MRUCacheBase, noting the possibility of using NO_AUTO_EVICT. | |
| 289 explicit OwningMRUCache(typename ParentType::size_type max_size) | |
| 290 : ParentType(max_size) { | |
| 291 } | |
| 292 virtual ~OwningMRUCache() { | |
| 293 } | |
| 294 | |
| 295 private: | |
| 296 DISALLOW_COPY_AND_ASSIGN(OwningMRUCache); | |
| 297 }; | |
| 298 | |
| 299 // HashingMRUCache ------------------------------------------------------------ | 227 // HashingMRUCache ------------------------------------------------------------ |
| 300 | 228 |
| 301 template <class KeyType, class ValueType, class HashType> | 229 template <class KeyType, class ValueType, class HashType> |
| 302 struct MRUCacheHashMap { | 230 struct MRUCacheHashMap { |
| 303 typedef std::unordered_map<KeyType, ValueType, HashType> Type; | 231 typedef std::unordered_map<KeyType, ValueType, HashType> Type; |
| 304 }; | 232 }; |
| 305 | 233 |
| 306 // This class is similar to MRUCache, except that it uses std::unordered_map as | 234 // This class is similar to MRUCache, except that it uses std::unordered_map as |
| 307 // the map type instead of std::map. Note that your KeyType must be hashable to | 235 // the map type instead of std::map. Note that your KeyType must be hashable to |
| 308 // use this cache or you need to provide a hashing class. | 236 // use this cache or you need to provide a hashing class. |
| 309 template <class KeyType, class PayloadType, class HashType = std::hash<KeyType>> | 237 template <class KeyType, class PayloadType, class HashType = std::hash<KeyType>> |
| 310 class HashingMRUCache : public MRUCacheBase<KeyType, | 238 class HashingMRUCache |
| 311 PayloadType, | 239 : public MRUCacheBase<KeyType, PayloadType, HashType, MRUCacheHashMap> { |
| 312 HashType, | |
| 313 MRUCacheNullDeletor<PayloadType>, | |
| 314 MRUCacheHashMap> { | |
| 315 private: | 240 private: |
| 316 typedef MRUCacheBase<KeyType, | 241 typedef MRUCacheBase<KeyType, PayloadType, HashType, MRUCacheHashMap> |
|
danakj
2016/03/07 21:27:10
ditto
vmpstr
2016/03/07 21:45:32
Done.
| |
| 317 PayloadType, | |
| 318 HashType, | |
| 319 MRUCacheNullDeletor<PayloadType>, | |
| 320 MRUCacheHashMap> | |
| 321 ParentType; | 242 ParentType; |
| 322 | 243 |
| 323 public: | 244 public: |
| 324 // See MRUCacheBase, noting the possibility of using NO_AUTO_EVICT. | 245 // See MRUCacheBase, noting the possibility of using NO_AUTO_EVICT. |
| 325 explicit HashingMRUCache(typename ParentType::size_type max_size) | 246 explicit HashingMRUCache(typename ParentType::size_type max_size) |
| 326 : ParentType(max_size) { | 247 : ParentType(max_size) {} |
| 327 } | 248 virtual ~HashingMRUCache() {} |
| 328 virtual ~HashingMRUCache() { | |
| 329 } | |
| 330 | 249 |
| 331 private: | 250 private: |
| 332 DISALLOW_COPY_AND_ASSIGN(HashingMRUCache); | 251 DISALLOW_COPY_AND_ASSIGN(HashingMRUCache); |
| 333 }; | 252 }; |
| 334 | 253 |
| 335 } // namespace base | 254 } // namespace base |
| 336 | 255 |
| 337 #endif // BASE_CONTAINERS_MRU_CACHE_H_ | 256 #endif // BASE_CONTAINERS_MRU_CACHE_H_ |
| OLD | NEW |