Skip to content

Commit c76c2e7

Browse files
committed
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
1 parent 6d59452 commit c76c2e7

File tree

1 file changed

+76
-2
lines changed

1 file changed

+76
-2
lines changed

src/librustdoc/html/static/js/search.js

+76-2
Original file line numberDiff line numberDiff line change
@@ -1318,7 +1318,7 @@ function initSearch(rawSearchIndex) {
13181318
* then this function will try with a different solution, or bail with false if it
13191319
* runs out of candidates.
13201320
*
1321-
* @param {Array<FunctionType>} fnTypes - The objects to check.
1321+
* @param {Array<FunctionType>} fnTypesIn - The objects to check.
13221322
* @param {Array<QueryElement>} queryElems - The elements from the parsed query.
13231323
* @param {[FunctionType]} whereClause - Trait bounds for generic items.
13241324
* @param {Map<number,number>|null} mgensIn
@@ -1340,6 +1340,79 @@ function initSearch(rawSearchIndex) {
13401340
}
13411341
const ql = queryElems.length;
13421342
let fl = fnTypesIn.length;
1343+
1344+
// Fast path
1345+
if (queryElems.length === 1 && queryElems[0].generics.length === 0) {
1346+
const queryElem = queryElems[0];
1347+
for (const fnType of fnTypesIn) {
1348+
if (!unifyFunctionTypeIsMatchCandidate(fnType, queryElem, whereClause, mgens)) {
1349+
continue;
1350+
}
1351+
if (fnType.id < 0 && queryElem.id < 0) {
1352+
if (mgens === null) {
1353+
mgens = new Map();
1354+
}
1355+
const alreadyAssigned = mgens.has(fnType.id);
1356+
if (alreadyAssigned) {
1357+
if (mgens.get(fnType.id) !== queryElem.id) {
1358+
continue;
1359+
}
1360+
} else {
1361+
mgens.set(fnType.id, queryElem.id);
1362+
}
1363+
if (!solutionCb || solutionCb(mgens)) {
1364+
return true;
1365+
}
1366+
if (!alreadyAssigned) {
1367+
mgens.delete(fnType.id);
1368+
}
1369+
} else if (!solutionCb || solutionCb(mgens)) {
1370+
// unifyFunctionTypeIsMatchCandidate already checks that ids match
1371+
return true;
1372+
}
1373+
}
1374+
for (const fnType of fnTypesIn) {
1375+
if (!unifyFunctionTypeIsUnboxCandidate(fnType, queryElem, whereClause, mgens)) {
1376+
continue;
1377+
}
1378+
if (fnType.id < 0) {
1379+
if (mgens === null) {
1380+
mgens = new Map();
1381+
}
1382+
const alreadyAssigned = mgens.has(fnType.id);
1383+
if (alreadyAssigned) {
1384+
if (mgens.get(fnType.id) !== 0) {
1385+
continue;
1386+
}
1387+
} else {
1388+
mgens.set(fnType.id, 0);
1389+
}
1390+
if (unifyFunctionTypes(
1391+
whereClause[(-fnType.id) - 1],
1392+
queryElems,
1393+
whereClause,
1394+
mgens,
1395+
solutionCb
1396+
)) {
1397+
return true;
1398+
}
1399+
if (!alreadyAssigned) {
1400+
mgens.delete(fnType.id);
1401+
}
1402+
} else if (unifyFunctionTypes(
1403+
fnType.generics,
1404+
queryElems,
1405+
whereClause,
1406+
mgens,
1407+
solutionCb
1408+
)) {
1409+
return true;
1410+
}
1411+
}
1412+
return false;
1413+
}
1414+
1415+
// Slow path
13431416
/**
13441417
* @type Array<FunctionType>
13451418
*/
@@ -1405,7 +1478,8 @@ function initSearch(rawSearchIndex) {
14051478
if (fnType.id < 0) {
14061479
if (mgens === null) {
14071480
mgens = new Map();
1408-
} else if (mgens.has(fnType.id) && mgens.get(fnType.id) !== queryElem.id) {
1481+
} else if (mgens.has(fnType.id) &&
1482+
mgens.get(fnType.id) !== queryElem.id) {
14091483
continue;
14101484
}
14111485
mgens.set(fnType.id, queryElem.id);

0 commit comments

Comments
 (0)