linuxwindowsinboxwhatsappicloudtweetdeckhipchattelegramhangoutsslackgmailskypefacebook-workplaceoutlookemailmicrosoft-teamsdiscordmessengercustom-servicesmacos
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
269 lines
6.8 KiB
269 lines
6.8 KiB
/** |
|
* @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 |
|
}, |
|
|
|
/* |
|
* @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 |
|
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); |
|
} |
|
}, |
|
|
|
/* |
|
* @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); |
|
}, |
|
|
|
/* |
|
* @inheritdoc |
|
*/ |
|
clear: function(/* private */ initial) { |
|
this.first = this.last = null; |
|
return this.callParent(arguments); |
|
}, |
|
|
|
// private. Only used by internal methods. |
|
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. Only used by internal methods. |
|
moveToEnd: function(entry) { |
|
this.unlinkEntry(entry); |
|
|
|
// NOT an assignment. |
|
// If the list is not empty, update the last entry |
|
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 |
|
*/ |
|
}); |