cytoscape
Version:
Graph theory (a.k.a. network) library for analysis and visualisation
179 lines (132 loc) • 3.73 kB
JavaScript
import Map from '../../../map';
import Set from'../../../set';
import * as util from '../../../util';
// Allows lookups for (ele, lvl) => cache.
// Uses keys so elements may share the same cache.
class ElementTextureCacheLookup {
constructor(getKey, doesEleInvalidateKey = util.falsify){
this.idsByKey = new Map();
this.keyForId = new Map();
this.cachesByLvl = new Map();
this.lvls = [];
this.getKey = getKey;
this.doesEleInvalidateKey = doesEleInvalidateKey;
}
getIdsFor(key){
if( key == null ){
util.error(`Can not get id list for null key`);
}
let { idsByKey } = this;
let ids = this.idsByKey.get(key);
if( !ids ){
ids = new Set();
idsByKey.set(key, ids);
}
return ids;
}
addIdForKey(key, id){
if( key != null ){
this.getIdsFor(key).add(id);
}
}
deleteIdForKey(key, id){
if( key != null ){
this.getIdsFor(key).delete(id);
}
}
getNumberOfIdsForKey(key){
if( key == null ){
return 0;
} else {
return this.getIdsFor(key).size;
}
}
updateKeyMappingFor(ele){
let id = ele.id();
let prevKey = this.keyForId.get(id);
let currKey = this.getKey(ele);
this.deleteIdForKey(prevKey, id);
this.addIdForKey(currKey, id);
this.keyForId.set(id, currKey);
}
deleteKeyMappingFor(ele){
let id = ele.id();
let prevKey = this.keyForId.get(id);
this.deleteIdForKey(prevKey, id);
this.keyForId.delete(id);
}
keyHasChangedFor(ele){
let id = ele.id();
let prevKey = this.keyForId.get(id);
let newKey = this.getKey(ele);
return prevKey !== newKey;
}
isInvalid(ele){
return this.keyHasChangedFor(ele) || this.doesEleInvalidateKey(ele);
}
getCachesAt(lvl){
let { cachesByLvl, lvls } = this;
let caches = cachesByLvl.get(lvl);
if( !caches ){
caches = new Map();
cachesByLvl.set(lvl, caches);
lvls.push(lvl);
}
return caches;
}
getCache(key, lvl){
return this.getCachesAt(lvl).get(key);
}
get(ele, lvl){
let key = this.getKey(ele);
let cache = this.getCache(key, lvl);
// getting for an element may need to add to the id list b/c eles can share keys
if( cache != null ){
this.updateKeyMappingFor(ele);
}
return cache;
}
getForCachedKey(ele, lvl){
let key = this.keyForId.get(ele.id()); // n.b. use cached key, not newly computed key
let cache = this.getCache(key, lvl);
return cache;
}
hasCache(key, lvl){
return this.getCachesAt(lvl).has(key);
}
has(ele, lvl){
let key = this.getKey(ele);
return this.hasCache(key, lvl);
}
setCache(key, lvl, cache){
cache.key = key;
this.getCachesAt(lvl).set(key, cache);
}
set(ele, lvl, cache){
let key = this.getKey(ele);
this.setCache(key, lvl, cache);
this.updateKeyMappingFor(ele);
}
deleteCache(key, lvl){
this.getCachesAt(lvl).delete(key);
}
delete(ele, lvl){
let key = this.getKey(ele);
this.deleteCache(key, lvl);
}
invalidateKey(key){
this.lvls.forEach( lvl => this.deleteCache(key, lvl) );
}
// returns true if no other eles reference the invalidated cache (n.b. other eles may need the cache with the same key)
invalidate(ele){
let id = ele.id();
let key = this.keyForId.get(id); // n.b. use stored key rather than current (potential key)
this.deleteKeyMappingFor(ele);
let entireKeyInvalidated = this.doesEleInvalidateKey(ele);
if( entireKeyInvalidated ){ // clear mapping for current key
this.invalidateKey(key);
}
return entireKeyInvalidated || this.getNumberOfIdsForKey(key) === 0;
}
}
export default ElementTextureCacheLookup;