@@ -2725,17 +2725,25 @@ ${item.displayPath}<span class="${type}">${name}</span>\
2725
2725
/**
2726
2726
* Empty, immutable map used in item search types with no bindings.
2727
2727
*
2728
- * @type {Map<integer , Array<Functiontype >> }
2728
+ * @type {Map<number , Array<FunctionType >> }
2729
2729
*/
2730
2730
const EMPTY_BINDINGS_MAP = new Map ( ) ;
2731
2731
2732
2732
/**
2733
2733
* Empty, immutable map used in item search types with no bindings.
2734
2734
*
2735
- * @type {Array<Functiontype > }
2735
+ * @type {Array<FunctionType > }
2736
2736
*/
2737
2737
const EMPTY_GENERICS_ARRAY = [ ] ;
2738
2738
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
+
2739
2747
/**
2740
2748
* Converts a single type.
2741
2749
*
@@ -2778,35 +2786,80 @@ ${item.displayPath}<span class="${type}">${name}</span>\
2778
2786
bindings = EMPTY_BINDINGS_MAP ;
2779
2787
}
2780
2788
}
2789
+ /**
2790
+ * @type {FunctionType }
2791
+ */
2792
+ let result ;
2781
2793
if ( pathIndex < 0 ) {
2782
2794
// types less than 0 are generic parameters
2783
2795
// the actual names of generic parameters aren't stored, since they aren't API
2784
- return {
2796
+ result = {
2785
2797
id : pathIndex ,
2786
2798
ty : TY_GENERIC ,
2787
2799
path : null ,
2788
2800
generics,
2789
2801
bindings,
2790
2802
} ;
2791
- }
2792
- if ( pathIndex === 0 ) {
2803
+ } else if ( pathIndex === 0 ) {
2793
2804
// `0` is used as a sentinel because it's fewer bytes than `null`
2794
- return {
2805
+ result = {
2795
2806
id : null ,
2796
2807
ty : null ,
2797
2808
path : null ,
2798
2809
generics,
2799
2810
bindings,
2800
2811
} ;
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
+ } ;
2801
2821
}
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 ;
2810
2863
}
2811
2864
2812
2865
/**
@@ -2817,7 +2870,7 @@ ${item.displayPath}<span class="${type}">${name}</span>\
2817
2870
* object-based encoding so that the actual search code is more readable and easier to debug.
2818
2871
*
2819
2872
* 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
2821
2874
*
2822
2875
* @param {{
2823
2876
* string: string,
@@ -2986,8 +3039,8 @@ ${item.displayPath}<span class="${type}">${name}</span>\
2986
3039
const fb = {
2987
3040
id : null ,
2988
3041
ty : 0 ,
2989
- generics : [ ] ,
2990
- bindings : new Map ( ) ,
3042
+ generics : EMPTY_GENERICS_ARRAY ,
3043
+ bindings : EMPTY_BINDINGS_MAP ,
2991
3044
} ;
2992
3045
for ( const [ k , v ] of type . bindings . entries ( ) ) {
2993
3046
fb . id = k ;
@@ -3215,6 +3268,8 @@ ${item.displayPath}<span class="${type}">${name}</span>\
3215
3268
}
3216
3269
currentIndex += itemTypes . length ;
3217
3270
}
3271
+ // Drop the (rather large) hash table used for reusing function items
3272
+ TYPES_POOL = new Map ( ) ;
3218
3273
}
3219
3274
3220
3275
/**
0 commit comments