| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
1 parent eec30c0 commit 0e57cdd
7 files changed
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -22,6 +22,7 @@ This document follows the conventions laid out in [Keep a CHANGELOG][]. | |||
| 22 | 22 | - .NET collection types now implement standard Python collection interfaces from `collections.abc`. | |
| 23 | 23 | See [Mixins/collections.py](src/runtime/Mixins/collections.py). | |
| 24 | 24 | - .NET arrays implement Python buffer protocol | |
| 25 | + - Python integer interoperability with `System.Numerics.BigInteger` | ||
| 25 | 26 | - Python.NET will correctly resolve .NET methods, that accept `PyList`, `PyInt`, | |
| 26 | 27 | and other `PyObject` derived types when called from Python. | |
| 27 | 28 | - .NET classes, that have `__call__` method are callable from Python | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -1,6 +1,7 @@ | |||
| 1 | 1 | using System; | |
| 2 | 2 | using System.Collections.Generic; | |
| 3 | 3 | using System.Linq; | |
| 4 | + using System.Numerics; | ||
| 4 | 5 | ||
| 5 | 6 | using NUnit.Framework; | |
| 6 | 7 | ||
@@ -131,6 +132,25 @@ public void ToNullable() | |||
| 131 | 132 | Assert.AreEqual(Const, ni); | |
| 132 | 133 | } | |
| 133 | 134 | ||
| 135 | + [Test] | ||
| 136 | + public void BigIntExplicit() | ||
| 137 | + { | ||
| 138 | + BigInteger val = 42; | ||
| 139 | + var i = new PyInt(val); | ||
| 140 | + var ni = i.As<BigInteger>(); | ||
| 141 | + Assert.AreEqual(val, ni); | ||
| 142 | + var nullable = i.As<BigInteger?>(); | ||
| 143 | + Assert.AreEqual(val, nullable); | ||
| 144 | + } | ||
| 145 | + | ||
| 146 | + [Test] | ||
| 147 | + public void PyIntImplicit() | ||
| 148 | + { | ||
| 149 | + var i = new PyInt(1); | ||
| 150 | + var ni = (PyObject)i.As<object>(); | ||
| 151 | + Assert.AreEqual(i.rawPtr, ni.rawPtr); | ||
| 152 | + } | ||
| 153 | + | ||
| 134 | 154 | [Test] | |
| 135 | 155 | public void ToPyList() | |
| 136 | 156 | { | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -1,4 +1,8 @@ | |||
| 1 | 1 | using System; | |
| 2 | + using System.Globalization; | ||
| 3 | + using System.Linq; | ||
| 4 | + using System.Numerics; | ||
| 5 | + | ||
| 2 | 6 | using NUnit.Framework; | |
| 3 | 7 | using Python.Runtime; | |
| 4 | 8 | ||
@@ -179,5 +183,35 @@ public void TestConvertToInt64() | |||
| 179 | 183 | Assert.IsInstanceOf(typeof(long), a.ToInt64()); | |
| 180 | 184 | Assert.AreEqual(val, a.ToInt64()); | |
| 181 | 185 | } | |
| 186 | + | ||
| 187 | + [Test] | ||
| 188 | + public void ToBigInteger() | ||
| 189 | + { | ||
| 190 | + int[] simpleValues = | ||
| 191 | + { | ||
| 192 | + 0, 1, 2, | ||
| 193 | + 0x10, | ||
| 194 | + 0x123, | ||
| 195 | + 0x1234, | ||
| 196 | + }; | ||
| 197 | + simpleValues = simpleValues.Concat(simpleValues.Select(v => -v)).ToArray(); | ||
| 198 | + | ||
| 199 | + foreach (var val in simpleValues) | ||
| 200 | + { | ||
| 201 | + var pyInt = new PyInt(val); | ||
| 202 | + Assert.AreEqual((BigInteger)val, pyInt.ToBigInteger()); | ||
| 203 | + } | ||
| 204 | + } | ||
| 205 | + | ||
| 206 | + [Test] | ||
| 207 | + public void ToBigIntegerLarge() | ||
| 208 | + { | ||
| 209 | + BigInteger val = BigInteger.Pow(2, 1024) + 3; | ||
| 210 | + var pyInt = new PyInt(val); | ||
| 211 | + Assert.AreEqual(val, pyInt.ToBigInteger()); | ||
| 212 | + val = -val; | ||
| 213 | + pyInt = new PyInt(val); | ||
| 214 | + Assert.AreEqual(val, pyInt.ToBigInteger()); | ||
| 215 | + } | ||
| 182 | 216 | } | |
| 183 | 217 | } | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -455,6 +455,14 @@ internal static bool ToManagedValue(BorrowedReference value, Type obType, | |||
| 455 | 455 | } | |
| 456 | 456 | } | |
| 457 | 457 | ||
| 458 | + if (obType == typeof(System.Numerics.BigInteger) | ||
| 459 | + && Runtime.PyInt_Check(value)) | ||
| 460 | + { | ||
| 461 | + using var pyInt = new PyInt(value); | ||
| 462 | + result = pyInt.ToBigInteger(); | ||
| 463 | + return true; | ||
| 464 | + } | ||
| 465 | + | ||
| 458 | 466 | return ToPrimitive(value, obType, out result, setError); | |
| 459 | 467 | } | |
| 460 | 468 | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -1,21 +1,21 @@ | |||
| 1 | 1 | using System; | |
| 2 | + using System.Globalization; | ||
| 3 | + using System.Numerics; | ||
| 2 | 4 | using System.Runtime.Serialization; | |
| 3 | 5 | ||
| 4 | 6 | namespace Python.Runtime | |
| 5 | 7 | { | |
| 6 | 8 | /// <summary> | |
| 7 | - /// Represents a Python integer object. See the documentation at | ||
| 8 | - /// PY2: https://docs.python.org/2/c-api/int.html | ||
| 9 | - /// PY3: No equivalent | ||
| 10 | - /// for details. | ||
| 9 | + /// Represents a Python integer object. | ||
| 10 | + /// See the documentation at https://docs.python.org/3/c-api/long.html | ||
| 11 | 11 | /// </summary> | |
| 12 | - public class PyInt : PyNumber | ||
| 12 | + public class PyInt : PyNumber, IFormattable | ||
| 13 | 13 | { | |
| 14 | 14 | internal PyInt(in StolenReference ptr) : base(ptr) | |
| 15 | 15 | { | |
| 16 | 16 | } | |
| 17 | 17 | ||
| 18 | - internal PyInt(BorrowedReference reference): base(reference) | ||
| 18 | + internal PyInt(BorrowedReference reference) : base(reference) | ||
| 19 | 19 | { | |
| 20 | 20 | if (!Runtime.PyInt_Check(reference)) throw new ArgumentException("object is not an int"); | |
| 21 | 21 | } | |
@@ -135,6 +135,8 @@ public PyInt(string value) : base(Runtime.PyLong_FromString(value, 0).StealOrThr | |||
| 135 | 135 | { | |
| 136 | 136 | } | |
| 137 | 137 | ||
| 138 | + public PyInt(BigInteger value) : this(value.ToString(CultureInfo.InvariantCulture)) { } | ||
| 139 | + | ||
| 138 | 140 | protected PyInt(SerializationInfo info, StreamingContext context) | |
| 139 | 141 | : base(info, context) { } | |
| 140 | 142 | ||
@@ -198,5 +200,35 @@ public long ToInt64() | |||
| 198 | 200 | } | |
| 199 | 201 | return val.Value; | |
| 200 | 202 | } | |
| 203 | + | ||
| 204 | + public BigInteger ToBigInteger() | ||
| 205 | + { | ||
| 206 | + using var pyHex = Runtime.HexCallable.Invoke(this); | ||
| 207 | + string hex = pyHex.As<string>(); | ||
| 208 | + int offset = 0; | ||
| 209 | + bool neg = false; | ||
| 210 | + if (hex[0] == '-') | ||
| 211 | + { | ||
| 212 | + offset++; | ||
| 213 | + neg = true; | ||
| 214 | + } | ||
| 215 | + byte[] littleEndianBytes = new byte[(hex.Length - offset + 1) / 2]; | ||
| 216 | + for (; offset < hex.Length; offset++) | ||
| 217 | + { | ||
| 218 | + int littleEndianHexIndex = hex.Length - 1 - offset; | ||
| 219 | + int byteIndex = littleEndianHexIndex / 2; | ||
| 220 | + int isByteTopHalf = littleEndianHexIndex & 1; | ||
| 221 | + int valueShift = isByteTopHalf * 4; | ||
| 222 | + littleEndianBytes[byteIndex] += (byte)(Util.HexToInt(hex[offset]) << valueShift); | ||
| 223 | + } | ||
| 224 | + var result = new BigInteger(littleEndianBytes); | ||
| 225 | + return neg ? -result : result; | ||
| 226 | + } | ||
| 227 | + | ||
| 228 | + public string ToString(string format, IFormatProvider formatProvider) | ||
| 229 | + { | ||
| 230 | + using var _ = Py.GIL(); | ||
| 231 | + return ToBigInteger().ToString(format, formatProvider); | ||
| 232 | + } | ||
| 201 | 233 | } | |
| 202 | 234 | } | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -179,6 +179,7 @@ internal static void Initialize(bool initSigs = false) | |||
| 179 | 179 | ||
| 180 | 180 | clrInterop = GetModuleLazy("clr.interop"); | |
| 181 | 181 | inspect = GetModuleLazy("inspect"); | |
| 182 | + hexCallable = new(() => new PyString("%x").GetAttr("__mod__")); | ||
| 182 | 183 | } | |
| 183 | 184 | ||
| 184 | 185 | static void NewRun() | |
@@ -279,8 +280,9 @@ internal static void Shutdown() | |||
| 279 | 280 | ||
| 280 | 281 | Exceptions.Shutdown(); | |
| 281 | 282 | PythonEngine.InteropConfiguration.Dispose(); | |
| 282 | - DisposeLazyModule(clrInterop); | ||
| 283 | - DisposeLazyModule(inspect); | ||
| 283 | + DisposeLazyObject(clrInterop); | ||
| 284 | + DisposeLazyObject(inspect); | ||
| 285 | + DisposeLazyObject(hexCallable); | ||
| 284 | 286 | PyObjectConversions.Reset(); | |
| 285 | 287 | ||
| 286 | 288 | PyGC_Collect(); | |
@@ -352,11 +354,11 @@ static bool TryCollectingGarbage(int runs, bool forceBreakLoops) | |||
| 352 | 354 | public static bool TryCollectingGarbage(int runs) | |
| 353 | 355 | => TryCollectingGarbage(runs, forceBreakLoops: false); | |
| 354 | 356 | ||
| 355 | - static void DisposeLazyModule(Lazy<PyObject> module) | ||
| 357 | + static void DisposeLazyObject(Lazy<PyObject> pyObject) | ||
| 356 | 358 | { | |
| 357 | - if (module.IsValueCreated) | ||
| 359 | + if (pyObject.IsValueCreated) | ||
| 358 | 360 | { | |
| 359 | - module.Value.Dispose(); | ||
| 361 | + pyObject.Value.Dispose(); | ||
| 360 | 362 | } | |
| 361 | 363 | } | |
| 362 | 364 | ||
@@ -489,8 +491,12 @@ private static void NullGCHandles(IEnumerable<IntPtr> objects) | |||
| 489 | 491 | ||
| 490 | 492 | private static Lazy<PyObject> inspect; | |
| 491 | 493 | internal static PyObject InspectModule => inspect.Value; | |
| 494 | + | ||
| 492 | 495 | private static Lazy<PyObject> clrInterop; | |
| 493 | 496 | internal static PyObject InteropModule => clrInterop.Value; | |
| 497 | + | ||
| 498 | + private static Lazy<PyObject> hexCallable; | ||
| 499 | + internal static PyObject HexCallable => hexCallable.Value; | ||
| 494 | 500 | #pragma warning restore CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable. | |
| 495 | 501 | ||
| 496 | 502 | internal static BorrowedReference CLRMetaType => PyCLRMetaType; | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -141,6 +141,13 @@ internal static string ReadStringResource(this System.Reflection.Assembly assemb | |||
| 141 | 141 | return reader.ReadToEnd(); | |
| 142 | 142 | } | |
| 143 | 143 | ||
| 144 | + public static int HexToInt(char hex) => hex switch | ||
| 145 | + { | ||
| 146 | + >= '0' and <= '9' => hex - '0', | ||
| 147 | + >= 'a' and <= 'f' => hex - 'a' + 10, | ||
| 148 | + _ => throw new ArgumentOutOfRangeException(nameof(hex)), | ||
| 149 | + }; | ||
| 150 | + | ||
| 144 | 151 | public static IEnumerator<T> GetEnumerator<T>(this IEnumerator<T> enumerator) => enumerator; | |
| 145 | 152 | ||
| 146 | 153 | public static IEnumerable<T> WhereNotNull<T>(this IEnumerable<T?> source) | |
| Back | FazBrowse Home | New Git URL |
0 commit comments