66using System . Collections ;
77using System . Collections . Generic ;
88using System . ComponentModel ;
9+ using System . Diagnostics ;
910using System . Diagnostics . CodeAnalysis ;
1011using System . Numerics ;
1112using System . Reflection ;
@@ -315,29 +316,17 @@ public static IEnumerable ConvertToIEnumerable(object o) {
315316 return _ienumerableSite . Target ( _ienumerableSite , o ) ;
316317 }
317318
318- internal static bool TryConvertToIndex ( object value , out int index ) {
319- return TryConvertToIndex ( value , true , out index ) ;
320- }
321-
322319 /// <summary>
323320 /// Attempts to convert value into a index usable for slicing and return the integer
324321 /// value. If the conversion fails false is returned.
325322 ///
326323 /// If throwOverflowError is true then BigInteger's outside the normal range of integers will
327324 /// result in an OverflowError.
328325 /// </summary>
329- internal static bool TryConvertToIndex ( object value , bool throwOverflowError , out int index ) {
330- int ? res = ConvertToSliceIndexHelper ( value , throwOverflowError ) ;
331- if ( ! res . HasValue ) {
332- object callable ;
333- if ( PythonOps . TryGetBoundAttr ( value , "__index__" , out callable ) ) {
334- res = ConvertToSliceIndexHelper ( PythonCalls . Call ( callable ) , throwOverflowError ) ;
335- }
336- }
337-
338- index = res ?? default ;
339- return res . HasValue ;
340- }
326+ internal static bool TryConvertToIndex ( object value , out int index , bool throwOverflowError = true )
327+ => TryGetInt ( value , out index , throwOverflowError )
328+ || PythonTypeOps . TryInvokeUnaryOperator ( DefaultContext . Default , value , "__index__" , out object res )
329+ && TryGetInt ( res , out index , throwOverflowError ) ;
341330
342331 /// <summary>
343332 /// Attempts to convert value into an index usable for slicing and return the integer or BigInteger
@@ -346,27 +335,22 @@ internal static bool TryConvertToIndex(object value, bool throwOverflowError, ou
346335 internal static bool TryConvertToIndex ( object value , out object index ) {
347336 index = ConvertToSliceIndexHelper ( value ) ;
348337 if ( index == null ) {
349- object callable ;
350- if ( PythonOps . TryGetBoundAttr ( value , "__index__" , out callable ) ) {
351- index = ConvertToSliceIndexHelper ( PythonCalls . Call ( callable ) ) ;
338+ if ( PythonTypeOps . TryInvokeUnaryOperator ( DefaultContext . Default , value , "__index__" , out object res ) ) {
339+ index = ConvertToSliceIndexHelper ( res ) ;
352340 }
353341 }
354342
355343 return index != null ;
356344 }
357345
358346 public static int ConvertToIndex ( object value ) {
359- int ? res = ConvertToSliceIndexHelper ( value , false ) ;
360- if ( res . HasValue ) {
361- return res . Value ;
347+ if ( TryGetInt ( value , out int res , throwOverflowError : false ) ) {
348+ return res ;
362349 }
363350
364- object callable ;
365- if ( PythonOps . TryGetBoundAttr ( value , "__index__" , out callable ) ) {
366- object index = PythonCalls . Call ( callable ) ;
367- res = ConvertToSliceIndexHelper ( index , false ) ;
368- if ( res . HasValue ) {
369- return res . Value ;
351+ if ( PythonTypeOps . TryInvokeUnaryOperator ( DefaultContext . Default , value , "__index__" , out object index ) ) {
352+ if ( TryGetInt ( index , out res , throwOverflowError : false ) ) {
353+ return res ;
370354 }
371355
372356 throw PythonOps . TypeError ( "__index__ returned non-int (type {0})" , DynamicHelpers . GetPythonType ( index ) . Name ) ;
@@ -375,27 +359,32 @@ public static int ConvertToIndex(object value) {
375359 throw PythonOps . TypeError ( "expected index value, got {0}" , DynamicHelpers . GetPythonType ( value ) . Name ) ;
376360 }
377361
378- private static int ? ConvertToSliceIndexHelper ( object value , bool throwOverflowError ) {
379- if ( value is int ) return ( int ) value ;
380- if ( value is Extensible < int > ) return ( ( Extensible < int > ) value ) . Value ;
381-
382- BigInteger bi ;
383- if ( value is BigInteger ) {
384- bi = ( BigInteger ) value ;
385- } else if ( value is Extensible < BigInteger > ebi ) {
386- bi = ebi . Value ;
362+ internal static bool TryGetInt ( object o , out int value , bool throwOverflowError ) {
363+ if ( o is int i ) {
364+ value = i ;
365+ } else if ( o is Extensible < int > ei ) {
366+ value = ei . Value ;
387367 } else {
388- return null ;
389- }
368+ BigInteger bi ;
369+ if ( o is BigInteger ) {
370+ bi = ( BigInteger ) o ;
371+ } else if ( o is Extensible < BigInteger > ebi ) {
372+ bi = ebi . Value ;
373+ } else {
374+ value = default ;
375+ return false ;
376+ }
390377
391- int res ;
392- if ( bi . AsInt32 ( out res ) ) return res ;
378+ if ( bi . AsInt32 ( out value ) ) return true ;
393379
394- if ( throwOverflowError ) {
395- throw PythonOps . OverflowError ( "can't fit long into index" ) ;
396- }
380+ if ( throwOverflowError ) {
381+ throw PythonOps . OverflowError ( "can't fit long into index" ) ;
382+ }
397383
398- return bi == BigInteger . Zero ? 0 : bi > 0 ? Int32 . MaxValue : Int32 . MinValue ;
384+ Debug . Assert ( bi != 0 ) ;
385+ value = bi > 0 ? int . MaxValue : int . MinValue ;
386+ }
387+ return true ;
399388 }
400389
401390 private static object ConvertToSliceIndexHelper ( object value ) {
0 commit comments