about summary refs log tree commit diff
diff options
context:
space:
mode:
authorMichael Howell <michael@notriddle.com>2023-11-17 14:44:53 -0700
committerMichael Howell <michael@notriddle.com>2023-11-17 18:22:30 -0700
commitc76c2e71f01a61a9b11001b0dc3fe837975f41c0 (patch)
tree603181212f210d780d6a9bea963b1e8184852a0d
parent6d5945284147be6dd22486fb1c189c57a98632cd (diff)
downloadrust-c76c2e71f01a61a9b11001b0dc3fe837975f41c0.tar.gz
rust-c76c2e71f01a61a9b11001b0dc3fe837975f41c0.zip
rustdoc-search: fast path for 1-query unification
Short queries, in addition to being common, are also the base
case for a lot of more complicated queries. We can avoid
most of the backtracking data structures, and use simple
recursive matching instead, by special casing them.

Profile output:
https://notriddle.com/rustdoc-html-demo-5/profile-3/index.html
-rw-r--r--src/librustdoc/html/static/js/search.js78
1 files changed, 76 insertions, 2 deletions
diff --git a/src/librustdoc/html/static/js/search.js b/src/librustdoc/html/static/js/search.js
index 0c337f47dc9..38391436aea 100644
--- a/src/librustdoc/html/static/js/search.js
+++ b/src/librustdoc/html/static/js/search.js
@@ -1318,7 +1318,7 @@ function initSearch(rawSearchIndex) {
          * then this function will try with a different solution, or bail with false if it
          * runs out of candidates.
          *
-         * @param {Array<FunctionType>} fnTypes - The objects to check.
+         * @param {Array<FunctionType>} fnTypesIn - The objects to check.
          * @param {Array<QueryElement>} queryElems - The elements from the parsed query.
          * @param {[FunctionType]} whereClause - Trait bounds for generic items.
          * @param {Map<number,number>|null} mgensIn
@@ -1340,6 +1340,79 @@ function initSearch(rawSearchIndex) {
             }
             const ql = queryElems.length;
             let fl = fnTypesIn.length;
+
+            // Fast path
+            if (queryElems.length === 1 && queryElems[0].generics.length === 0) {
+                const queryElem = queryElems[0];
+                for (const fnType of fnTypesIn) {
+                    if (!unifyFunctionTypeIsMatchCandidate(fnType, queryElem, whereClause, mgens)) {
+                        continue;
+                    }
+                    if (fnType.id < 0 && queryElem.id < 0) {
+                        if (mgens === null) {
+                            mgens = new Map();
+                        }
+                        const alreadyAssigned = mgens.has(fnType.id);
+                        if (alreadyAssigned) {
+                            if (mgens.get(fnType.id) !== queryElem.id) {
+                                continue;
+                            }
+                        } else {
+                            mgens.set(fnType.id, queryElem.id);
+                        }
+                        if (!solutionCb || solutionCb(mgens)) {
+                            return true;
+                        }
+                        if (!alreadyAssigned) {
+                            mgens.delete(fnType.id);
+                        }
+                    } else if (!solutionCb || solutionCb(mgens)) {
+                        // unifyFunctionTypeIsMatchCandidate already checks that ids match
+                        return true;
+                    }
+                }
+                for (const fnType of fnTypesIn) {
+                    if (!unifyFunctionTypeIsUnboxCandidate(fnType, queryElem, whereClause, mgens)) {
+                        continue;
+                    }
+                    if (fnType.id < 0) {
+                        if (mgens === null) {
+                            mgens = new Map();
+                        }
+                        const alreadyAssigned = mgens.has(fnType.id);
+                        if (alreadyAssigned) {
+                            if (mgens.get(fnType.id) !== 0) {
+                                continue;
+                            }
+                        } else {
+                            mgens.set(fnType.id, 0);
+                        }
+                        if (unifyFunctionTypes(
+                            whereClause[(-fnType.id) - 1],
+                            queryElems,
+                            whereClause,
+                            mgens,
+                            solutionCb
+                        )) {
+                            return true;
+                        }
+                        if (!alreadyAssigned) {
+                            mgens.delete(fnType.id);
+                        }
+                    } else if (unifyFunctionTypes(
+                        fnType.generics,
+                        queryElems,
+                        whereClause,
+                        mgens,
+                        solutionCb
+                    )) {
+                        return true;
+                    }
+                }
+                return false;
+            }
+
+            // Slow path
             /**
              * @type Array<FunctionType>
              */
@@ -1405,7 +1478,8 @@ function initSearch(rawSearchIndex) {
                         if (fnType.id < 0) {
                             if (mgens === null) {
                                 mgens = new Map();
-                            } else if (mgens.has(fnType.id) && mgens.get(fnType.id) !== queryElem.id) {
+                            } else if (mgens.has(fnType.id) &&
+                                mgens.get(fnType.id) !== queryElem.id) {
                                 continue;
                             }
                             mgens.set(fnType.id, queryElem.id);