OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 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 #ifndef NET_BASE_EXPIRING_CACHE_H_ | 5 #ifndef NET_BASE_EXPIRING_CACHE_H_ |
6 #define NET_BASE_EXPIRING_CACHE_H_ | 6 #define NET_BASE_EXPIRING_CACHE_H_ |
7 | 7 |
8 #include <map> | 8 #include <map> |
9 #include <utility> | 9 #include <utility> |
10 | 10 |
11 #include "base/basictypes.h" | 11 #include "base/basictypes.h" |
12 #include "base/gtest_prod_util.h" | 12 #include "base/gtest_prod_util.h" |
13 #include "base/time/time.h" | 13 #include "base/time/time.h" |
14 | 14 |
15 namespace net { | 15 namespace net { |
16 | 16 |
17 template <typename KeyType, | 17 template <typename KeyType, typename ValueType, typename ExpirationType> |
18 typename ValueType, | |
19 typename ExpirationType> | |
20 class NoopEvictionHandler { | 18 class NoopEvictionHandler { |
21 public: | 19 public: |
22 void Handle(const KeyType& key, | 20 void Handle(const KeyType& key, |
23 const ValueType& value, | 21 const ValueType& value, |
24 const ExpirationType& expiration, | 22 const ExpirationType& expiration, |
25 const ExpirationType& now, | 23 const ExpirationType& now, |
26 bool onGet) const { | 24 bool onGet) const {} |
27 } | |
28 }; | 25 }; |
29 | 26 |
30 // Cache implementation where all entries have an explicit expiration policy. As | 27 // Cache implementation where all entries have an explicit expiration policy. As |
31 // new items are added, expired items will be removed first. | 28 // new items are added, expired items will be removed first. |
32 // The template types have the following requirements: | 29 // The template types have the following requirements: |
33 // KeyType must be LessThanComparable, Assignable, and CopyConstructible. | 30 // KeyType must be LessThanComparable, Assignable, and CopyConstructible. |
34 // ValueType must be CopyConstructible and Assignable. | 31 // ValueType must be CopyConstructible and Assignable. |
35 // ExpirationType must be CopyConstructible and Assignable. | 32 // ExpirationType must be CopyConstructible and Assignable. |
36 // ExpirationCompare is a function class that takes two arguments of the | 33 // ExpirationCompare is a function class that takes two arguments of the |
37 // type ExpirationType and returns a bool. If |comp| is an instance of | 34 // type ExpirationType and returns a bool. If |comp| is an instance of |
(...skipping 23 matching lines...) Expand all Loading... |
61 // }; | 58 // }; |
62 // ExpiringCache<std::string, std::string, ComplexExpiration, | 59 // ExpiringCache<std::string, std::string, ComplexExpiration, |
63 // ComplexExpirationFunctor> cache(15); | 60 // ComplexExpirationFunctor> cache(15); |
64 // // Add a value that expires once the 'sprocket' has 'cog'-ified. | 61 // // Add a value that expires once the 'sprocket' has 'cog'-ified. |
65 // cache.Put("key1", "value1", ComplexExpiration("sprocket"), | 62 // cache.Put("key1", "value1", ComplexExpiration("sprocket"), |
66 // ComplexExpiration("cog")); | 63 // ComplexExpiration("cog")); |
67 template <typename KeyType, | 64 template <typename KeyType, |
68 typename ValueType, | 65 typename ValueType, |
69 typename ExpirationType, | 66 typename ExpirationType, |
70 typename ExpirationCompare, | 67 typename ExpirationCompare, |
71 typename EvictionHandler = NoopEvictionHandler<KeyType, | 68 typename EvictionHandler = |
72 ValueType, | 69 NoopEvictionHandler<KeyType, ValueType, ExpirationType> > |
73 ExpirationType> > | |
74 class ExpiringCache { | 70 class ExpiringCache { |
75 private: | 71 private: |
76 // Intentionally violate the C++ Style Guide so that EntryMap is known to be | 72 // Intentionally violate the C++ Style Guide so that EntryMap is known to be |
77 // a dependent type. Without this, Clang's two-phase lookup complains when | 73 // a dependent type. Without this, Clang's two-phase lookup complains when |
78 // using EntryMap::const_iterator, while GCC and MSVC happily resolve the | 74 // using EntryMap::const_iterator, while GCC and MSVC happily resolve the |
79 // typename. | 75 // typename. |
80 | 76 |
81 // Tuple to represent the value and when it expires. | 77 // Tuple to represent the value and when it expires. |
82 typedef std::pair<ValueType, ExpirationType> Entry; | 78 typedef std::pair<ValueType, ExpirationType> Entry; |
83 typedef std::map<KeyType, Entry> EntryMap; | 79 typedef std::map<KeyType, Entry> EntryMap; |
84 | 80 |
85 public: | 81 public: |
86 typedef KeyType key_type; | 82 typedef KeyType key_type; |
87 typedef ValueType value_type; | 83 typedef ValueType value_type; |
88 typedef ExpirationType expiration_type; | 84 typedef ExpirationType expiration_type; |
89 | 85 |
90 // This class provides a read-only iterator over items in the ExpiringCache | 86 // This class provides a read-only iterator over items in the ExpiringCache |
91 class Iterator { | 87 class Iterator { |
92 public: | 88 public: |
93 explicit Iterator(const ExpiringCache& cache) | 89 explicit Iterator(const ExpiringCache& cache) |
94 : cache_(cache), | 90 : cache_(cache), it_(cache_.entries_.begin()) {} |
95 it_(cache_.entries_.begin()) { | |
96 } | |
97 ~Iterator() {} | 91 ~Iterator() {} |
98 | 92 |
99 bool HasNext() const { return it_ != cache_.entries_.end(); } | 93 bool HasNext() const { return it_ != cache_.entries_.end(); } |
100 void Advance() { ++it_; } | 94 void Advance() { ++it_; } |
101 | 95 |
102 const KeyType& key() const { return it_->first; } | 96 const KeyType& key() const { return it_->first; } |
103 const ValueType& value() const { return it_->second.first; } | 97 const ValueType& value() const { return it_->second.first; } |
104 const ExpirationType& expiration() const { return it_->second.second; } | 98 const ExpirationType& expiration() const { return it_->second.second; } |
105 | 99 |
106 private: | 100 private: |
107 const ExpiringCache& cache_; | 101 const ExpiringCache& cache_; |
108 | 102 |
109 // Use a second layer of type indirection, as both EntryMap and | 103 // Use a second layer of type indirection, as both EntryMap and |
110 // EntryMap::const_iterator are dependent types. | 104 // EntryMap::const_iterator are dependent types. |
111 typedef typename ExpiringCache::EntryMap EntryMap; | 105 typedef typename ExpiringCache::EntryMap EntryMap; |
112 typename EntryMap::const_iterator it_; | 106 typename EntryMap::const_iterator it_; |
113 }; | 107 }; |
114 | 108 |
115 | |
116 // Constructs an ExpiringCache that stores up to |max_entries|. | 109 // Constructs an ExpiringCache that stores up to |max_entries|. |
117 explicit ExpiringCache(size_t max_entries) : max_entries_(max_entries) {} | 110 explicit ExpiringCache(size_t max_entries) : max_entries_(max_entries) {} |
118 ~ExpiringCache() {} | 111 ~ExpiringCache() {} |
119 | 112 |
120 // Returns the value matching |key|, which must be valid at the time |now|. | 113 // Returns the value matching |key|, which must be valid at the time |now|. |
121 // Returns NULL if the item is not found or has expired. If the item has | 114 // Returns NULL if the item is not found or has expired. If the item has |
122 // expired, it is immediately removed from the cache. | 115 // expired, it is immediately removed from the cache. |
123 // Note: The returned pointer remains owned by the ExpiringCache and is | 116 // Note: The returned pointer remains owned by the ExpiringCache and is |
124 // invalidated by a call to a non-const method. | 117 // invalidated by a call to a non-const method. |
125 const ValueType* Get(const KeyType& key, const ExpirationType& now) { | 118 const ValueType* Get(const KeyType& key, const ExpirationType& now) { |
(...skipping 11 matching lines...) Expand all Loading... |
137 } | 130 } |
138 | 131 |
139 // Updates or replaces the value associated with |key|. | 132 // Updates or replaces the value associated with |key|. |
140 void Put(const KeyType& key, | 133 void Put(const KeyType& key, |
141 const ValueType& value, | 134 const ValueType& value, |
142 const ExpirationType& now, | 135 const ExpirationType& now, |
143 const ExpirationType& expiration) { | 136 const ExpirationType& expiration) { |
144 typename EntryMap::iterator it = entries_.find(key); | 137 typename EntryMap::iterator it = entries_.find(key); |
145 if (it == entries_.end()) { | 138 if (it == entries_.end()) { |
146 // Compact the cache if it grew beyond the limit. | 139 // Compact the cache if it grew beyond the limit. |
147 if (entries_.size() == max_entries_ ) | 140 if (entries_.size() == max_entries_) |
148 Compact(now); | 141 Compact(now); |
149 | 142 |
150 // No existing entry. Creating a new one. | 143 // No existing entry. Creating a new one. |
151 entries_.insert(std::make_pair(key, Entry(value, expiration))); | 144 entries_.insert(std::make_pair(key, Entry(value, expiration))); |
152 } else { | 145 } else { |
153 // Update an existing cache entry. | 146 // Update an existing cache entry. |
154 it->second.first = value; | 147 it->second.first = value; |
155 it->second.second = expiration; | 148 it->second.second = expiration; |
156 } | 149 } |
157 } | 150 } |
158 | 151 |
159 // Empties the cache. | 152 // Empties the cache. |
160 void Clear() { | 153 void Clear() { entries_.clear(); } |
161 entries_.clear(); | |
162 } | |
163 | 154 |
164 // Returns the number of entries in the cache. | 155 // Returns the number of entries in the cache. |
165 size_t size() const { return entries_.size(); } | 156 size_t size() const { return entries_.size(); } |
166 | 157 |
167 // Returns the maximum number of entries in the cache. | 158 // Returns the maximum number of entries in the cache. |
168 size_t max_entries() const { return max_entries_; } | 159 size_t max_entries() const { return max_entries_; } |
169 | 160 |
170 bool empty() const { return entries_.empty(); } | 161 bool empty() const { return entries_.empty(); } |
171 | 162 |
172 private: | 163 private: |
173 FRIEND_TEST_ALL_PREFIXES(ExpiringCacheTest, Compact); | 164 FRIEND_TEST_ALL_PREFIXES(ExpiringCacheTest, Compact); |
174 FRIEND_TEST_ALL_PREFIXES(ExpiringCacheTest, CustomFunctor); | 165 FRIEND_TEST_ALL_PREFIXES(ExpiringCacheTest, CustomFunctor); |
175 | 166 |
176 // Prunes entries from the cache to bring it below |max_entries()|. | 167 // Prunes entries from the cache to bring it below |max_entries()|. |
177 void Compact(const ExpirationType& now) { | 168 void Compact(const ExpirationType& now) { |
178 // Clear out expired entries. | 169 // Clear out expired entries. |
179 typename EntryMap::iterator it; | 170 typename EntryMap::iterator it; |
180 for (it = entries_.begin(); it != entries_.end(); ) { | 171 for (it = entries_.begin(); it != entries_.end();) { |
181 if (!expiration_comp_(now, it->second.second)) { | 172 if (!expiration_comp_(now, it->second.second)) { |
182 Evict(it++, now, false); | 173 Evict(it++, now, false); |
183 } else { | 174 } else { |
184 ++it; | 175 ++it; |
185 } | 176 } |
186 } | 177 } |
187 | 178 |
188 if (entries_.size() < max_entries_) | 179 if (entries_.size() < max_entries_) |
189 return; | 180 return; |
190 | 181 |
191 // If the cache is still too full, start deleting items 'randomly'. | 182 // If the cache is still too full, start deleting items 'randomly'. |
192 for (it = entries_.begin(); | 183 for (it = entries_.begin(); |
193 it != entries_.end() && entries_.size() >= max_entries_;) { | 184 it != entries_.end() && entries_.size() >= max_entries_;) { |
194 Evict(it++, now, false); | 185 Evict(it++, now, false); |
195 } | 186 } |
196 } | 187 } |
197 | 188 |
198 void Evict(typename EntryMap::iterator it, | 189 void Evict(typename EntryMap::iterator it, |
199 const ExpirationType& now, | 190 const ExpirationType& now, |
200 bool on_get) { | 191 bool on_get) { |
201 eviction_handler_.Handle(it->first, it->second.first, it->second.second, | 192 eviction_handler_.Handle( |
202 now, on_get); | 193 it->first, it->second.first, it->second.second, now, on_get); |
203 entries_.erase(it); | 194 entries_.erase(it); |
204 } | 195 } |
205 | 196 |
206 // Bound on total size of the cache. | 197 // Bound on total size of the cache. |
207 size_t max_entries_; | 198 size_t max_entries_; |
208 | 199 |
209 EntryMap entries_; | 200 EntryMap entries_; |
210 ExpirationCompare expiration_comp_; | 201 ExpirationCompare expiration_comp_; |
211 EvictionHandler eviction_handler_; | 202 EvictionHandler eviction_handler_; |
212 | 203 |
213 DISALLOW_COPY_AND_ASSIGN(ExpiringCache); | 204 DISALLOW_COPY_AND_ASSIGN(ExpiringCache); |
214 }; | 205 }; |
215 | 206 |
216 } // namespace net | 207 } // namespace net |
217 | 208 |
218 #endif // NET_BASE_EXPIRING_CACHE_H_ | 209 #endif // NET_BASE_EXPIRING_CACHE_H_ |
OLD | NEW |