From: Jakub Pawlowicz Date: Sun, 23 Feb 2014 16:12:05 +0000 (+0000) Subject: Refactors the new, non-adjacent optimizer. X-Git-Url: https://git.ndcode.org/public/gitweb.cgi?a=commitdiff_plain;h=be857dded6c8286b658bc185da472742a042d126;p=clean-css.git Refactors the new, non-adjacent optimizer. * Extracts common parts from simple & complex scenarios. * Adds performance boost so its speed is comparable with the old one. --- diff --git a/lib/selectors/optimizer.js b/lib/selectors/optimizer.js index c55c155a..cbf3e7f6 100644 --- a/lib/selectors/optimizer.js +++ b/lib/selectors/optimizer.js @@ -161,54 +161,27 @@ module.exports = function Optimizer(data, context, options) { for (var i = 0, l = matches.length; i < l; i++) { var selector = matches[i]; var data = positions[selector]; - var bodies = []; - var joinsAt = []; - var processedTokens = []; - - for (var j = data.length - 1, m = 0; j >= 0; j--) { - if (data[j].partial && bodies.length === 0) - continue; - - var where = data[j].where; - var token = tokens[where]; - var body = token.body; - bodies.push(body); - processedTokens.push(where); - } - - for (j = 0, m = bodies.length; j < m; j++) { - if (bodies[j].length > 0) - joinsAt.push((joinsAt[j - 1] || 0) + bodies[j].split(';').length); - } - - var optimizedBody = propertyOptimizer.process(bodies.join(';'), joinsAt); - var optimizedProperties = optimizedBody.split(';'); - var processedCount = processedTokens.length; - var propertyIdx = optimizedProperties.length - 1; - var tokenIdx = processedCount - 1; + if (data.length < 2) + continue; - while (tokenIdx >= 0) { - if ((tokenIdx === 0 || bodies[tokenIdx].indexOf(optimizedProperties[propertyIdx]) > -1) && propertyIdx > -1) { - propertyIdx--; - continue; + /* jshint loopfunc: true */ + _reduceSelector(tokens, selector, data, { + filterOut: function(idx, bodies) { + return data[idx].partial && bodies.length === 0; + }, + callback: function(token, newBody, processedCount, tokenIdx) { + if (!data[processedCount - tokenIdx - 1].partial) + token.body = newBody.join(';'); } - - var newBody = optimizedProperties.splice(propertyIdx + 1); - if (!data[processedCount - tokenIdx - 1].partial) - tokens[processedTokens[tokenIdx]].body = newBody.join(';'); - - tokenIdx--; - } + }); } }; var _reduceComplexNonAdjacentCases = function(tokens, positions) { - for (var i = 0, matches = Object.keys(positions), l = matches.length; i < l; i++) { - var complexSelector = matches[i]; - var allSame = true; - - if (complexSelector.indexOf(',') == -1) // another assumption which is wrong in case of :not() selector + allSelectors: + for (var complexSelector in positions) { + if (complexSelector.indexOf(',') == -1) // simplification, as :not() can have commas too continue; var intoPosition = positions[complexSelector].pop().where; @@ -220,51 +193,67 @@ module.exports = function Optimizer(data, context, options) { for (var j = 0, m = selectors.length; j < m; j++) { var selector = selectors[j]; var data = positions[selector]; - var bodies = []; - var joinsAt = []; - var processedTokens = []; - - for (var k = data.length - 1, n = 0; k >= 0; k--) { - var where = data[k].where; - if (where < intoPosition) - continue; - - var token = tokens[where]; - var body = token.body; - bodies.push(body); - processedTokens.push(where); - } - for (k = 0, n = bodies.length; k < n; k++) { - if (bodies[k].length > 0) - joinsAt.push((joinsAt[k - 1] || 0) + bodies[k].split(';').length); - } + if (data.length < 2) + continue allSelectors; + + /* jshint loopfunc: true */ + _reduceSelector(tokens, selector, data, { + filterOut: function(idx) { + return data[idx].where < intoPosition; + }, + callback: function(token, newBody, processedCount, tokenIdx) { + if (tokenIdx === 0) + reducedBodies.push(newBody.join(';')); + } + }); - var optimizedBody = propertyOptimizer.process(bodies.join(';'), joinsAt); - var optimizedProperties = optimizedBody.split(';'); + if (reducedBodies[reducedBodies.length - 1] != reducedBodies[0]) + continue allSelectors; + } - var processedCount = processedTokens.length; - var propertyIdx = optimizedProperties.length - 1; - var tokenIdx = processedCount - 1; + intoToken.body = reducedBodies[0]; + } + }; - while (tokenIdx >= 0) { - if ((tokenIdx === 0 || bodies[tokenIdx].indexOf(optimizedProperties[propertyIdx]) > -1) && propertyIdx > -1) { - propertyIdx--; - continue; - } + var _reduceSelector = function(tokens, selector, data, options) { + var bodies = []; + var joinsAt = []; + var processedTokens = []; - var newBody = optimizedProperties.splice(propertyIdx + 1); - if (tokenIdx === 0) - reducedBodies.push(newBody.join(';')); + for (var j = data.length - 1, m = 0; j >= 0; j--) { + if (options.filterOut(j, bodies)) + continue; - tokenIdx--; - } + var where = data[j].where; + var token = tokens[where]; + var body = token.body; + bodies.push(body); + processedTokens.push(where); + } - allSame = allSame && reducedBodies[reducedBodies.length - 1] == reducedBodies[0]; + for (j = 0, m = bodies.length; j < m; j++) { + if (bodies[j].length > 0) + joinsAt.push((joinsAt[j - 1] || 0) + bodies[j].split(';').length); + } + + var optimizedBody = propertyOptimizer.process(bodies.join(';'), joinsAt); + var optimizedProperties = optimizedBody.split(';'); + + var processedCount = processedTokens.length; + var propertyIdx = optimizedProperties.length - 1; + var tokenIdx = processedCount - 1; + + while (tokenIdx >= 0) { + if ((tokenIdx === 0 || bodies[tokenIdx].indexOf(optimizedProperties[propertyIdx]) > -1) && propertyIdx > -1) { + propertyIdx--; + continue; } - if (allSame) - intoToken.body = reducedBodies[0]; + var newBody = optimizedProperties.splice(propertyIdx + 1); + options.callback(tokens[processedTokens[tokenIdx]], newBody, processedCount, tokenIdx); + + tokenIdx--; } };