66//------------------------------------------------------------------------------
77
88using System ;
9+ using System . Collections ;
910using System . Collections . Generic ;
1011using System . Diagnostics . Contracts ;
1112using System . Linq ;
@@ -38,11 +39,7 @@ public static bool HasAutoSelectProperty(this IEdmModel edmModel, IEdmStructured
3839 throw Error . ArgumentNull ( nameof ( structuredType ) ) ;
3940 }
4041
41- List < IEdmStructuredType > structuredTypes = new List < IEdmStructuredType > ( ) ;
42- structuredTypes . Add ( structuredType ) ;
43- structuredTypes . AddRange ( edmModel . FindAllDerivedTypes ( structuredType ) ) ;
44-
45- foreach ( IEdmStructuredType edmStructuredType in structuredTypes )
42+ foreach ( IEdmStructuredType edmStructuredType in new SelfAndDerivedEnumerator ( structuredType , edmModel ) )
4643 {
4744 // for top type, let's retrieve its properties and the properties from base type of top type if has.
4845 // for derived type, let's retrieve the declared properties.
@@ -92,11 +89,8 @@ private static bool HasAutoExpandProperty(this IEdmModel edmModel, IEdmStructure
9289 }
9390 visited . Add ( structuredType ) ;
9491
95- List < IEdmStructuredType > structuredTypes = new List < IEdmStructuredType > ( ) ;
96- structuredTypes . Add ( structuredType ) ;
97- structuredTypes . AddRange ( edmModel . FindAllDerivedTypes ( structuredType ) ) ;
9892
99- foreach ( IEdmStructuredType edmStructuredType in structuredTypes )
93+ foreach ( IEdmStructuredType edmStructuredType in new SelfAndDerivedEnumerator ( structuredType , edmModel ) )
10094 {
10195 // for top type, let's retrieve its properties and the properties from base type of top type if has.
10296 // for derived type, let's retrieve the declared properties.
@@ -144,7 +138,7 @@ private static bool HasAutoExpandProperty(this IEdmModel edmModel, IEdmStructure
144138 /// <param name="pathProperty">The property from path, it can be null.</param>
145139 /// <param name="querySettings">The query settings.</param>
146140 /// <returns>The auto select paths.</returns>
147- public static IList < SelectModelPath > GetAutoSelectPaths ( this IEdmModel edmModel , IEdmStructuredType structuredType ,
141+ public static IEnumerable < SelectModelPath > GetAutoSelectPaths ( this IEdmModel edmModel , IEdmStructuredType structuredType ,
148142 IEdmProperty pathProperty , ModelBoundQuerySettings querySettings = null )
149143 {
150144 if ( edmModel == null )
@@ -157,13 +151,8 @@ public static IList<SelectModelPath> GetAutoSelectPaths(this IEdmModel edmModel,
157151 throw Error . ArgumentNull ( nameof ( structuredType ) ) ;
158152 }
159153
160- List < SelectModelPath > autoSelectProperties = new List < SelectModelPath > ( ) ;
161-
162- List < IEdmStructuredType > structuredTypes = new List < IEdmStructuredType > ( ) ;
163- structuredTypes . Add ( structuredType ) ;
164- structuredTypes . AddRange ( edmModel . FindAllDerivedTypes ( structuredType ) ) ;
165-
166- foreach ( IEdmStructuredType edmStructuredType in structuredTypes )
154+ List < SelectModelPath > autoSelectProperties = null ;
155+ foreach ( IEdmStructuredType edmStructuredType in new SelfAndDerivedEnumerator ( structuredType , edmModel ) )
167156 {
168157 // for top type, let's retrieve its properties and the properties from base type of top type if has.
169158 // for derived type, let's retrieve the declared properties.
@@ -175,6 +164,11 @@ public static IList<SelectModelPath> GetAutoSelectPaths(this IEdmModel edmModel,
175164 {
176165 if ( IsAutoSelect ( property , pathProperty , edmStructuredType , edmModel , querySettings ) )
177166 {
167+ if ( autoSelectProperties == null )
168+ {
169+ autoSelectProperties = new List < SelectModelPath > ( 1 ) ;
170+ }
171+
178172 if ( edmStructuredType == structuredType )
179173 {
180174 autoSelectProperties . Add ( new SelectModelPath ( new [ ] { property } ) ) ;
@@ -187,7 +181,7 @@ public static IList<SelectModelPath> GetAutoSelectPaths(this IEdmModel edmModel,
187181 }
188182 }
189183
190- return autoSelectProperties ;
184+ return autoSelectProperties ?? Enumerable . Empty < SelectModelPath > ( ) ;
191185 }
192186
193187 /// <summary>
@@ -199,7 +193,7 @@ public static IList<SelectModelPath> GetAutoSelectPaths(this IEdmModel edmModel,
199193 /// <param name="isSelectPresent">Is $select presented.</param>
200194 /// <param name="querySettings">The query settings.</param>
201195 /// <returns>The auto expand paths.</returns>
202- public static IList < ExpandModelPath > GetAutoExpandPaths ( this IEdmModel edmModel , IEdmStructuredType structuredType ,
196+ public static IEnumerable < ExpandModelPath > GetAutoExpandPaths ( this IEdmModel edmModel , IEdmStructuredType structuredType ,
203197 IEdmProperty property , bool isSelectPresent = false , ModelBoundQuerySettings querySettings = null )
204198 {
205199 if ( edmModel == null )
@@ -290,11 +284,7 @@ private static void GetAutoExpandPaths(this IEdmModel edmModel, IEdmStructuredTy
290284 }
291285 visited . Add ( structuredType ) ;
292286
293- List < IEdmStructuredType > structuredTypes = new List < IEdmStructuredType > ( ) ;
294- structuredTypes . Add ( structuredType ) ;
295- structuredTypes . AddRange ( edmModel . FindAllDerivedTypes ( structuredType ) ) ;
296-
297- foreach ( IEdmStructuredType edmStructuredType in structuredTypes )
287+ foreach ( IEdmStructuredType edmStructuredType in new SelfAndDerivedEnumerator ( structuredType , edmModel ) )
298288 {
299289 IEnumerable < IEdmProperty > properties ;
300290
@@ -347,5 +337,103 @@ private static void GetAutoExpandPaths(this IEdmModel edmModel, IEdmStructuredTy
347337 }
348338 }
349339 }
340+
341+ /// <summary>
342+ /// This is a helper that allows us to avoid inefficiencies in the previous pattern:
343+ /// var structuredTypes = new List<IEdmStructuredType>();
344+ /// structuredTypes.Add(structuredType);
345+ /// structuredTypes.AddRange(edmModel.FindAllDerivedTypes(structuredType));
346+ ///
347+ /// Specifically, the allocation of the list and the resizing driven by the "AddRange" call are
348+ /// avoided by leveraging a struct with a simple state machine for enumerating over a type
349+ /// and its derived types.
350+ /// </summary>
351+ private struct SelfAndDerivedEnumerator : IEnumerator < IEdmStructuredType >
352+ {
353+ private enum Stage : byte
354+ {
355+ Initial ,
356+ Self ,
357+ Derived ,
358+ }
359+
360+ private readonly IEnumerator < IEdmStructuredType > derivedEnumerator ;
361+ private readonly IEdmStructuredType structuredType ;
362+
363+ private Stage stage ;
364+
365+ public SelfAndDerivedEnumerator ( IEdmStructuredType structuredType , IEdmModel edmModel )
366+ {
367+ if ( structuredType == null )
368+ {
369+ throw new ArgumentNullException ( nameof ( structuredType ) ) ;
370+ }
371+
372+ if ( edmModel == null )
373+ {
374+ throw new ArgumentNullException ( nameof ( edmModel ) ) ;
375+ }
376+
377+ this . stage = Stage . Initial ;
378+ this . derivedEnumerator = edmModel . FindAllDerivedTypes ( structuredType ) . GetEnumerator ( ) ;
379+ this . structuredType = structuredType ;
380+ }
381+
382+ public IEdmStructuredType Current
383+ {
384+ get
385+ {
386+ switch ( stage )
387+ {
388+ case Stage . Self :
389+ return this . structuredType ;
390+
391+ case Stage . Derived :
392+ return this . derivedEnumerator . Current ;
393+
394+ default :
395+ throw new InvalidOperationException ( "Enumeration is an invalid state" ) ;
396+ }
397+ }
398+ }
399+
400+ object IEnumerator . Current => this . Current ;
401+
402+ public void Dispose ( )
403+ {
404+ this . derivedEnumerator . Dispose ( ) ;
405+ }
406+
407+ public SelfAndDerivedEnumerator GetEnumerator ( )
408+ {
409+ return this ;
410+ }
411+
412+ public bool MoveNext ( )
413+ {
414+ switch ( this . stage )
415+ {
416+ case Stage . Initial :
417+ this . stage = Stage . Self ;
418+ return true ;
419+
420+ case Stage . Self :
421+ this . stage = Stage . Derived ;
422+ goto case Stage . Derived ;
423+
424+ case Stage . Derived :
425+ return this . derivedEnumerator . MoveNext ( ) ;
426+
427+ default :
428+ return false ;
429+ }
430+ }
431+
432+ public void Reset ( )
433+ {
434+ this . stage = Stage . Initial ;
435+ this . derivedEnumerator . Reset ( ) ;
436+ }
437+ }
350438 }
351439}
0 commit comments