From 9ee72ec58819e7cfd7e8419efc19b0879b3b1a55 Mon Sep 17 00:00:00 2001 From: Joeri Samson Date: Sun, 13 Apr 2014 21:47:02 +0200 Subject: [PATCH] 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. --- lib/jsdoc/util/dumper.js | 43 ++++++++++++++++++++++++++++++++++------ 1 file changed, 37 insertions(+), 6 deletions(-) diff --git a/lib/jsdoc/util/dumper.js b/lib/jsdoc/util/dumper.js index fd65a9e2..317268c6 100644 --- a/lib/jsdoc/util/dumper.js +++ b/lib/jsdoc/util/dumper.js @@ -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 ''; } 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; };