@@ -18,7 +18,8 @@ namespace NuGet.Protocol.Core.Types
1818 /// </summary>
1919 public class SourceRepository
2020 {
21- private readonly Dictionary < Type , INuGetResourceProvider [ ] > _providerCache ;
21+ internal const int ProviderCacheTypes = 25 ;
22+ private readonly Dictionary < Type , IReadOnlyList < INuGetResourceProvider > > _providerCache ;
2223 private readonly PackageSource _source ;
2324
2425 /// <summary>
@@ -150,12 +151,13 @@ public virtual async Task<T> GetResourceAsync<T>() where T : class, INuGetResour
150151 public virtual async Task < T > GetResourceAsync < T > ( CancellationToken token ) where T : class , INuGetResource
151152 {
152153 var resourceType = typeof ( T ) ;
153- INuGetResourceProvider [ ] possible = null ;
154+ IReadOnlyList < INuGetResourceProvider > possible ;
154155
155156 if ( _providerCache . TryGetValue ( resourceType , out possible ) )
156157 {
157- foreach ( var provider in possible )
158+ for ( int i = 0 ; i < possible . Count ; i ++ )
158159 {
160+ var provider = possible [ i ] ;
159161 var result = await provider . TryCreate ( this , token ) ;
160162 if ( result . Item1 )
161163 {
@@ -172,47 +174,59 @@ public virtual async Task<T> GetResourceAsync<T>(CancellationToken token) where
172174 /// </summary>
173175 /// <param name="providers"></param>
174176 /// <returns></returns>
175- private static Dictionary < Type , INuGetResourceProvider [ ] > Init ( IEnumerable < Lazy < INuGetResourceProvider > > providers )
177+ private static Dictionary < Type , IReadOnlyList < INuGetResourceProvider > > Init ( IEnumerable < Lazy < INuGetResourceProvider > > providers )
176178 {
177- var cache = new Dictionary < Type , INuGetResourceProvider [ ] > ( ) ;
179+ var cache = new Dictionary < Type , IReadOnlyList < INuGetResourceProvider > > ( ProviderCacheTypes ) ;
178180
179181 foreach ( var group in providers . GroupBy ( p => p . Value . ResourceType ) )
180182 {
181- cache . Add ( group . Key , Sort ( group ) . ToArray ( ) ) ;
183+ cache . Add ( group . Key , Sort ( group ) ) ;
182184 }
183185
184186 return cache ;
185187 }
186188
187- private static INuGetResourceProvider [ ]
189+ private static IReadOnlyList < INuGetResourceProvider >
188190 Sort ( IEnumerable < Lazy < INuGetResourceProvider > > group )
189191 {
192+ var items = new List < INuGetResourceProvider > ( group . Count ( ) ) ;
193+ foreach ( var lazy in group )
194+ {
195+ items . Add ( lazy . Value ) ;
196+ }
197+
190198 // initial ordering to help make this deterministic
191- var items = new List < INuGetResourceProvider > (
192- group . Select ( e => e . Value ) . OrderBy ( e => e . Name ) . ThenBy ( e => e . After . Count ( ) ) . ThenBy ( e => e . Before . Count ( ) ) ) ;
199+ items . Sort ( ( a , b ) =>
200+ {
201+ int cmp = StringComparer . Ordinal . Compare ( a . Name , b . Name ) ;
202+ if ( cmp != 0 ) return cmp ;
203+ cmp = a . After . Count ( ) . CompareTo ( b . After . Count ( ) ) ;
204+ if ( cmp != 0 ) return cmp ;
205+ return a . Before . Count ( ) . CompareTo ( b . Before . Count ( ) ) ;
206+ } ) ;
193207
194208 var comparer = ProviderComparer . Instance ;
195209
196- var ordered = new Queue < INuGetResourceProvider > ( ) ;
197-
198210 // List.Sort does not work when lists have unsolvable gaps, which can occur here
199- while ( items . Count > 0 )
211+ for ( int start = 0 ; start < items . Count - 1 ; start ++ )
200212 {
201- var best = items [ 0 ] ;
213+ int bestIndex = start ;
202214
203- for ( var i = 1 ; i < items . Count ; i ++ )
215+ for ( int i = start + 1 ; i < items . Count ; i ++ )
204216 {
205- if ( comparer . Compare ( items [ i ] , best ) < 0 )
217+ if ( comparer . Compare ( items [ i ] , items [ bestIndex ] ) < 0 )
206218 {
207- best = items [ i ] ;
219+ bestIndex = i ;
208220 }
209221 }
210222
211- items . Remove ( best ) ;
212- ordered . Enqueue ( best ) ;
223+ if ( bestIndex != start )
224+ {
225+ ( items [ start ] , items [ bestIndex ] ) = ( items [ bestIndex ] , items [ start ] ) ;
226+ }
213227 }
214228
215- return ordered . ToArray ( ) ;
229+ return items ;
216230 }
217231
218232 /// <summary>
0 commit comments