scontainers
Version:
A container/collection/iterator library for JavaScript, comfortable to use, performant and versatile.
145 lines (107 loc) • 3.44 kB
JavaScript
;
function _implSymbol(target, sym, value) {
Object.defineProperty(target, sym, {
value,
configurable: true
});
return target[sym];
}
function _getSymbol(targetSymName, ...traitSets) {
let symbol;
traitSets.forEach(traitSet => {
const sym = traitSet[targetSymName];
if (typeof sym === 'symbol') {
if (!!symbol && symbol !== sym) {
throw new Error(`Symbol ${targetSymName} offered by multiple trait sets.`);
}
symbol = sym;
}
});
if (!symbol) {
throw new Error(`No trait set is providing symbol ${targetSymName}.`);
}
return symbol;
}
function _testTraitSet(traitSet) {
if (!traitSet || typeof traitSet === 'boolean' || typeof traitSet === 'number' || typeof traitSet === 'string') {
throw new Error(`${traitSet} cannot be used as a trait set.`);
}
}
const {
traits,
id,
KVN
} = require('../utils.js');
_testTraitSet(traits.utils);
_testTraitSet(traits.scontainers);
_testTraitSet(traits.semantics);
const _hasKey = _getSymbol("hasKey", traits.utils, traits.scontainers, traits.semantics);
const _describeScontainer = _getSymbol("describeScontainer", traits.utils, traits.scontainers, traits.semantics);
const _implCoreTraits = _getSymbol("implCoreTraits", traits.utils, traits.scontainers, traits.semantics);
const _nthKVN = _getSymbol("nthKVN", traits.utils, traits.scontainers, traits.semantics);
const _getKVN = _getSymbol("getKVN", traits.utils, traits.scontainers, traits.semantics);
const _nToKey = _getSymbol("nToKey", traits.utils, traits.scontainers, traits.semantics);
const _get = _getSymbol("get", traits.utils, traits.scontainers, traits.semantics);
const _set = _getSymbol("set", traits.utils, traits.scontainers, traits.semantics);
const _len = _getSymbol("len", traits.utils, traits.scontainers, traits.semantics);
module.exports = function (ParentCollection) {
if (!ParentCollection.prototype[_hasKey]) {
return;
}
return function () {
class Cache {
static get name() {
return `${ParentCollection.name}::Cache`;
}
constructor(coll, CacheType = Map) {
this.wrapped = coll;
this.cache = new CacheType();
}
toString() {
return `${this.wrapped}.cache(${this.cache.constructor.name})`;
}
}
const parentProto = ParentCollection.prototype;
Cache[_describeScontainer]({
InnerCollection: ParentCollection,
innerCollectionKey: id`wrapped`,
argKeys: [id`mapFn`]
});
Cache[_implCoreTraits]({
stage(kvn) {
return kvn;
},
indexToParentIndex(index) {
return index;
},
nthKVN() {
if (parentProto[_nthKVN]) {
return function (n) {
return this[_getKVN](this[_nToKey](n));
};
}
},
getKVN() {
if (parentProto[_getKVN]) {
return function (key) {
if (this.cache[_hasKey](key)) {
const kvn = this.cache[_get](key);
return new KVN(kvn.key, kvn.value, kvn.n);
}
const kvn = this.wrapped[_getKVN](key);
this.cache[_set](key, kvn);
return new KVN(kvn.key, kvn.value, kvn.n);
};
}
},
len() {
if (parentProto[_len]) {
return function () {
return this.wrapped[_len]();
};
}
}
});
return Cache;
};
};