Add visitor.js array-based function cache for faster lookups. perf / #1615

This commit is contained in:
fredburger
2013-10-30 00:01:57 +01:00
parent 0213579de4
commit e5ae8a2500

View File

@@ -1,7 +1,39 @@
(function (tree) {
var _visitArgs = { visitDeeper: true },
_hasIndexed = false;
function _noop(node) {
return node;
}
function indexNodeTypes(parent, ticker) {
// add .typeIndex to tree node types for lookup table
var key, child;
for (key in parent) {
child = parent[key];
switch (typeof child) {
case "function":
if (child.prototype.type) {
child.prototype.typeIndex = ticker++;
}
break;
case "object":
ticker = indexNodeTypes(child, ticker);
break;
}
}
return ticker;
}
tree.visitor = function(implementation) {
this._implementation = implementation;
this._visitFnCache = [];
if (!_hasIndexed) {
indexNodeTypes(tree, 1);
_hasIndexed = true;
}
};
tree.visitor.prototype = {
@@ -11,27 +43,48 @@
return this.visitArray(node);
}
if (!node || !node.type) {
if (!node) {
return node;
}
var funcName = "visit" + node.type,
func = this._implementation[funcName],
visitArgs, newNode;
if (func) {
visitArgs = {visitDeeper: true};
newNode = func.call(this._implementation, node, visitArgs);
if (this._implementation.isReplacing) {
var nodeTypeIndex = node.typeIndex;
if (!nodeTypeIndex) {
return node;
}
var visitFnCache = this._visitFnCache,
impl = this._implementation,
aryIndx = nodeTypeIndex << 1,
func = visitFnCache[aryIndx],
funcOut = visitFnCache[aryIndx | 1],
visitArgs = _visitArgs, noop = _noop,
fnName;
visitArgs.visitDeeper = true;
if (!func) {
fnName = "visit" + node.type;
func = impl[fnName] || noop;
funcOut = impl[fnName + "Out"] || noop;
visitFnCache[aryIndx] = func;
visitFnCache[aryIndx | 1] = funcOut;
}
if (func != noop) {
var newNode = func.call(impl, node, visitArgs);
if (impl.isReplacing) {
node = newNode;
}
}
if ((!visitArgs || visitArgs.visitDeeper) && node && node.accept) {
if (visitArgs.visitDeeper && node && node.accept) {
node.accept(this);
}
funcName = funcName + "Out";
if (this._implementation[funcName]) {
this._implementation[funcName](node);
if (funcOut != noop) {
funcOut.call(impl, node);
}
return node;
},
visitArray: function(nodes) {