]> git.proxmox.com Git - extjs.git/blame - extjs/packages/core/src/util/LruCache.js
add extjs 6.0.1 sources
[extjs.git] / extjs / packages / core / src / util / LruCache.js
CommitLineData
6527f429
DM
1/**\r
2 * @private\r
3 * @class Ext.util.LruCache\r
4 * @extend Ext.util.HashMap\r
5 * A linked {@link Ext.util.HashMap HashMap} implementation which maintains most recently accessed\r
6 * items at the end of the list, and purges the cache down to the most recently accessed {@link #maxSize} items\r
7 * upon add.\r
8 */\r
9Ext.define('Ext.util.LruCache', {\r
10 extend: 'Ext.util.HashMap',\r
11\r
12 config: {\r
13 /** \r
14 * @cfg {Number} maxSize The maximum size the cache is allowed to grow to before further additions cause\r
15 * removal of the least recently used entry.\r
16 */\r
17 maxSize: null\r
18 },\r
19\r
20 /**\r
21 * @inheritdoc\r
22 */\r
23 add: function(key, newValue) {\r
24 var me = this,\r
25 entry, last;\r
26\r
27 me.removeAtKey(key);\r
28 last = me.last;\r
29 entry = {\r
30 prev: last,\r
31 next: null,\r
32 key: key,\r
33 value: newValue\r
34 };\r
35\r
36 \r
37 if (last) {\r
38 // If the list is not empty, update the last entry\r
39 last.next = entry;\r
40 } else {\r
41 // List is empty\r
42 me.first = entry;\r
43 }\r
44 me.last = entry;\r
45 me.callParent([key, entry]);\r
46 me.prune();\r
47 return newValue;\r
48 },\r
49\r
50 /**\r
51 * @private\r
52 */\r
53 insertBefore: function(key, newValue, sibling) {\r
54 var me = this,\r
55 existingKey,\r
56 entry;\r
57\r
58 // NOT an assignment.\r
59 // If there is a following sibling\r
60 if (sibling = this.map[this.findKey(sibling)]) {\r
61 existingKey = me.findKey(newValue);\r
62\r
63 // "new" value is in the list.\r
64 if (existingKey) {\r
65 me.unlinkEntry(entry = me.map[existingKey]);\r
66 }\r
67 // Genuinely new: create an entry for it.\r
68 else {\r
69 entry = {\r
70 prev: sibling.prev,\r
71 next: sibling,\r
72 key: key,\r
73 value: newValue\r
74 };\r
75 }\r
76\r
77 if (sibling.prev) {\r
78 entry.prev.next = entry;\r
79 } else {\r
80 me.first = entry;\r
81 }\r
82 entry.next = sibling;\r
83 sibling.prev = entry;\r
84 me.prune();\r
85 return newValue;\r
86 }\r
87 // No following sibling, it's just an add.\r
88 else {\r
89 return me.add(key, newValue);\r
90 }\r
91 },\r
92\r
93 /**\r
94 * @inheritdoc\r
95 */\r
96 get: function(key) {\r
97 var entry = this.map[key];\r
98 if (entry) {\r
99\r
100 // If it's not the end, move to end of list on get\r
101 if (entry.next) {\r
102 this.moveToEnd(entry);\r
103 }\r
104 return entry.value;\r
105 }\r
106 },\r
107\r
108 /**\r
109 * @private\r
110 */\r
111 removeAtKey: function(key) {\r
112 this.unlinkEntry(this.map[key]);\r
113 return this.callParent(arguments);\r
114 },\r
115\r
116 /**\r
117 * @inheritdoc\r
118 */\r
119 clear: function(/* private */ initial) {\r
120 this.first = this.last = null;\r
121 return this.callParent([initial]);\r
122 },\r
123\r
124 /**\r
125 * @private\r
126 */\r
127 unlinkEntry: function(entry) {\r
128 // Stitch the list back up.\r
129 if (entry) {\r
130 if (entry.next) {\r
131 entry.next.prev = entry.prev;\r
132 } else {\r
133 this.last = entry.prev;\r
134 }\r
135 if (entry.prev) {\r
136 entry.prev.next = entry.next;\r
137 } else {\r
138 this.first = entry.next;\r
139 }\r
140 entry.prev = entry.next = null;\r
141 }\r
142 },\r
143\r
144 /**\r
145 * @private\r
146 */\r
147 moveToEnd: function(entry) {\r
148 this.unlinkEntry(entry);\r
149\r
150 // NOT an assignment.\r
151 // If the list is not empty, update the last entry\r
152 if (entry.prev = this.last) {\r
153 this.last.next = entry;\r
154 }\r
155 // List is empty\r
156 else {\r
157 this.first = entry;\r
158 }\r
159 this.last = entry;\r
160 },\r
161\r
162 /**\r
163 * @private\r
164 */\r
165 getArray: function(isKey) {\r
166 var arr = [],\r
167 entry = this.first;\r
168\r
169 while (entry) {\r
170 arr.push(isKey ? entry.key: entry.value);\r
171 entry = entry.next;\r
172 }\r
173 return arr;\r
174 },\r
175\r
176 /**\r
177 * Executes the specified function once for each item in the cache.\r
178 * Returning false from the function will cease iteration.\r
179 *\r
180 * By default, iteration is from least recently used to most recent.\r
181 *\r
182 * The paramaters passed to the function are:\r
183 * <div class="mdetail-params"><ul>\r
184 * <li><b>key</b> : String<p class="sub-desc">The key of the item</p></li>\r
185 * <li><b>value</b> : Number<p class="sub-desc">The value of the item</p></li>\r
186 * <li><b>length</b> : Number<p class="sub-desc">The total number of items in the hash</p></li>\r
187 * </ul></div>\r
188 * @param {Function} fn The function to execute.\r
189 * @param {Object} scope The scope (<code>this</code> reference) to execute in. Defaults to this LruCache.\r
190 * @param {Boolean} [reverse=false] Pass <code>true</code> to iterate the list in reverse (most recent first) order.\r
191 * @return {Ext.util.LruCache} this\r
192 */\r
193 each: function(fn, scope, reverse) {\r
194 var me = this,\r
195 entry = reverse ? me.last : me.first,\r
196 length = me.length;\r
197\r
198 scope = scope || me;\r
199 while (entry) {\r
200 if (fn.call(scope, entry.key, entry.value, length) === false) {\r
201 break;\r
202 }\r
203 entry = reverse ? entry.prev : entry.next;\r
204 }\r
205 return me;\r
206 },\r
207\r
208 /**\r
209 * @private\r
210 */\r
211 findKey: function(value) {\r
212 var key,\r
213 map = this.map;\r
214\r
215 for (key in map) {\r
216 // Attention. Differs from subclass in that this compares the value property\r
217 // of the entry.\r
218 if (map.hasOwnProperty(key) && map[key].value === value) {\r
219 return key;\r
220 }\r
221 }\r
222 return undefined;\r
223 },\r
224\r
225 /**\r
226 * Performs a shallow copy on this haLruCachesh.\r
227 * @return {Ext.util.HashMap} The new hash object.\r
228 */\r
229 clone: function() {\r
230 var newCache = new this.self(this.initialConfig),\r
231 map = this.map,\r
232 key;\r
233\r
234 newCache.suspendEvents();\r
235 for (key in map) {\r
236 if (map.hasOwnProperty(key)) {\r
237 newCache.add(key, map[key].value);\r
238 }\r
239 }\r
240 newCache.resumeEvents();\r
241 return newCache;\r
242 },\r
243\r
244 /**\r
245 * Purge the least recently used entries if the maxSize has been exceeded.\r
246 */\r
247 prune: function() {\r
248 var me = this,\r
249 max = me.getMaxSize(),\r
250 purgeCount = max ? (me.length - max) : 0;\r
251\r
252 if (purgeCount > 0) {\r
253 for (; me.first && purgeCount; purgeCount--) {\r
254 me.removeAtKey(me.first.key);\r
255 }\r
256 }\r
257 },\r
258\r
259 destroy: function() {\r
260 this.first = this.last = null;\r
261 this.callParent(); \r
262 }\r
263\r
264 /**\r
265 * @method containsKey\r
266 * @private\r
267 */\r
268 /**\r
269 * @method contains\r
270 * @private\r
271 */\r
272 /**\r
273 * @method getKeys\r
274 * @private\r
275 */\r
276 /**\r
277 * @method getValues\r
278 * @private\r
279 */\r
280});