/** * @private * @class Ext.util.LruCache * @extend Ext.util.HashMap * A linked {@link Ext.util.HashMap HashMap} implementation which maintains most recently accessed * items at the end of the list, and purges the cache down to the most recently accessed * {@link #maxSize} items upon add. */Ext.define('Ext.util.LruCache', { extend: 'Ext.util.HashMap', config: { /** * @cfg {Number} maxSize * The maximum size the cache is allowed to grow to before further additions * cause removal of the least recently used entry. */ maxSize: null }, /** * @method add * @inheritdoc */ add: function(key, newValue) { var me = this, entry, last; me.removeAtKey(key); last = me.last; entry = { prev: last, next: null, key: key, value: newValue }; if (last) { // If the list is not empty, update the last entry last.next = entry; } else { // List is empty me.first = entry; } me.last = entry; me.callParent([key, entry]); me.prune(); return newValue; }, /** * @private */ insertBefore: function(key, newValue, sibling) { var me = this, existingKey, entry; // NOT an assignment. // If there is a following sibling // eslint-disable-next-line no-cond-assign if (sibling = this.map[this.findKey(sibling)]) { existingKey = me.findKey(newValue); // "new" value is in the list. if (existingKey) { me.unlinkEntry(entry = me.map[existingKey]); } // Genuinely new: create an entry for it. else { entry = { prev: sibling.prev, next: sibling, key: key, value: newValue }; } if (sibling.prev) { entry.prev.next = entry; } else { me.first = entry; } entry.next = sibling; sibling.prev = entry; me.prune(); return newValue; } // No following sibling, it's just an add. else { return me.add(key, newValue); } }, /** * @method get * @inheritdoc */ get: function(key) { var entry = this.map[key]; if (entry) { // If it's not the end, move to end of list on get if (entry.next) { this.moveToEnd(entry); } return entry.value; } }, /** * @private */ removeAtKey: function(key) { this.unlinkEntry(this.map[key]); return this.callParent(arguments); }, /** * @method clear * @inheritdoc * @param initial (private) */ clear: function(initial) { this.first = this.last = null; return this.callParent([initial]); }, /** * @private */ unlinkEntry: function(entry) { // Stitch the list back up. if (entry) { if (entry.next) { entry.next.prev = entry.prev; } else { this.last = entry.prev; } if (entry.prev) { entry.prev.next = entry.next; } else { this.first = entry.next; } entry.prev = entry.next = null; } }, /** * @private */ moveToEnd: function(entry) { this.unlinkEntry(entry); // NOT an assignment. // If the list is not empty, update the last entry // eslint-disable-next-line no-cond-assign if (entry.prev = this.last) { this.last.next = entry; } // List is empty else { this.first = entry; } this.last = entry; }, /** * @private */ getArray: function(isKey) { var arr = [], entry = this.first; while (entry) { arr.push(isKey ? entry.key : entry.value); entry = entry.next; } return arr; }, /** * Executes the specified function once for each item in the cache. * Returning false from the function will cease iteration. * * By default, iteration is from least recently used to most recent. * * The paramaters passed to the function are: * <div class="mdetail-params"><ul> * <li><b>key</b> : String<p class="sub-desc">The key of the item</p></li> * <li><b>value</b> : Number<p class="sub-desc">The value of the item</p></li> * <li><b>length</b> : Number<p class="sub-desc">The total number of items in the hash</p></li> * </ul></div> * @param {Function} fn The function to execute. * @param {Object} scope The scope (<code>this</code> reference) to execute in. Defaults * to this LruCache. * @param {Boolean} [reverse=false] Pass <code>true</code> to iterate the list in reverse * (most recent first) order. * @return {Ext.util.LruCache} this */ each: function(fn, scope, reverse) { var me = this, entry = reverse ? me.last : me.first, length = me.length; scope = scope || me; while (entry) { if (fn.call(scope, entry.key, entry.value, length) === false) { break; } entry = reverse ? entry.prev : entry.next; } return me; }, /** * @private */ findKey: function(value) { var key, map = this.map; for (key in map) { // Attention. Differs from subclass in that this compares the value property // of the entry. if (map.hasOwnProperty(key) && map[key].value === value) { return key; } } return undefined; }, /** * Performs a shallow copy on this haLruCachesh. * @return {Ext.util.HashMap} The new hash object. */ clone: function() { var newCache = new this.self(this.initialConfig), map = this.map, key; newCache.suspendEvents(); for (key in map) { if (map.hasOwnProperty(key)) { newCache.add(key, map[key].value); } } newCache.resumeEvents(); return newCache; }, /** * Purge the least recently used entries if the maxSize has been exceeded. */ prune: function() { var me = this, max = me.getMaxSize(), purgeCount = max ? (me.length - max) : 0; if (purgeCount > 0) { for (; me.first && purgeCount; purgeCount--) { me.removeAtKey(me.first.key); } } } /** * @method containsKey * @private */ /** * @method contains * @private */ /** * @method getKeys * @private */ /** * @method getValues * @private */});