@@ -19,7 +19,7 @@ internal static class EnumInfo<T> where T : unmanaged, Enum
1919 /// <summary>
2020 /// All enum values sorted in increasing order (unstable sort)
2121 /// </summary>
22- public static IReadOnlyList < T > All => _all ;
22+ public static IReadOnlyList < T > AllValuesOrdered => _allValuesOrdered ;
2323
2424 /// <summary>
2525 /// All enum values with distinct numerical values sorted in increasing order.
@@ -43,9 +43,8 @@ internal static class EnumInfo<T> where T : unmanaged, Enum
4343 /// </summary>
4444 public static readonly Type UnderlyingType = typeof ( T ) . GetEnumUnderlyingType ( ) ;
4545
46- private static readonly T [ ] _all ;
47- private static readonly string [ ] _names ;
48- private static readonly Dictionary < T , int > _numericallyDistinctValues ;
46+ private static readonly T [ ] _allValuesOrdered ;
47+ private static readonly Dictionary < T , int > _numericallyDistinctIndices ;
4948 private static readonly ulong [ ] _allEnumValuesRaw ;
5049 private static readonly bool _unnamedAreIndexable ;
5150
@@ -127,61 +126,23 @@ static unsafe EnumInfo()
127126 throw new InvalidOperationException ( "Enum provided uses an unknown numeric base??" ) ;
128127 }
129128
130-
131- var names = new string [ all . Length ] ;
132- for ( var index = 0 ; index < all . Length ; index++ )
133- {
134- names[ index ] = all [ index ] . ToString ( ) ; // todo: readable name attributes?
135- }
136-
137129 var dict = new Dictionary < T , int > ( vals . Length ) ;
138- for ( var i = 0 ; i < vals . Length ; i ++ )
130+ for ( var index = 0 ; index < vals . Length ; index ++ )
139131 {
140- var enumVal = vals[ i ] ;
132+ var enumVal = vals[ index ] ;
141133
142134 // get attribute and check for ignore
143135
144- dict . Add( enumVal , i ) ;
136+ dict . Add( enumVal , index ) ;
145137 }
146138
147- _names = names ;
148- _all = all ;
139+ _allValuesOrdered = all ;
149140 UniqueValues = vals ;
150- _numericallyDistinctValues = dict ;
151- MinValue = All [ 0 ] ;
152- MaxValue = All [ ^ 1 ] ;
141+ _numericallyDistinctIndices = dict ;
142+ MinValue = AllValuesOrdered [ 0 ] ;
143+ MaxValue = AllValuesOrdered [ ^ 1 ] ;
153144 }
154145
155- /// <summary>
156- /// Get the ordered index of the value provided.
157- /// Values with the same numerical value will *not* return the same index, and are not guaranteed to be
158- /// stably sorted across application runs.
159- /// The index provided
160- /// </summary>
161- /// <param name="value"></param>
162- /// <returns>The index of the sorted enum value</returns>
163- [ MethodImpl ( MethodImplOptions . AggressiveInlining ) ]
164- private static int NameIndexOf( T value ) => Array. IndexOf ( _all , value ) ;
165-
166- /// <inheritdoc cref="_names"/>
167-
168- /// <summary>
169- /// Returns the names of an enum value, pre-allocated
170- /// </summary>
171- public static string NameOf( T value ) => _names[ NameIndexOf ( value ) ] ;
172-
173- /// <summary>
174- /// Get the ordered index of the value provided.
175- /// Values with the same numerical value will return the same index
176- /// </summary>
177- /// <param name="value"></param>
178- /// <returns>The index of the sorted enum numerical value, or -1 if not a named enum member.</returns>
179- /// <exception cref="InvalidOperationException"></exception>
180- [ MethodImpl ( MethodImplOptions . AggressiveInlining ) ]
181- public static int ValueIndexOf( T value ) => ! _unnamedAreIndexable
182- ? ValueOf < T , int > ( value )
183- : _numericallyDistinctValues . GetValueOrDefault ( value , - 1 ) ;
184-
185146 /// <summary>
186147 /// Gets the ordered index of the unnamed enum value provided. This index is calculated by:
187148 /// (the number of named members in this enum type) + (the raw value of the number if unnamed)
@@ -190,57 +151,60 @@ public static int ValueIndexOf(T value) => !_unnamedAreIndexable
190151 /// </summary>
191152 /// <param name="value"></param>
192153 /// <returns></returns>
193- public static int ValueIndexOfUnnamed ( T value )
154+ public static int ValueIndexOf ( T value )
194155 {
195- if ( ! _unnamedAreIndexable )
156+ // happy path - it's a named value we've already computed
157+ if ( _numericallyDistinctIndices . TryGetValue ( value , out var index ) )
196158 {
197- return ValueOf < T , int > ( value ) ;
159+ return index ;
198160 }
199161
200- if ( _numericallyDistinctValues . TryGetValue ( value , out var index ) )
162+ // unhappy path - it's an unnamed value we haven't computed yet
163+ if ( ! _unnamedAreIndexable )
201164 {
202- return index ;
165+ // unnamed indexing is disabled
166+ return - 1 ;
203167 }
204168
205- var rawValue = ValueOf < T , int > ( value ) ;
169+ var rawValue = Convert < T , int > ( value ) ;
206170
207171 // todo - don't rely on joystickButton's unknown - find the MinValue
208- if ( rawValue < = 0 || rawValue >= ValueOf < ulong , int > ( _allEnumValuesRaw [ 0 ] ) )
172+ if ( rawValue < = 0 || rawValue >= Convert < ulong , int > ( _allEnumValuesRaw [ 0 ] ) )
209173 {
210174 return - 1 ;
211175 }
212176
213- return _all . Length + rawValue ;
177+ return _allValuesOrdered . Length + rawValue ;
214178 }
215179
216180 /// <summary>
217181 /// Returns the numerical value of the enum value provided in a type-safe way
218182 /// </summary>
219183 /// <param name="value"></param>
220- /// <typeparam name="TValue "></typeparam>
221- /// <typeparam name="TNumber "></typeparam>
184+ /// <typeparam name="TFrom "></typeparam>
185+ /// <typeparam name="TTo "></typeparam>
222186 /// <returns></returns>
223- private static unsafe TNumber ValueOf < TValue , TNumber > ( TValue value ) where TNumber : unmanaged where TValue : unmanaged
187+ private static unsafe TTo Convert < TFrom , TTo > ( TFrom value ) where TTo : unmanaged where TFrom : unmanaged
224188 {
225- if ( sizeof ( T ) == sizeof ( TNumber ) )
189+ if ( sizeof ( T ) == sizeof ( TTo ) )
226190 {
227- return Unsafe . Read < TNumber > ( & value ) ;
191+ return Unsafe . Read < TTo > ( & value ) ;
228192 }
229193
230- var minSize = Math . Min ( sizeof ( TNumber ) , sizeof ( T ) ) ;
194+ var minSize = Math . Min ( sizeof ( TTo ) , sizeof ( T ) ) ;
231195
232196 var originalValuePtr = ( byte * ) & value ;
233197
234198 var valuePtr = & originalValuePtr [ Math . Abs ( minSize - sizeof ( T ) ) ] ; // does this assume little-endianness?
235- var numberPtr = stackalloc byte [ sizeof ( TNumber ) ] ;
199+ var numberPtr = stackalloc byte [ sizeof ( TTo ) ] ;
236200
237201 // ensure block is initialized (as it isnt guaranteed?) so any missing bytes of the output will stay 0
238202 // if type TNumber is a larger size than type T
239- Unsafe . InitBlock ( numberPtr , 0 , ( uint ) sizeof ( TNumber ) ) ;
203+ Unsafe . InitBlock ( numberPtr , 0 , ( uint ) sizeof ( TTo ) ) ;
240204
241- var copyToPtr = & numberPtr [ Math . Abs ( minSize - sizeof ( TNumber ) ) ] ;
242- Buffer. MemoryCopy ( valuePtr , copyToPtr , sizeof ( TNumber ) , minSize ) ;
243- return * ( TNumber * ) numberPtr ;
205+ var copyToPtr = & numberPtr [ Math . Abs ( minSize - sizeof ( TTo ) ) ] ;
206+ Buffer. MemoryCopy ( valuePtr , copyToPtr , sizeof ( TTo ) , minSize ) ;
207+ return * ( TTo * ) numberPtr ;
244208 }
245209
246210 private static T [ ] OrderedValues < TNumber> ( bool byNumericValue )
@@ -251,13 +215,13 @@ private static T[] OrderedValues<TNumber>(bool byNumericValue)
251215
252216 if ( byNumericValue )
253217 {
254- allValues = allValues . DistinctBy ( ValueOf < T , TNumber > ) . ToArray ( ) ;
218+ allValues = allValues . DistinctBy ( Convert < T , TNumber > ) . ToArray ( ) ;
255219 }
256220
257221 // sort by increasing order
258222 allValues . AsSpan ( ) . StableSort ( ( a , b ) => {
259- var aNumber = ValueOf < T , TNumber > ( a ) ;
260- var bNumber = ValueOf < T , TNumber > ( b ) ;
223+ var aNumber = Convert < T , TNumber > ( a ) ;
224+ var bNumber = Convert < T , TNumber > ( b ) ;
261225 return aNumber . CompareTo ( bNumber ) ;
262226 } ) ;
263227
@@ -271,4 +235,10 @@ private static bool IsIgnored(T value)
271235 }
272236
273237 public static unsafe bool HasValue( int value ) => _allEnumValuesRaw . Contains ( * ( uint * ) & value ) ;
238+
239+ public static unsafe T ValueOfIndex( int index )
240+ {
241+ var value = _allEnumValuesRaw[ index] ;
242+ return * ( T * ) & value ;
243+ }
274244}
0 commit comments