Skip to content

Commit eea88db

Browse files
authored
Cleanup Converter.ConvertToIndex (#978)
1 parent 3efe5f4 commit eea88db

File tree

3 files changed

+38
-49
lines changed

3 files changed

+38
-49
lines changed

Src/IronPython/Runtime/ByteArray.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ public void __init__(int source) {
7070
}
7171

7272
public void __init__([NotNull]IBufferProtocol source) {
73-
if (Converter.TryConvertToIndex(source, throwOverflowError: true, out int size)) {
73+
if (Converter.TryConvertToIndex(source, out int size)) {
7474
__init__(size);
7575
} else {
7676
lock (this) {
@@ -82,7 +82,7 @@ public void __init__([NotNull]IBufferProtocol source) {
8282
}
8383

8484
public void __init__(CodeContext context, object? source) {
85-
if (Converter.TryConvertToIndex(source, throwOverflowError: true, out int size)) {
85+
if (Converter.TryConvertToIndex(source, out int size)) {
8686
__init__(size);
8787
} else if (source is IEnumerable<byte> en) {
8888
lock (this) {

Src/IronPython/Runtime/Bytes.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ public static object __new__(CodeContext context, [NotNull] PythonType cls, [Not
6060
return source;
6161
} else if (TryInvokeBytesOperator(context, source, out Bytes? res)) {
6262
return res;
63-
} else if (Converter.TryConvertToIndex(source, throwOverflowError: true, out int size)) {
63+
} else if (Converter.TryConvertToIndex(source, out int size)) {
6464
if (size < 0) throw PythonOps.ValueError("negative count");
6565
return new Bytes(new byte[size]);
6666
} else {
@@ -78,7 +78,7 @@ public static object __new__(CodeContext context, [NotNull] PythonType cls, obje
7878
return @object;
7979
} else if (TryInvokeBytesOperator(context, @object, out Bytes? res)) {
8080
return res;
81-
} else if (Converter.TryConvertToIndex(@object, throwOverflowError: true, out int size)) {
81+
} else if (Converter.TryConvertToIndex(@object, out int size)) {
8282
if (size < 0) throw PythonOps.ValueError("negative count");
8383
return new Bytes(new byte[size]);
8484
} else {

Src/IronPython/Runtime/Converter.cs

Lines changed: 34 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
using System.Collections;
77
using System.Collections.Generic;
88
using System.ComponentModel;
9+
using System.Diagnostics;
910
using System.Diagnostics.CodeAnalysis;
1011
using System.Numerics;
1112
using 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

Comments
 (0)