@@ -1106,7 +1106,7 @@ class DocSearch {
11061106 /**
11071107 * @type {Uint32Array }
11081108 */
1109- this . functionTypeFingerprint = new Uint32Array ( ( id + 1 ) * 4 ) ;
1109+ this . functionTypeFingerprint = null ;
11101110 /**
11111111 * Map from normalized type names to integers. Used to make type search
11121112 * more efficient.
@@ -1182,7 +1182,7 @@ class DocSearch {
11821182 /**
11831183 * @type {Array<Row> }
11841184 */
1185- this . searchIndex = buildIndex ( rawSearchIndex ) ;
1185+ this . searchIndex = this . buildIndex ( rawSearchIndex ) ;
11861186 }
11871187
11881188 /**
@@ -1359,6 +1359,91 @@ class DocSearch {
13591359 return result ;
13601360 }
13611361
1362+ /**
1363+ * Type fingerprints allow fast, approximate matching of types.
1364+ *
1365+ * This algo creates a compact representation of the type set using a Bloom filter.
1366+ * This fingerprint is used three ways:
1367+ *
1368+ * - It accelerates the matching algorithm by checking the function fingerprint against the
1369+ * query fingerprint. If any bits are set in the query but not in the function, it can't
1370+ * match.
1371+ *
1372+ * - The fourth section has the number of distinct items in the set.
1373+ * This is the distance function, used for filtering and for sorting.
1374+ *
1375+ * [^1]: Distance is the relatively naive metric of counting the number of distinct items in
1376+ * the function that are not present in the query.
1377+ *
1378+ * @param {FunctionType|QueryElement } type - a single type
1379+ * @param {Uint32Array } output - write the fingerprint to this data structure: uses 128 bits
1380+ * @param {Set<number> } fps - Set of distinct items
1381+ */
1382+ buildFunctionTypeFingerprint ( type , output , fps ) {
1383+ let input = type . id ;
1384+ // All forms of `[]`/`()`/`->` get collapsed down to one thing in the bloom filter.
1385+ // Differentiating between arrays and slices, if the user asks for it, is
1386+ // still done in the matching algorithm.
1387+ if ( input === this . typeNameIdOfArray || input === this . typeNameIdOfSlice ) {
1388+ input = this . typeNameIdOfArrayOrSlice ;
1389+ }
1390+ if ( input === this . typeNameIdOfTuple || input === this . typeNameIdOfUnit ) {
1391+ input = this . typeNameIdOfTupleOrUnit ;
1392+ }
1393+ if ( input === this . typeNameIdOfFn || input === this . typeNameIdOfFnMut ||
1394+ input === this . typeNameIdOfFnOnce ) {
1395+ input = this . typeNameIdOfHof ;
1396+ }
1397+ // http://burtleburtle.net/bob/hash/integer.html
1398+ // ~~ is toInt32. It's used before adding, so
1399+ // the number stays in safe integer range.
1400+ const hashint1 = k => {
1401+ k = ( ~ ~ k + 0x7ed55d16 ) + ( k << 12 ) ;
1402+ k = ( k ^ 0xc761c23c ) ^ ( k >>> 19 ) ;
1403+ k = ( ~ ~ k + 0x165667b1 ) + ( k << 5 ) ;
1404+ k = ( ~ ~ k + 0xd3a2646c ) ^ ( k << 9 ) ;
1405+ k = ( ~ ~ k + 0xfd7046c5 ) + ( k << 3 ) ;
1406+ return ( k ^ 0xb55a4f09 ) ^ ( k >>> 16 ) ;
1407+ } ;
1408+ const hashint2 = k => {
1409+ k = ~ k + ( k << 15 ) ;
1410+ k ^= k >>> 12 ;
1411+ k += k << 2 ;
1412+ k ^= k >>> 4 ;
1413+ k = Math . imul ( k , 2057 ) ;
1414+ return k ^ ( k >> 16 ) ;
1415+ } ;
1416+ if ( input !== null ) {
1417+ const h0a = hashint1 ( input ) ;
1418+ const h0b = hashint2 ( input ) ;
1419+ // Less Hashing, Same Performance: Building a Better Bloom Filter
1420+ // doi=10.1.1.72.2442
1421+ const h1a = ~ ~ ( h0a + Math . imul ( h0b , 2 ) ) ;
1422+ const h1b = ~ ~ ( h0a + Math . imul ( h0b , 3 ) ) ;
1423+ const h2a = ~ ~ ( h0a + Math . imul ( h0b , 4 ) ) ;
1424+ const h2b = ~ ~ ( h0a + Math . imul ( h0b , 5 ) ) ;
1425+ output [ 0 ] |= ( 1 << ( h0a % 32 ) ) | ( 1 << ( h1b % 32 ) ) ;
1426+ output [ 1 ] |= ( 1 << ( h1a % 32 ) ) | ( 1 << ( h2b % 32 ) ) ;
1427+ output [ 2 ] |= ( 1 << ( h2a % 32 ) ) | ( 1 << ( h0b % 32 ) ) ;
1428+ fps . add ( input ) ;
1429+ }
1430+ for ( const g of type . generics ) {
1431+ this . buildFunctionTypeFingerprint ( g , output , fps ) ;
1432+ }
1433+ const fb = {
1434+ id : null ,
1435+ ty : 0 ,
1436+ generics : this . EMPTY_GENERICS_ARRAY ,
1437+ bindings : this . EMPTY_BINDINGS_MAP ,
1438+ } ;
1439+ for ( const [ k , v ] of type . bindings . entries ( ) ) {
1440+ fb . id = k ;
1441+ fb . generics = v ;
1442+ this . buildFunctionTypeFingerprint ( fb , output , fps ) ;
1443+ }
1444+ output [ 3 ] = fps . size ;
1445+ }
1446+
13621447 /**
13631448 * Convert raw search index into in-memory search index.
13641449 *
@@ -1390,7 +1475,7 @@ class DocSearch {
13901475 let inputs , output ;
13911476 if ( typeof functionSearchType [ INPUTS_DATA ] === "number" ) {
13921477 inputs = [
1393- this . buildItemSearchType ( functionSearchType [ INPUTS_DATA ] , lowercasePaths )
1478+ this . buildItemSearchType ( functionSearchType [ INPUTS_DATA ] , lowercasePaths ) ,
13941479 ] ;
13951480 } else {
13961481 inputs = this . buildItemSearchTypeAll (
@@ -1404,7 +1489,7 @@ class DocSearch {
14041489 this . buildItemSearchType (
14051490 functionSearchType [ OUTPUT_DATA ] ,
14061491 lowercasePaths ,
1407- )
1492+ ) ,
14081493 ] ;
14091494 } else {
14101495 output = this . buildItemSearchTypeAll (
@@ -1426,94 +1511,9 @@ class DocSearch {
14261511 inputs, output, where_clause,
14271512 } ;
14281513 } ;
1429- }
1430-
1431- /**
1432- * Type fingerprints allow fast, approximate matching of types.
1433- *
1434- * This algo creates a compact representation of the type set using a Bloom filter.
1435- * This fingerprint is used three ways:
1436- *
1437- * - It accelerates the matching algorithm by checking the function fingerprint against the
1438- * query fingerprint. If any bits are set in the query but not in the function, it can't
1439- * match.
1440- *
1441- * - The fourth section has the number of distinct items in the set.
1442- * This is the distance function, used for filtering and for sorting.
1443- *
1444- * [^1]: Distance is the relatively naive metric of counting the number of distinct items in
1445- * the function that are not present in the query.
1446- *
1447- * @param {FunctionType|QueryElement } type - a single type
1448- * @param {Uint32Array } output - write the fingerprint to this data structure: uses 128 bits
1449- * @param {Set<number> } fps - Set of distinct items
1450- */
1451- const buildFunctionTypeFingerprint = ( type , output , fps ) => {
1452- let input = type . id ;
1453- // All forms of `[]`/`()`/`->` get collapsed down to one thing in the bloom filter.
1454- // Differentiating between arrays and slices, if the user asks for it, is
1455- // still done in the matching algorithm.
1456- if ( input === this . typeNameIdOfArray || input === this . typeNameIdOfSlice ) {
1457- input = this . typeNameIdOfArrayOrSlice ;
1458- }
1459- if ( input === this . typeNameIdOfTuple || input === this . typeNameIdOfUnit ) {
1460- input = this . typeNameIdOfTupleOrUnit ;
1461- }
1462- if ( input === this . typeNameIdOfFn || input === this . typeNameIdOfFnMut ||
1463- input === this . typeNameIdOfFnOnce ) {
1464- input = this . typeNameIdOfHof ;
1465- }
1466- // http://burtleburtle.net/bob/hash/integer.html
1467- // ~~ is toInt32. It's used before adding, so
1468- // the number stays in safe integer range.
1469- const hashint1 = k => {
1470- k = ( ~ ~ k + 0x7ed55d16 ) + ( k << 12 ) ;
1471- k = ( k ^ 0xc761c23c ) ^ ( k >>> 19 ) ;
1472- k = ( ~ ~ k + 0x165667b1 ) + ( k << 5 ) ;
1473- k = ( ~ ~ k + 0xd3a2646c ) ^ ( k << 9 ) ;
1474- k = ( ~ ~ k + 0xfd7046c5 ) + ( k << 3 ) ;
1475- return ( k ^ 0xb55a4f09 ) ^ ( k >>> 16 ) ;
1476- } ;
1477- const hashint2 = k => {
1478- k = ~ k + ( k << 15 ) ;
1479- k ^= k >>> 12 ;
1480- k += k << 2 ;
1481- k ^= k >>> 4 ;
1482- k = Math . imul ( k , 2057 ) ;
1483- return k ^ ( k >> 16 ) ;
1484- } ;
1485- if ( input !== null ) {
1486- const h0a = hashint1 ( input ) ;
1487- const h0b = hashint2 ( input ) ;
1488- // Less Hashing, Same Performance: Building a Better Bloom Filter
1489- // doi=10.1.1.72.2442
1490- const h1a = ~ ~ ( h0a + Math . imul ( h0b , 2 ) ) ;
1491- const h1b = ~ ~ ( h0a + Math . imul ( h0b , 3 ) ) ;
1492- const h2a = ~ ~ ( h0a + Math . imul ( h0b , 4 ) ) ;
1493- const h2b = ~ ~ ( h0a + Math . imul ( h0b , 5 ) ) ;
1494- output [ 0 ] |= ( 1 << ( h0a % 32 ) ) | ( 1 << ( h1b % 32 ) ) ;
1495- output [ 1 ] |= ( 1 << ( h1a % 32 ) ) | ( 1 << ( h2b % 32 ) ) ;
1496- output [ 2 ] |= ( 1 << ( h2a % 32 ) ) | ( 1 << ( h0b % 32 ) ) ;
1497- fps . add ( input ) ;
1498- }
1499- for ( const g of type . generics ) {
1500- buildFunctionTypeFingerprint ( g , output , fps ) ;
1501- }
1502- const fb = {
1503- id : null ,
1504- ty : 0 ,
1505- generics : this . EMPTY_GENERICS_ARRAY ,
1506- bindings : this . EMPTY_BINDINGS_MAP ,
1507- } ;
1508- for ( const [ k , v ] of type . bindings . entries ( ) ) {
1509- fb . id = k ;
1510- fb . generics = v ;
1511- buildFunctionTypeFingerprint ( fb , output , fps ) ;
1512- }
1513- output [ 3 ] = fps . size ;
1514- }
1514+ } ;
15151515
1516- let searchIndex = [ ] ;
1516+ const searchIndex = [ ] ;
15171517 const charA = "A" . charCodeAt ( 0 ) ;
15181518 let currentIndex = 0 ;
15191519 let id = 0 ;
@@ -1526,7 +1526,7 @@ class DocSearch {
15261526 // does, too
15271527 id += crate . t . length + 1 ;
15281528 }
1529-
1529+ this . functionTypeFingerprint = new Uint32Array ( ( id + 1 ) * 4 ) ;
15301530 // This loop actually generates the search item indexes, including
15311531 // normalized names, type signature objects and fingerprints, and aliases.
15321532 id = 0 ;
@@ -1664,14 +1664,14 @@ class DocSearch {
16641664 const fp = this . functionTypeFingerprint . subarray ( id * 4 , ( id + 1 ) * 4 ) ;
16651665 const fps = new Set ( ) ;
16661666 for ( const t of type . inputs ) {
1667- buildFunctionTypeFingerprint ( t , fp , fps ) ;
1667+ this . buildFunctionTypeFingerprint ( t , fp , fps ) ;
16681668 }
16691669 for ( const t of type . output ) {
1670- buildFunctionTypeFingerprint ( t , fp , fps ) ;
1670+ this . buildFunctionTypeFingerprint ( t , fp , fps ) ;
16711671 }
16721672 for ( const w of type . where_clause ) {
16731673 for ( const t of w ) {
1674- buildFunctionTypeFingerprint ( t , fp , fps ) ;
1674+ this . buildFunctionTypeFingerprint ( t , fp , fps ) ;
16751675 }
16761676 }
16771677 }
@@ -2079,7 +2079,7 @@ class DocSearch {
20792079 }
20802080 }
20812081 return out ;
2082- }
2082+ } ;
20832083
20842084 /**
20852085 * This function takes a result map, and sorts it by various criteria, including edit
@@ -2090,7 +2090,7 @@ class DocSearch {
20902090 * @param {string } preferredCrate
20912091 * @returns {Promise<[ResultObject]> }
20922092 */
2093- const sortResults = async ( results , isType , preferredCrate ) => {
2093+ const sortResults = async ( results , isType , preferredCrate ) => {
20942094 const userQuery = parsedQuery . userQuery ;
20952095 const result_list = [ ] ;
20962096 for ( const result of results . values ( ) ) {
@@ -2193,7 +2193,7 @@ class DocSearch {
21932193 } ) ;
21942194
21952195 return transformResults ( result_list ) ;
2196- }
2196+ } ;
21972197
21982198 /**
21992199 * This function checks if a list of search query `queryElems` can all be found in the
@@ -2540,7 +2540,7 @@ class DocSearch {
25402540 }
25412541 return true ;
25422542 }
2543- }
2543+ } ;
25442544 /**
25452545 * This function checks the associated type bindings. Any that aren't matched get converted
25462546 * to generics, and this function returns an array of the function's generics with these
@@ -2741,7 +2741,7 @@ class DocSearch {
27412741 }
27422742 }
27432743 return unifyFunctionTypes ( [ row ] , [ elem ] , whereClause , mgens , null , unboxingDepth ) ;
2744- }
2744+ } ;
27452745
27462746 /**
27472747 * Compute an "edit distance" that ignores missing path elements.
@@ -2825,7 +2825,7 @@ class DocSearch {
28252825 } ;
28262826 }
28272827
2828- const handleAliases = async ( ret , query , filterCrates , currentCrate ) => {
2828+ const handleAliases = async ( ret , query , filterCrates , currentCrate ) => {
28292829 const lowerQuery = query . toLowerCase ( ) ;
28302830 // We separate aliases and crate aliases because we want to have current crate
28312831 // aliases to be before the others in the displayed results.
@@ -2892,7 +2892,7 @@ class DocSearch {
28922892 alias . desc = crateDescs [ i ] ;
28932893 } ) ;
28942894 crateAliases . forEach ( pushFunc ) ;
2895- }
2895+ } ;
28962896
28972897 /**
28982898 * This function adds the given result into the provided `results` map if it matches the
@@ -3106,7 +3106,7 @@ class DocSearch {
31063106 return null ;
31073107 }
31083108 return this . functionTypeFingerprint [ ( fullId * 4 ) + 3 ] ;
3109- }
3109+ } ;
31103110
31113111
31123112 const innerRunQuery = ( ) => {
@@ -3141,7 +3141,7 @@ class DocSearch {
31413141 let match = null ;
31423142 let matchDist = maxEditDistance + 1 ;
31433143 let matchName = "" ;
3144- for ( const [ name , { id, assocOnly } ] of typeNameIdMap ) {
3144+ for ( const [ name , { id, assocOnly } ] of this . typeNameIdMap ) {
31453145 const dist = editDistance ( name , elem . normalizedPathLast , maxEditDistance ) ;
31463146 if ( dist <= matchDist && dist <= maxEditDistance &&
31473147 ( isAssocType || ! assocOnly ) ) {
@@ -3220,22 +3220,23 @@ class DocSearch {
32203220 return [ this . typeNameIdMap . get ( name ) . id , constraints ] ;
32213221 } ) ,
32223222 ) ;
3223- }
3223+ } ;
32243224
32253225 const fps = new Set ( ) ;
32263226 for ( const elem of parsedQuery . elems ) {
32273227 convertNameToId ( elem ) ;
3228- buildFunctionTypeFingerprint ( elem , parsedQuery . typeFingerprint , fps ) ;
3228+ this . buildFunctionTypeFingerprint ( elem , parsedQuery . typeFingerprint , fps ) ;
32293229 }
32303230 for ( const elem of parsedQuery . returned ) {
32313231 convertNameToId ( elem ) ;
3232- buildFunctionTypeFingerprint ( elem , parsedQuery . typeFingerprint , fps ) ;
3232+ this . buildFunctionTypeFingerprint ( elem , parsedQuery . typeFingerprint , fps ) ;
32333233 }
32343234
32353235 if ( parsedQuery . foundElems === 1 && parsedQuery . returned . length === 0 ) {
32363236 if ( parsedQuery . elems . length === 1 ) {
32373237 const elem = parsedQuery . elems [ 0 ] ;
3238- for ( let i = 0 , nSearchIndex = searchIndex . length ; i < nSearchIndex ; ++ i ) {
3238+ const length = this . searchIndex . length ;
3239+ for ( let i = 0 , nSearchIndex = length ; i < nSearchIndex ; ++ i ) {
32393240 // It means we want to check for this element everywhere (in names, args and
32403241 // returned).
32413242 handleSingleArg (
@@ -3266,7 +3267,7 @@ class DocSearch {
32663267 } ;
32673268 parsedQuery . elems . sort ( sortQ ) ;
32683269 parsedQuery . returned . sort ( sortQ ) ;
3269- for ( let i = 0 , nSearchIndex = searchIndex . length ; i < nSearchIndex ; ++ i ) {
3270+ for ( let i = 0 , nSearchIndex = this . searchIndex . length ; i < nSearchIndex ; ++ i ) {
32703271 handleArgs ( this . searchIndex [ i ] , i , results_others ) ;
32713272 }
32723273 }
0 commit comments