diff --git a/src/librustdoc/html/static/js/search.js b/src/librustdoc/html/static/js/search.js index d23806f0b70..00d3ef9374d 100644 --- a/src/librustdoc/html/static/js/search.js +++ b/src/librustdoc/html/static/js/search.js @@ -90,91 +90,97 @@ function printTab(nb) { * algorithm should not matter to the caller of the methods, which is why it is not noted in the * documentation. */ -let editDistanceCurrent = []; -let editDistancePrev = []; -let editDistancePrevPrev = []; -function editDistance(a, b, limit) { - // Ensure that `b` is the shorter string, minimizing memory use. - if (a.length < b.length) { - const aTmp = a; - a = b; - b = aTmp; - } - - const minDist = a.length - b.length; - // If we know the limit will be exceeded, we can return early. - if (minDist > limit) { - return limit + 1; - } - - // Strip common prefix. - // We know that `b` is the shorter string, so we don't need to check - // `a.length`. - while (b.length > 0 && b[0] === a[0]) { - a = a.substring(1); - b = b.substring(1); - } - // Strip common suffix. - while (b.length > 0 && b[b.length - 1] === a[a.length - 1]) { - a = a.substring(0, a.length - 1); - b = b.substring(0, b.length - 1); - } - - // If either string is empty, the distance is the length of the other. - // We know that `b` is the shorter string, so we don't need to check `a`. - if (b.length === 0) { - return minDist; - } - - const aLength = a.length; - const bLength = b.length; - - for (let i = 0; i <= bLength; ++i) { - editDistanceCurrent[i] = 0; - editDistancePrev[i] = i; - editDistancePrevPrev[i] = Number.MAX_VALUE; - } - - // row by row - for (let i = 1; i <= aLength; ++i) { - editDistanceCurrent[0] = i; - const aIdx = i - 1; - - // column by column - for (let j = 1; j <= bLength; ++j) { - const bIdx = j - 1; - - // There is no cost to substitute a character with itself. - const substitutionCost = a[aIdx] === b[bIdx] ? 0 : 1; - - editDistanceCurrent[j] = Math.min( - // deletion - editDistancePrev[j] + 1, - // insertion - editDistanceCurrent[j - 1] + 1, - // substitution - editDistancePrev[j - 1] + substitutionCost - ); - - if ((i > 1) && (j > 1) && (a[aIdx] === b[bIdx - 1]) && (a[aIdx - 1] === b[bIdx])) { - // transposition - editDistanceCurrent[j] = Math.min( - editDistanceCurrent[j], - editDistancePrevPrev[j - 2] + 1 - ); - } +const editDistanceState = { + current: [], + prev: [], + prevPrev: [], + calculate: function calculate(a, b, limit) { + // Ensure that `b` is the shorter string, minimizing memory use. + if (a.length < b.length) { + const aTmp = a; + a = b; + b = aTmp; } - // Rotate the buffers, reusing the memory - const prevPrevTmp = editDistancePrevPrev; - editDistancePrevPrev = editDistancePrev; - editDistancePrev = editDistanceCurrent; - editDistanceCurrent = prevPrevTmp; - } + const minDist = a.length - b.length; + // If we know the limit will be exceeded, we can return early. + if (minDist > limit) { + return limit + 1; + } - // `prev` because we already rotated the buffers. - const distance = editDistancePrev[bLength]; - return distance <= limit ? distance : (limit + 1); + // Strip common prefix. + // We know that `b` is the shorter string, so we don't need to check + // `a.length`. + while (b.length > 0 && b[0] === a[0]) { + a = a.substring(1); + b = b.substring(1); + } + // Strip common suffix. + while (b.length > 0 && b[b.length - 1] === a[a.length - 1]) { + a = a.substring(0, a.length - 1); + b = b.substring(0, b.length - 1); + } + + // If either string is empty, the distance is the length of the other. + // We know that `b` is the shorter string, so we don't need to check `a`. + if (b.length === 0) { + return minDist; + } + + const aLength = a.length; + const bLength = b.length; + + for (let i = 0; i <= bLength; ++i) { + this.current[i] = 0; + this.prev[i] = i; + this.prevPrev[i] = Number.MAX_VALUE; + } + + // row by row + for (let i = 1; i <= aLength; ++i) { + this.current[0] = i; + const aIdx = i - 1; + + // column by column + for (let j = 1; j <= bLength; ++j) { + const bIdx = j - 1; + + // There is no cost to substitute a character with itself. + const substitutionCost = a[aIdx] === b[bIdx] ? 0 : 1; + + this.current[j] = Math.min( + // deletion + this.prev[j] + 1, + // insertion + this.current[j - 1] + 1, + // substitution + this.prev[j - 1] + substitutionCost + ); + + if ((i > 1) && (j > 1) && (a[aIdx] === b[bIdx - 1]) && (a[aIdx - 1] === b[bIdx])) { + // transposition + this.current[j] = Math.min( + this.current[j], + this.prevPrev[j - 2] + 1 + ); + } + } + + // Rotate the buffers, reusing the memory + const prevPrevTmp = this.prevPrev; + this.prevPrev = this.prev; + this.prev = this.current; + this.current = prevPrevTmp; + } + + // `prev` because we already rotated the buffers. + const distance = this.prev[bLength]; + return distance <= limit ? distance : (limit + 1); + }, +}; + +function editDistance(a, b, limit) { + return editDistanceState.calculate(a, b, limit); } function initSearch(rawSearchIndex) {