Skip to content

Commit 8b6e34a

Browse files
authored
Misc changes (#973)
* Make from_bytes a class method * Fix empty deque comparison * Fix hex(BigInteger) * Update after review
1 parent 229ac53 commit 8b6e34a

File tree

7 files changed

+61
-26
lines changed

7 files changed

+61
-26
lines changed

Src/IronPython.Modules/_collections.cs

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -486,16 +486,13 @@ int IComparable.CompareTo(object obj) {
486486
return CompareToWorker(otherDeque);
487487
}
488488

489-
private int CompareToWorker(deque otherDeque) {
490-
return CompareToWorker(otherDeque, null);
491-
}
492-
493-
private int CompareToWorker(deque otherDeque, IComparer comparer) {
489+
private int CompareToWorker(deque otherDeque, IComparer comparer = null) {
494490
Assert.NotNull(otherDeque);
495491

496-
if (otherDeque._itemCnt == 0 && _itemCnt == 0) {
497-
// comparing two empty deques
498-
return 0;
492+
if (_itemCnt == 0) {
493+
return otherDeque._itemCnt == 0 ? 0 : -1;
494+
} else if (otherDeque._itemCnt == 0) {
495+
return 1;
499496
}
500497

501498
if (CompareUtil.Check(this)) return 0;

Src/IronPython/Modules/Builtin.cs

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -625,10 +625,12 @@ private static void AppendIndent(StringBuilder doc, int indent) {
625625
public static string hex(object? o) {
626626
object res = PythonOps.Index(o);
627627
if (res is BigInteger b) {
628-
if (b < 0) {
629-
return "-0x" + (-b).ToString("x");
628+
if (b == 0) {
629+
return "0x0";
630+
} else if (b < 0) {
631+
return "-0x" + ToHexString(-b);
630632
} else {
631-
return "0x" + b.ToString("x");
633+
return "0x" + ToHexString(b);
632634
}
633635
}
634636

@@ -638,6 +640,12 @@ public static string hex(object? o) {
638640
} else {
639641
return "0x" + Convert.ToString(x, 16);
640642
}
643+
644+
static string ToHexString(BigInteger b) {
645+
var val = b.ToString("x");
646+
if (val[0] == '0') val = val.TrimStart('0'); // BigInteger.ToString("x") sometimes pads with 0 so we need to trim it (https://github.com/dotnet/runtime/issues/43269)
647+
return val;
648+
}
641649
}
642650

643651
public static object id(object? o) {

Src/IronPython/Runtime/ClassMethodDescriptor.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ internal ClassMethodDescriptor(BuiltinFunction func) {
1818

1919
internal override bool TryGetValue(CodeContext context, object instance, PythonType owner, out object value) {
2020
owner = CheckGetArgs(context, instance, owner);
21-
value = new Method(_func, owner);
21+
value = new BuiltinFunction(owner, _func._data);
2222
return true;
2323
}
2424

Src/IronPython/Runtime/Operations/IntOps.cs

Lines changed: 7 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -528,10 +528,9 @@ public static Bytes to_bytes(Int32 value, int length, string byteorder, bool sig
528528
return Bytes.Make(res.ToArray());
529529
}
530530

531-
public static BigInteger from_bytes(CodeContext context, object bytes, [NotNull] string byteorder, bool signed = false) {
531+
[ClassMethod, StaticExtensionMethod]
532+
public static object from_bytes(CodeContext context, PythonType type, object bytes, [NotNull] string byteorder, bool signed = false) {
532533
// TODO: signed should be a keyword only argument
533-
// TODO: return int when possible?
534-
// TODO: if called on a subclass of Extensible<BigInteger>, return that subclass
535534

536535
bool isLittle = byteorder == "little";
537536
if (!isLittle && byteorder != "big") throw PythonOps.ValueError("byteorder must be either 'little' or 'big'");
@@ -540,19 +539,13 @@ public static BigInteger from_bytes(CodeContext context, object bytes, [NotNull]
540539
if (bytesArr.Length == 0) return 0;
541540

542541
#if NETCOREAPP
543-
return new BigInteger(bytesArr.AsSpan(), isUnsigned: !signed, isBigEndian: !isLittle);
542+
var val = new BigInteger(bytesArr.AsSpan(), isUnsigned: !signed, isBigEndian: !isLittle);
544543
#else
545-
546-
if (isLittle) {
547-
bool msbSet = (bytesArr[bytesArr.Length - 1] & 0x80) == 0x80;
548-
if (!msbSet) return new BigInteger(bytesArr);
549-
return new BigInteger(bytesArr.Concat(Enumerable.Repeat<byte>(signed ? (byte)0xff : (byte)0, 1)).ToArray());
550-
} else {
551-
bool msbSet = (bytesArr[0] & 0x80) == 0x80;
552-
if (!msbSet) return new BigInteger(bytesArr.Reverse());
553-
return new BigInteger(bytesArr.Reverse().Concat(Enumerable.Repeat<byte>(signed ? (byte)0xff : (byte)0, 1)).ToArray());
554-
}
544+
if (!isLittle) bytesArr = bytesArr.Reverse();
545+
if (!signed && (bytesArr[bytesArr.Length - 1] & 0x80) == 0x80) Array.Resize(ref bytesArr, bytesArr.Length + 1);
546+
var val = new BigInteger(bytesArr);
555547
#endif
548+
return __new__(context, type, val);
556549
}
557550

558551
public static int __round__(int self) {

Tests/test_builtinfunc.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1068,6 +1068,10 @@ def __index__(self):
10681068
self.assertEqual([(2147483647, 2), (2147483648, 3), (2147483649, 4)], list(enumerate([2,3,4], value_maker(int((1<<31) - 1)))))
10691069
self.assertEqual([(2147483648, 2), (2147483649, 3), (2147483650, 4)], list(enumerate([2,3,4], value_maker(1<<31))))
10701070

1071+
def test_hex_long(self):
1072+
"""https://github.com/IronLanguages/ironpython3/pull/973"""
1073+
self.assertEqual(hex(0x800000000), '0x800000000')
1074+
10711075
# temp_func = in_main()
10721076
# locals_globals = 7
10731077
# temp_func()

Tests/test_deque.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
# Licensed to the .NET Foundation under one or more agreements.
2+
# The .NET Foundation licenses this file to you under the Apache 2.0 License.
3+
# See the LICENSE file in the project root for more information.
4+
5+
from _collections import deque
6+
import unittest
7+
8+
class DequeTest(unittest.TestCase):
9+
def test_deque_cmp_empty(self):
10+
"""https://github.com/IronLanguages/ironpython3/pull/973"""
11+
class AlwaysLessThan:
12+
def __lt__(self, other):
13+
return True
14+
15+
self.assertFalse(deque([AlwaysLessThan()]) < deque())
16+
17+
if __name__ == "__main__":
18+
unittest.main()

Tests/test_int.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
# Licensed to the .NET Foundation under one or more agreements.
2+
# The .NET Foundation licenses this file to you under the Apache 2.0 License.
3+
# See the LICENSE file in the project root for more information.
4+
5+
import unittest
6+
7+
class IntSubclass(int): pass
8+
9+
class IntTest(unittest.TestCase):
10+
def test_from_bytes(self):
11+
self.assertEqual(type(int.from_bytes(b"abc", "big")), int)
12+
self.assertEqual(type(IntSubclass.from_bytes(b"abc", "big")), IntSubclass) # https://github.com/IronLanguages/ironpython3/pull/973
13+
14+
if __name__ == "__main__":
15+
unittest.main()

0 commit comments

Comments
 (0)