@@ -2725,17 +2725,25 @@ ${item.displayPath}<span class="${type}">${name}</span>\
27252725 /**
27262726 * Empty, immutable map used in item search types with no bindings.
27272727 *
2728- * @type {Map<integer , Array<Functiontype >> }
2728+ * @type {Map<number , Array<FunctionType >> }
27292729 */
27302730 const EMPTY_BINDINGS_MAP = new Map ( ) ;
27312731
27322732 /**
27332733 * Empty, immutable map used in item search types with no bindings.
27342734 *
2735- * @type {Array<Functiontype > }
2735+ * @type {Array<FunctionType > }
27362736 */
27372737 const EMPTY_GENERICS_ARRAY = [ ] ;
27382738
2739+ /**
2740+ * Object pool for function types with no bindings or generics.
2741+ * This is reset after loading the index.
2742+ *
2743+ * @type {Map<number|null, FunctionType> }
2744+ */
2745+ let TYPES_POOL = new Map ( ) ;
2746+
27392747 /**
27402748 * Converts a single type.
27412749 *
@@ -2778,35 +2786,80 @@ ${item.displayPath}<span class="${type}">${name}</span>\
27782786 bindings = EMPTY_BINDINGS_MAP ;
27792787 }
27802788 }
2789+ /**
2790+ * @type {FunctionType }
2791+ */
2792+ let result ;
27812793 if ( pathIndex < 0 ) {
27822794 // types less than 0 are generic parameters
27832795 // the actual names of generic parameters aren't stored, since they aren't API
2784- return {
2796+ result = {
27852797 id : pathIndex ,
27862798 ty : TY_GENERIC ,
27872799 path : null ,
27882800 generics,
27892801 bindings,
27902802 } ;
2791- }
2792- if ( pathIndex === 0 ) {
2803+ } else if ( pathIndex === 0 ) {
27932804 // `0` is used as a sentinel because it's fewer bytes than `null`
2794- return {
2805+ result = {
27952806 id : null ,
27962807 ty : null ,
27972808 path : null ,
27982809 generics,
27992810 bindings,
28002811 } ;
2812+ } else {
2813+ const item = lowercasePaths [ pathIndex - 1 ] ;
2814+ result = {
2815+ id : buildTypeMapIndex ( item . name , isAssocType ) ,
2816+ ty : item . ty ,
2817+ path : item . path ,
2818+ generics,
2819+ bindings,
2820+ } ;
28012821 }
2802- const item = lowercasePaths [ pathIndex - 1 ] ;
2803- return {
2804- id : buildTypeMapIndex ( item . name , isAssocType ) ,
2805- ty : item . ty ,
2806- path : item . path ,
2807- generics,
2808- bindings,
2809- } ;
2822+ const cr = TYPES_POOL . get ( result . id ) ;
2823+ if ( cr ) {
2824+ // Shallow equality check. Since this function is used
2825+ // to construct every type object, this should be mostly
2826+ // equivalent to a deep equality check, except if there's
2827+ // a conflict, we don't keep the old one around, so it's
2828+ // not a fully precise implementation of hashcons.
2829+ if ( cr . generics . length === result . generics . length &&
2830+ cr . generics !== result . generics &&
2831+ cr . generics . every ( ( x , i ) => result . generics [ i ] === x )
2832+ ) {
2833+ result . generics = cr . generics ;
2834+ }
2835+ if ( cr . bindings . size === result . bindings . size && cr . bindings !== result . bindings ) {
2836+ let ok = true ;
2837+ for ( const [ k , v ] of cr . bindings . entries ( ) ) {
2838+ const v2 = result . bindings . get ( v ) ;
2839+ if ( ! v2 ) {
2840+ ok = false ;
2841+ break ;
2842+ }
2843+ if ( v !== v2 && v . length === v2 . length && v . every ( ( x , i ) => v2 [ i ] === x ) ) {
2844+ result . bindings . set ( k , v ) ;
2845+ } else if ( v !== v2 ) {
2846+ ok = false ;
2847+ break ;
2848+ }
2849+ }
2850+ if ( ok ) {
2851+ result . bindings = cr . bindings ;
2852+ }
2853+ }
2854+ if ( cr . ty === result . ty && cr . path === result . path
2855+ && cr . bindings === result . bindings && cr . generics === result . generics
2856+ && cr . ty === result . ty
2857+ ) {
2858+ return cr ;
2859+ }
2860+ }
2861+ TYPES_POOL . set ( result . id , result ) ;
2862+ return result ;
28102863 }
28112864
28122865 /**
@@ -2817,7 +2870,7 @@ ${item.displayPath}<span class="${type}">${name}</span>\
28172870 * object-based encoding so that the actual search code is more readable and easier to debug.
28182871 *
28192872 * The raw function search type format is generated using serde in
2820- * librustdoc/html/render/mod.rs: impl Serialize for IndexItemFunctionType
2873+ * librustdoc/html/render/mod.rs: IndexItemFunctionType::write_to_string
28212874 *
28222875 * @param {{
28232876 * string: string,
@@ -2986,8 +3039,8 @@ ${item.displayPath}<span class="${type}">${name}</span>\
29863039 const fb = {
29873040 id : null ,
29883041 ty : 0 ,
2989- generics : [ ] ,
2990- bindings : new Map ( ) ,
3042+ generics : EMPTY_GENERICS_ARRAY ,
3043+ bindings : EMPTY_BINDINGS_MAP ,
29913044 } ;
29923045 for ( const [ k , v ] of type . bindings . entries ( ) ) {
29933046 fb . id = k ;
@@ -3215,6 +3268,8 @@ ${item.displayPath}<span class="${type}">${name}</span>\
32153268 }
32163269 currentIndex += itemTypes . length ;
32173270 }
3271+ // Drop the (rather large) hash table used for reusing function items
3272+ TYPES_POOL = new Map ( ) ;
32183273 }
32193274
32203275 /**
0 commit comments