@@ -1106,7 +1106,7 @@ class DocSearch {
1106
1106
/**
1107
1107
* @type {Uint32Array }
1108
1108
*/
1109
- this . functionTypeFingerprint = new Uint32Array ( ( id + 1 ) * 4 ) ;
1109
+ this . functionTypeFingerprint = null ;
1110
1110
/**
1111
1111
* Map from normalized type names to integers. Used to make type search
1112
1112
* more efficient.
@@ -1182,7 +1182,7 @@ class DocSearch {
1182
1182
/**
1183
1183
* @type {Array<Row> }
1184
1184
*/
1185
- this . searchIndex = buildIndex ( rawSearchIndex ) ;
1185
+ this . searchIndex = this . buildIndex ( rawSearchIndex ) ;
1186
1186
}
1187
1187
1188
1188
/**
@@ -1359,6 +1359,91 @@ class DocSearch {
1359
1359
return result ;
1360
1360
}
1361
1361
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
+
1362
1447
/**
1363
1448
* Convert raw search index into in-memory search index.
1364
1449
*
@@ -1390,7 +1475,7 @@ class DocSearch {
1390
1475
let inputs , output ;
1391
1476
if ( typeof functionSearchType [ INPUTS_DATA ] === "number" ) {
1392
1477
inputs = [
1393
- this . buildItemSearchType ( functionSearchType [ INPUTS_DATA ] , lowercasePaths )
1478
+ this . buildItemSearchType ( functionSearchType [ INPUTS_DATA ] , lowercasePaths ) ,
1394
1479
] ;
1395
1480
} else {
1396
1481
inputs = this . buildItemSearchTypeAll (
@@ -1404,7 +1489,7 @@ class DocSearch {
1404
1489
this . buildItemSearchType (
1405
1490
functionSearchType [ OUTPUT_DATA ] ,
1406
1491
lowercasePaths ,
1407
- )
1492
+ ) ,
1408
1493
] ;
1409
1494
} else {
1410
1495
output = this . buildItemSearchTypeAll (
@@ -1426,94 +1511,9 @@ class DocSearch {
1426
1511
inputs, output, where_clause,
1427
1512
} ;
1428
1513
} ;
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
+ } ;
1515
1515
1516
- let searchIndex = [ ] ;
1516
+ const searchIndex = [ ] ;
1517
1517
const charA = "A" . charCodeAt ( 0 ) ;
1518
1518
let currentIndex = 0 ;
1519
1519
let id = 0 ;
@@ -1526,7 +1526,7 @@ class DocSearch {
1526
1526
// does, too
1527
1527
id += crate . t . length + 1 ;
1528
1528
}
1529
-
1529
+ this . functionTypeFingerprint = new Uint32Array ( ( id + 1 ) * 4 ) ;
1530
1530
// This loop actually generates the search item indexes, including
1531
1531
// normalized names, type signature objects and fingerprints, and aliases.
1532
1532
id = 0 ;
@@ -1664,14 +1664,14 @@ class DocSearch {
1664
1664
const fp = this . functionTypeFingerprint . subarray ( id * 4 , ( id + 1 ) * 4 ) ;
1665
1665
const fps = new Set ( ) ;
1666
1666
for ( const t of type . inputs ) {
1667
- buildFunctionTypeFingerprint ( t , fp , fps ) ;
1667
+ this . buildFunctionTypeFingerprint ( t , fp , fps ) ;
1668
1668
}
1669
1669
for ( const t of type . output ) {
1670
- buildFunctionTypeFingerprint ( t , fp , fps ) ;
1670
+ this . buildFunctionTypeFingerprint ( t , fp , fps ) ;
1671
1671
}
1672
1672
for ( const w of type . where_clause ) {
1673
1673
for ( const t of w ) {
1674
- buildFunctionTypeFingerprint ( t , fp , fps ) ;
1674
+ this . buildFunctionTypeFingerprint ( t , fp , fps ) ;
1675
1675
}
1676
1676
}
1677
1677
}
@@ -2079,7 +2079,7 @@ class DocSearch {
2079
2079
}
2080
2080
}
2081
2081
return out ;
2082
- }
2082
+ } ;
2083
2083
2084
2084
/**
2085
2085
* This function takes a result map, and sorts it by various criteria, including edit
@@ -2090,7 +2090,7 @@ class DocSearch {
2090
2090
* @param {string } preferredCrate
2091
2091
* @returns {Promise<[ResultObject]> }
2092
2092
*/
2093
- const sortResults = async ( results , isType , preferredCrate ) => {
2093
+ const sortResults = async ( results , isType , preferredCrate ) => {
2094
2094
const userQuery = parsedQuery . userQuery ;
2095
2095
const result_list = [ ] ;
2096
2096
for ( const result of results . values ( ) ) {
@@ -2193,7 +2193,7 @@ class DocSearch {
2193
2193
} ) ;
2194
2194
2195
2195
return transformResults ( result_list ) ;
2196
- }
2196
+ } ;
2197
2197
2198
2198
/**
2199
2199
* This function checks if a list of search query `queryElems` can all be found in the
@@ -2540,7 +2540,7 @@ class DocSearch {
2540
2540
}
2541
2541
return true ;
2542
2542
}
2543
- }
2543
+ } ;
2544
2544
/**
2545
2545
* This function checks the associated type bindings. Any that aren't matched get converted
2546
2546
* to generics, and this function returns an array of the function's generics with these
@@ -2741,7 +2741,7 @@ class DocSearch {
2741
2741
}
2742
2742
}
2743
2743
return unifyFunctionTypes ( [ row ] , [ elem ] , whereClause , mgens , null , unboxingDepth ) ;
2744
- }
2744
+ } ;
2745
2745
2746
2746
/**
2747
2747
* Compute an "edit distance" that ignores missing path elements.
@@ -2825,7 +2825,7 @@ class DocSearch {
2825
2825
} ;
2826
2826
}
2827
2827
2828
- const handleAliases = async ( ret , query , filterCrates , currentCrate ) => {
2828
+ const handleAliases = async ( ret , query , filterCrates , currentCrate ) => {
2829
2829
const lowerQuery = query . toLowerCase ( ) ;
2830
2830
// We separate aliases and crate aliases because we want to have current crate
2831
2831
// aliases to be before the others in the displayed results.
@@ -2892,7 +2892,7 @@ class DocSearch {
2892
2892
alias . desc = crateDescs [ i ] ;
2893
2893
} ) ;
2894
2894
crateAliases . forEach ( pushFunc ) ;
2895
- }
2895
+ } ;
2896
2896
2897
2897
/**
2898
2898
* This function adds the given result into the provided `results` map if it matches the
@@ -3106,7 +3106,7 @@ class DocSearch {
3106
3106
return null ;
3107
3107
}
3108
3108
return this . functionTypeFingerprint [ ( fullId * 4 ) + 3 ] ;
3109
- }
3109
+ } ;
3110
3110
3111
3111
3112
3112
const innerRunQuery = ( ) => {
@@ -3141,7 +3141,7 @@ class DocSearch {
3141
3141
let match = null ;
3142
3142
let matchDist = maxEditDistance + 1 ;
3143
3143
let matchName = "" ;
3144
- for ( const [ name , { id, assocOnly } ] of typeNameIdMap ) {
3144
+ for ( const [ name , { id, assocOnly } ] of this . typeNameIdMap ) {
3145
3145
const dist = editDistance ( name , elem . normalizedPathLast , maxEditDistance ) ;
3146
3146
if ( dist <= matchDist && dist <= maxEditDistance &&
3147
3147
( isAssocType || ! assocOnly ) ) {
@@ -3220,22 +3220,23 @@ class DocSearch {
3220
3220
return [ this . typeNameIdMap . get ( name ) . id , constraints ] ;
3221
3221
} ) ,
3222
3222
) ;
3223
- }
3223
+ } ;
3224
3224
3225
3225
const fps = new Set ( ) ;
3226
3226
for ( const elem of parsedQuery . elems ) {
3227
3227
convertNameToId ( elem ) ;
3228
- buildFunctionTypeFingerprint ( elem , parsedQuery . typeFingerprint , fps ) ;
3228
+ this . buildFunctionTypeFingerprint ( elem , parsedQuery . typeFingerprint , fps ) ;
3229
3229
}
3230
3230
for ( const elem of parsedQuery . returned ) {
3231
3231
convertNameToId ( elem ) ;
3232
- buildFunctionTypeFingerprint ( elem , parsedQuery . typeFingerprint , fps ) ;
3232
+ this . buildFunctionTypeFingerprint ( elem , parsedQuery . typeFingerprint , fps ) ;
3233
3233
}
3234
3234
3235
3235
if ( parsedQuery . foundElems === 1 && parsedQuery . returned . length === 0 ) {
3236
3236
if ( parsedQuery . elems . length === 1 ) {
3237
3237
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 ) {
3239
3240
// It means we want to check for this element everywhere (in names, args and
3240
3241
// returned).
3241
3242
handleSingleArg (
@@ -3266,7 +3267,7 @@ class DocSearch {
3266
3267
} ;
3267
3268
parsedQuery . elems . sort ( sortQ ) ;
3268
3269
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 ) {
3270
3271
handleArgs ( this . searchIndex [ i ] , i , results_others ) ;
3271
3272
}
3272
3273
}
0 commit comments