whatsappicloudtweetdeckhipchattelegramhangoutsslackgmailskypefacebook-workplaceoutlookemailmicrosoft-teamsdiscordmessengercustom-servicesmacoslinuxwindowsinbox
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.
236 lines
7.3 KiB
236 lines
7.3 KiB
9 years ago
|
/**
|
||
|
* This class is used to manage simple, LRU caches. It provides an absolutely minimal
|
||
|
* container interface. It is created like this:
|
||
|
*
|
||
|
* this.itemCache = new Ext.util.Cache({
|
||
|
* miss: function (key) {
|
||
|
* return new CacheItem(key);
|
||
|
* }
|
||
|
* });
|
||
|
*
|
||
|
* The `{@link #miss}` abstract method must be implemented by either a derived class or
|
||
|
* at the instance level as shown above.
|
||
|
*
|
||
|
* Once the cache exists and it can handle cache misses, the cache is used like so:
|
||
|
*
|
||
|
* var item = this.itemCache.get(key);
|
||
|
*
|
||
|
* The `key` is some value that uniquely identifies the cached item.
|
||
|
*
|
||
|
* In some cases, creating the cache item may require more than just the lookup key. In
|
||
|
* that case, any extra arguments passed to `get` will be passed to `miss`.
|
||
|
*
|
||
|
* this.otherCache = new Ext.util.Cache({
|
||
|
* miss: function (key, extra) {
|
||
|
* return new CacheItem(key, extra);
|
||
|
* }
|
||
|
* });
|
||
|
*
|
||
|
* var item = this.otherCache.get(key, extra);
|
||
|
*
|
||
|
* To process items as they are removed, you can provide an `{@link #evict}` method. The
|
||
|
* stock method is `Ext.emptyFn` and so does nothing.
|
||
|
*
|
||
|
* For example:
|
||
|
*
|
||
|
* this.itemCache = new Ext.util.Cache({
|
||
|
* miss: function (key) {
|
||
|
* return new CacheItem(key);
|
||
|
* },
|
||
|
*
|
||
|
* evict: function (key, cacheItem) {
|
||
|
* cacheItem.destroy();
|
||
|
* }
|
||
|
* });
|
||
|
*
|
||
|
* @class Ext.util.Cache
|
||
|
* @private
|
||
|
* @since 5.1.0
|
||
|
*/
|
||
|
(function (Cache, prototype) {
|
||
|
// @define Ext.util.Cache
|
||
|
|
||
|
// NOTE: We have to implement this class old-school because it is used by the
|
||
|
// platformConfig class processor (so Ext.define is not yet ready for action).
|
||
|
(Ext.util || (Ext.util = {})).Cache = Cache = function (config) {
|
||
|
var me = this,
|
||
|
head;
|
||
|
|
||
|
if (config) {
|
||
|
Ext.apply(me, config);
|
||
|
}
|
||
|
|
||
|
// Give all entries the same object shape.
|
||
|
me.head = head = {
|
||
|
//<debug>
|
||
|
id: (me.seed = 0),
|
||
|
//</debug>
|
||
|
key: null,
|
||
|
value: null
|
||
|
};
|
||
|
|
||
|
me.map = {};
|
||
|
|
||
|
head.next = head.prev = head;
|
||
|
};
|
||
|
|
||
|
Cache.prototype = prototype = {
|
||
|
/**
|
||
|
* @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: 100,
|
||
|
|
||
|
/**
|
||
|
* @property {Number} count
|
||
|
* The number of items in this cache.
|
||
|
* @readonly
|
||
|
*/
|
||
|
count: 0,
|
||
|
|
||
|
/**
|
||
|
* This method is called by `{@link #get}` when the key is not found in the cache.
|
||
|
* The implementation of this method should create the (expensive) value and return
|
||
|
* it. Whatever arguments were passed to `{@link #get}` will be passed on to this
|
||
|
* method.
|
||
|
*
|
||
|
* @param {String} key The cache lookup key for the item.
|
||
|
* @param {Object...} args Any other arguments originally passed to `{@link #get}`.
|
||
|
* @method miss
|
||
|
* @abstract
|
||
|
* @protected
|
||
|
*/
|
||
|
|
||
|
/**
|
||
|
* Removes all items from this cache.
|
||
|
*/
|
||
|
clear: function () {
|
||
|
var me = this,
|
||
|
head = me.head,
|
||
|
entry = head.next;
|
||
|
|
||
|
head.next = head.prev = head;
|
||
|
|
||
|
if (!me.evict.$nullFn) {
|
||
|
for ( ; entry !== head; entry = entry.next) {
|
||
|
me.evict(entry.key, entry.value);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
me.count = 0;
|
||
|
},
|
||
|
|
||
|
/**
|
||
|
* Calls the given function `fn` for each item in the cache. The items will be passed
|
||
|
* to `fn` from most-to-least recently used.
|
||
|
* @param {Function} fn The function to call for each cache item.
|
||
|
* @param {String} fn.key The cache key for the item.
|
||
|
* @param {Object} fn.value The value in the cache for the item.
|
||
|
* @param {Object} [scope] The `this` pointer to use for `fn`.
|
||
|
*/
|
||
|
each: function (fn, scope) {
|
||
|
scope = scope || this;
|
||
|
|
||
|
for (var head = this.head, ent = head.next; ent !== head; ent = ent.next) {
|
||
|
if (fn.call(scope, ent.key, ent.value)) {
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
},
|
||
|
|
||
|
/**
|
||
|
* Finds an item in this cache and returns its value. If the item is present, it is
|
||
|
* shuffled into the MRU (most-recently-used) position as necessary. If the item is
|
||
|
* missing, the `{@link #miss}` method is called to create the item.
|
||
|
*
|
||
|
* @param {String} key The cache key of the item.
|
||
|
* @param {Object...} args Arguments for the `miss` method should it be needed.
|
||
|
* @return {Object} The cached object.
|
||
|
*/
|
||
|
get: function (key) {
|
||
|
var me = this,
|
||
|
head = me.head,
|
||
|
map = me.map,
|
||
|
entry = map[key];
|
||
|
|
||
|
if (entry) {
|
||
|
if (entry.prev !== head) {
|
||
|
// The entry is not at the front, so remove it and insert it at the front
|
||
|
// (to make it the MRU - Most Recently Used).
|
||
|
me.unlinkEntry(entry);
|
||
|
me.linkEntry(entry);
|
||
|
}
|
||
|
} else {
|
||
|
map[key] = entry = {
|
||
|
//<debug>
|
||
|
id: ++me.seed,
|
||
|
//</debug>
|
||
|
key: key,
|
||
|
value: me.miss.apply(me, arguments)
|
||
|
};
|
||
|
|
||
|
me.linkEntry(entry);
|
||
|
++me.count;
|
||
|
|
||
|
while (me.count > me.maxSize) {
|
||
|
me.unlinkEntry(head.prev, true);
|
||
|
--me.count;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return entry.value;
|
||
|
},
|
||
|
|
||
|
//-------------------------------------------------------------------------
|
||
|
// Internals
|
||
|
|
||
|
/**
|
||
|
* This method is called internally from `{@link #get}` when the cache is full and
|
||
|
* the least-recently-used (LRU) item has been removed.
|
||
|
*
|
||
|
* @param {String} key The cache lookup key for the item being removed.
|
||
|
* @param {Object} value The cache value (returned by `{@link #miss}`) for the item
|
||
|
* being removed.
|
||
|
* @method evict
|
||
|
* @template
|
||
|
* @protected
|
||
|
*/
|
||
|
evict: Ext.emptyFn,
|
||
|
|
||
|
/**
|
||
|
* Inserts the given entry at the front (MRU) end of the entry list.
|
||
|
* @param {Object} entry The cache item entry.
|
||
|
* @private
|
||
|
*/
|
||
|
linkEntry: function (entry) {
|
||
|
var head = this.head,
|
||
|
first = head.next;
|
||
|
|
||
|
entry.next = first;
|
||
|
entry.prev = head;
|
||
|
head.next = entry;
|
||
|
first.prev = entry;
|
||
|
},
|
||
|
|
||
|
/**
|
||
|
* Removes the given entry from the entry list.
|
||
|
* @param {Object} entry The cache item entry.
|
||
|
* @param {Boolean} evicted Pass `true` if `{@link #evict}` should be called.
|
||
|
* @private
|
||
|
*/
|
||
|
unlinkEntry: function (entry, evicted) {
|
||
|
var next = entry.next,
|
||
|
prev = entry.prev;
|
||
|
|
||
|
prev.next = next;
|
||
|
next.prev = prev;
|
||
|
|
||
|
if (evicted) {
|
||
|
this.evict(entry.key, entry.value);
|
||
|
}
|
||
|
}
|
||
|
};
|
||
|
|
||
|
prototype.destroy = prototype.clear;
|
||
|
}());
|