diff --git a/src/librustdoc/html/static/js/search.js b/src/librustdoc/html/static/js/search.js index dc47e093ecd75..a72190661043b 100644 --- a/src/librustdoc/html/static/js/search.js +++ b/src/librustdoc/html/static/js/search.js @@ -2261,6 +2261,22 @@ function initSearch(rawSearchIndex) { } } } else if (parsedQuery.foundElems > 0) { + // Sort input and output so that generic type variables go first and + // types with generic parameters go last. + // That's because of the way unification is structured: it eats off + // the end, and hits a fast path if the last item is a simple atom. + const sortQ = (a, b) => { + const ag = a.generics.length === 0 && a.bindings.size === 0; + const bg = b.generics.length === 0 && b.bindings.size === 0; + if (ag !== bg) { + return ag - bg; + } + const ai = a.id > 0; + const bi = b.id > 0; + return ai - bi; + }; + parsedQuery.elems.sort(sortQ); + parsedQuery.returned.sort(sortQ); for (let i = 0, nSearchWords = searchWords.length; i < nSearchWords; ++i) { handleArgs(searchIndex[i], i, results_others); } @@ -2823,7 +2839,6 @@ ${item.displayPath}${name}\ * @param {Set} fps - Set of distinct items */ function buildFunctionTypeFingerprint(type, output, fps) { - let input = type.id; // All forms of `[]` get collapsed down to one thing in the bloom filter. // Differentiating between arrays and slices, if the user asks for it, is @@ -2831,15 +2846,37 @@ ${item.displayPath}${name}\ if (input === typeNameIdOfArray || input === typeNameIdOfSlice) { input = typeNameIdOfArrayOrSlice; } + // http://burtleburtle.net/bob/hash/integer.html + // ~~ is toInt32. It's used before adding, so + // the number stays in safe integer range. + const hashint1 = k => { + k = (~~k + 0x7ed55d16) + (k << 12); + k = (k ^ 0xc761c23c) ^ (k >>> 19); + k = (~~k + 0x165667b1) + (k << 5); + k = (~~k + 0xd3a2646c) ^ (k << 9); + k = (~~k + 0xfd7046c5) + (k << 3); + return (k ^ 0xb55a4f09) ^ (k >>> 16); + }; + const hashint2 = k => { + k = ~k + (k << 15); + k ^= k >>> 12; + k += k << 2; + k ^= k >>> 4; + k = Math.imul(k, 2057); + return k ^ (k >> 16); + }; if (input !== null) { - // https://docs.rs/rustc-hash/1.1.0/src/rustc_hash/lib.rs.html#60 - // Rotate is skipped because we're only doing one cycle anyway. - const h0 = Math.imul(input, 0x9e3779b9); - const h1 = Math.imul(479001599 ^ input, 0x9e3779b9); - const h2 = Math.imul(433494437 ^ input, 0x9e3779b9); - output[0] |= 1 << (h0 % 32); - output[1] |= 1 << (h1 % 32); - output[2] |= 1 << (h2 % 32); + const h0a = hashint1(input); + const h0b = hashint2(input); + // Less Hashing, Same Performance: Building a Better Bloom Filter + // doi=10.1.1.72.2442 + const h1a = ~~(h0a + Math.imul(h0b, 2)); + const h1b = ~~(h0a + Math.imul(h0b, 3)); + const h2a = ~~(h0a + Math.imul(h0b, 4)); + const h2b = ~~(h0a + Math.imul(h0b, 5)); + output[0] |= (1 << (h0a % 32)) | (1 << (h1b % 32)); + output[1] |= (1 << (h1a % 32)) | (1 << (h2b % 32)); + output[2] |= (1 << (h2a % 32)) | (1 << (h0b % 32)); fps.add(input); } for (const g of type.generics) { @@ -2868,7 +2905,6 @@ ${item.displayPath}${name}\ * This function might return 0! */ function compareTypeFingerprints(fullId, queryFingerprint) { - const fh0 = functionTypeFingerprint[fullId * 4]; const fh1 = functionTypeFingerprint[(fullId * 4) + 1]; const fh2 = functionTypeFingerprint[(fullId * 4) + 2];