Faster dumping with and without Harmony

Replace an O(n^2) algorithm (indexOf + insert) * n with a much faster
algorithm, depending on what is supported by the JS engine.

I prefer the Set version as it is similar in spirit to the original
code and does not need to change the walked tree, but the flag setting
approach has the advantage that it works with current Node versions
without needing commandline flags.
This commit is contained in:
Joeri Samson 2014-04-13 21:47:02 +02:00
parent bac1ea00fa
commit 9ee72ec588

View File

@ -7,17 +7,43 @@
'use strict';
var util = require('util');
var setDefined = typeof Set !== 'undefined';
function ObjectWalker() {
this.seenItems = [];
if (setDefined) {
this.seenItems = new Set();
} else {
this.seenItems = [];
}
}
ObjectWalker.prototype.seen = function(object) {
if (this.seenItems.indexOf(object) !== -1) {
return true;
var result;
if (setDefined) {
result = this.seenItems.has(object);
} else {
result = object.hasBeenSeenByWalkerDumper;
}
return result;
};
return false;
ObjectWalker.prototype.markAsSeen = function(object) {
if (setDefined) {
this.seenItems.add(object);
} else {
object.hasBeenSeenByWalkerDumper = true;
this.seenItems.push(object);
}
};
ObjectWalker.prototype.cleanSeenFlag = function() {
if (setDefined) {
this.seenItems = new Set();
} else {
this.seenItems.forEach(function(object) {
delete object.hasBeenSeenByWalkerDumper;
});
}
};
// some objects are unwalkable, like Java native objects
@ -39,7 +65,7 @@ ObjectWalker.prototype.checkCircularRefs = function(o, func) {
return '<CircularRef>';
}
else {
this.seenItems.push(o);
this.markAsSeen(o);
return func(o);
}
};
@ -81,6 +107,7 @@ ObjectWalker.prototype.walk = function(o) {
result = this.checkCircularRefs(o, function(obj) {
var newObj = {};
Object.keys(obj).forEach(function(key) {
if (!setDefined && key === 'hasBeenSeenByWalkerDumper') { return; }
newObj[key] = self.walk(obj[key]);
});
@ -99,5 +126,9 @@ ObjectWalker.prototype.walk = function(o) {
* @param {*} object
*/
exports.dump = function(object) {
return JSON.stringify(new ObjectWalker().walk(object), null, 4);
var walker = new ObjectWalker();
var result = JSON.stringify(walker.walk(object), null, 4);
walker.cleanSeenFlag();
return result;
};