1- using Microsoft . Extensions . Primitives ;
1+ // Ignore Spelling: Deconstruct
2+
3+ using Microsoft . Extensions . Primitives ;
24using System ;
35using System . Collections . Concurrent ;
46using System . Collections . Generic ;
911using System . Runtime . CompilerServices ;
1012using System . Threading ;
1113using static System . Linq . Expressions . Expression ;
12-
14+ //using static FastExpressionCompiler.LightExpression.Expression;
1315namespace Open . Text ;
1416
1517/// <summary>
@@ -83,7 +85,7 @@ static Func<TEnum, string> GetEnumNameDelegate()
8385 Default ( tResult )
8486 ) ,
8587 null ,
86- Values . Select ( v => SwitchCase (
88+ Values . OrderBy ( v => string . Intern ( v . ToString ( ) ) ) . Select ( v => SwitchCase (
8789 Constant ( string . Intern ( v . ToString ( ) ) ) ,
8890 Constant ( v )
8991 ) ) . ToArray ( )
@@ -93,41 +95,46 @@ static Func<TEnum, string> GetEnumNameDelegate()
9395 private static Func < TEnum , string > ? _nameLookup ;
9496 internal static Func < TEnum , string > NameLookup
9597 => LazyInitializer . EnsureInitialized ( ref _nameLookup ,
96- ( ) => GetEnumNameDelegate ( ) ) ! ;
98+ GetEnumNameDelegate ) ! ;
9799 internal static Func < string , ValueLookupResult > GetEnumTryParseDelegate ( )
98100 {
99101 var valueParam = Parameter ( typeof ( string ) , "value" ) ;
102+ var lengthParam = Variable ( typeof ( int ) , "length" ) ;
100103 var defaultExpression = CreateNewTuple ( false , default ! ) ;
101104 var enumValues = Values . Select ( v => ( value : v , name : string . Intern ( v . ToString ( ) ) ) ) ;
102- var nameGroups = enumValues . GroupBy ( v => v . name . Length ) ;
105+ var nameGroups = enumValues . GroupBy ( v => v . name . Length ) . OrderBy ( g => g . Key ) ;
103106 var lengthCheckCases = nameGroups . Select ( group =>
104107 SwitchCase (
105108 Switch (
106109 valueParam ,
107110 defaultExpression ,
108111 null ,
109- group . Select ( v => SwitchCase (
112+ group . OrderBy ( v => v . name ) . Select ( v => SwitchCase (
110113 CreateNewTuple ( true , v . value ) ,
111114 Constant ( v . name )
112- ) ) . ToArray ( )
115+ ) )
116+ . ToArray ( )
113117 ) ,
114118 Constant ( group . Key )
115119 )
116120 ) . ToArray ( ) ;
117121
118122 return Lambda < Func < string , ValueLookupResult > > (
119- Switch (
120- Property ( valueParam , nameof ( string . Length ) ) ,
121- defaultExpression ,
122- null ,
123- lengthCheckCases
123+ Block ( new [ ] { lengthParam } ,
124+ Assign ( lengthParam , Property ( valueParam , nameof ( string . Length ) ) ) ,
125+ Switch (
126+ lengthParam ,
127+ defaultExpression ,
128+ null ,
129+ lengthCheckCases
130+ )
124131 ) ,
125132 valueParam
126133 ) . Compile ( ) ;
127134
128135 static Expression CreateNewTuple ( bool success , TEnum value )
129136 => New (
130- typeof ( ValueLookupResult ) . GetConstructor ( new [ ] { typeof ( bool ) , typeof ( TEnum ) } ) ,
137+ typeof ( ValueLookupResult ) . GetConstructor ( new [ ] { typeof ( bool ) , typeof ( TEnum ) } ) ! ,
131138 Constant ( success ) ,
132139 Constant ( value )
133140 ) ;
@@ -153,8 +160,12 @@ public void Deconstruct(out bool success, out TEnum value)
153160
154161 private static Func < string , ValueLookupResult > ? _valueLookup ;
155162 internal static Func < string , ValueLookupResult > ValueLookup
156- => LazyInitializer . EnsureInitialized ( ref _valueLookup ,
157- ( ) => GetEnumTryParseDelegate ( ) ) ! ;
163+ => LazyInitializer . EnsureInitialized ( ref _valueLookup , GetEnumTryParseDelegate ) ! ;
164+
165+ private static IReadOnlyDictionary < string , TEnum > ? _ignoreCaseLookup ;
166+ internal static IReadOnlyDictionary < string , TEnum > IgnoreCaseLookup
167+ => LazyInitializer . EnsureInitialized ( ref _ignoreCaseLookup ,
168+ ( ) => Values . ToDictionary ( e => Enum . GetName ( typeof ( TEnum ) , e ) ! , e => e , StringComparer . OrdinalIgnoreCase ) ) ! ;
158169
159170 static Entry [ ] ? [ ] CreateLookup ( )
160171 {
@@ -484,6 +495,7 @@ public static class EnumValue
484495 /// <returns>The enum that represents the string <paramref name="value"/> provided.</returns>
485496 /// <exception cref="ArgumentException">Requested <paramref name="value"/> was not found.</exception>
486497 /// <inheritdoc cref="TryParse{TEnum}(StringSegment, bool, out TEnum)"/>
498+ [ MethodImpl ( MethodImplOptions . AggressiveInlining ) ]
487499 public static TEnum Parse < TEnum > ( string value )
488500 where TEnum : Enum
489501 {
@@ -493,6 +505,7 @@ public static TEnum Parse<TEnum>(string value)
493505 }
494506
495507 /// <inheritdoc cref="TryParse{TEnum}(StringSegment, out TEnum)"/>
508+ [ MethodImpl ( MethodImplOptions . AggressiveInlining ) ]
496509 public static bool TryParse < TEnum > ( string value , out TEnum e )
497510 where TEnum : Enum
498511 {
@@ -505,30 +518,54 @@ public static bool TryParse<TEnum>(string value, out TEnum e)
505518 /// <exception cref="ArgumentNullException"><paramref name="value"/> is null.</exception>
506519 /// <exception cref="ArgumentException">Requested <paramref name="value"/> was not found.</exception>
507520 /// <inheritdoc cref="TryParse{TEnum}(StringSegment, bool, out TEnum)"/>
521+ [ MethodImpl ( MethodImplOptions . AggressiveInlining ) ]
508522 public static TEnum Parse < TEnum > ( StringSegment value )
509523 where TEnum : Enum
510524 => TryParse < TEnum > ( value , false , out var e ) ? e
511525 : throw new ArgumentException ( string . Format ( NotFoundMessage , value ) , nameof ( value ) ) ;
512526
513527 /// <inheritdoc cref="TryParse{TEnum}(StringSegment, bool, out TEnum)"/>
528+ [ MethodImpl ( MethodImplOptions . AggressiveInlining ) ]
514529 public static TEnum Parse < TEnum > ( string value , bool ignoreCase )
515530 where TEnum : Enum
516531 => ignoreCase
517- ? TryParse < TEnum > ( value , ignoreCase , out var e ) ? e
532+ ? EnumValue < TEnum > . IgnoreCaseLookup . TryGetValue ( value , out var e ) ? e
518533 : throw new ArgumentException ( string . Format ( NotFoundMessage , value ) , nameof ( value ) )
519534 : Parse < TEnum > ( value ) ;
520535
521536 /// <inheritdoc cref="TryParse{TEnum}(StringSegment, bool, out TEnum)"/>
537+ [ MethodImpl ( MethodImplOptions . AggressiveInlining ) ]
522538 public static TEnum Parse < TEnum > ( StringSegment value , bool ignoreCase )
523539 where TEnum : Enum
524- => TryParse < TEnum > ( value , ignoreCase , out var e ) ? e
525- : throw new ArgumentException ( string . Format ( NotFoundMessage , value ) , nameof ( value ) ) ;
540+ {
541+ var buffer = value . Buffer ?? throw new ArgumentNullException ( nameof ( value ) ) ;
542+ return value . Length == buffer . Length
543+ ? Parse < TEnum > ( value . Buffer , ignoreCase )
544+ : TryParse < TEnum > ( value , ignoreCase , out var e )
545+ ? e : throw new ArgumentException ( string . Format ( NotFoundMessage , value ) , nameof ( value ) ) ;
546+ }
526547
527548 /// <inheritdoc cref="TryParse{TEnum}(StringSegment, bool, out TEnum)"/>
549+ [ MethodImpl ( MethodImplOptions . AggressiveInlining ) ]
528550 public static bool TryParse < TEnum > ( StringSegment value , out TEnum e )
529551 where TEnum : Enum
530552 => TryParse ( value , false , out e ) ;
531553
554+ /// <inheritdoc cref="TryParse{TEnum}(StringSegment, bool, out TEnum)"/>
555+ [ MethodImpl ( MethodImplOptions . AggressiveInlining ) ]
556+ public static bool TryParse < TEnum > ( string name , bool ignoreCase , out TEnum e )
557+ where TEnum : Enum
558+ => ignoreCase
559+ ? EnumValue < TEnum > . IgnoreCaseLookup . TryGetValue ( name , out e )
560+ : TryParse ( name , out e ) ;
561+
562+ /// <inheritdoc cref="TryParse{TEnum}(StringSegment, bool, out TEnum)"/>
563+ /// <remarks>Can be slightly faster than other ignore-case methods.</remarks>
564+ [ MethodImpl ( MethodImplOptions . AggressiveInlining ) ]
565+ public static bool TryParseIgnoreCase < TEnum > ( string name , out TEnum e )
566+ where TEnum : Enum
567+ => EnumValue < TEnum > . IgnoreCaseLookup . TryGetValue ( name , out e ) ;
568+
532569 /// <summary>
533570 /// Converts the string representation of the name of one or more enumerated constants to an equivalent enumerated object.
534571 /// </summary>
@@ -543,8 +580,9 @@ public static bool TryParse<TEnum>(StringSegment name, bool ignoreCase, out TEnu
543580 if ( len == 0 ) goto notFound ;
544581
545582 // If this is a string, use the optimized version.
546- if ( ! ignoreCase && name . Buffer ! . Length == len )
547- return TryParse ( name . Buffer , out e ) ;
583+ string buffer = name . Buffer ! ;
584+ if ( buffer . Length == len )
585+ return TryParse ( buffer , ignoreCase , out e ) ;
548586
549587 var lookup = EnumValue < TEnum > . Lookup ;
550588 if ( len >= lookup . Length ) goto notFound ;
0 commit comments