Skip to content

Commit

Permalink
IComparable and IEquatable implementations for PyInt, PyFloat, and Py…
Browse files Browse the repository at this point in the history
…String for primitive .NET types
  • Loading branch information
lostmsu committed Feb 15, 2024
1 parent eef67db commit 4c84ca8
Show file tree
Hide file tree
Showing 6 changed files with 196 additions and 4 deletions.
26 changes: 26 additions & 0 deletions src/runtime/PythonTypes/PyFloat.IComparable.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
using System;

namespace Python.Runtime;

partial class PyFloat : IComparable<double>, IComparable<float>
, IEquatable<double>, IEquatable<float>
{
public override bool Equals(object o)
{
using var _ = Py.GIL();
return o switch
{
double f64 => this.Equals(f64),
float f32 => this.Equals(f32),
_ => base.Equals(o),
};
}

public int CompareTo(double other) => this.ToDouble().CompareTo(other);

public int CompareTo(float other) => this.ToDouble().CompareTo(other);

public bool Equals(double other) => this.ToDouble().Equals(other);

public bool Equals(float other) => this.ToDouble().Equals(other);
}
4 changes: 3 additions & 1 deletion src/runtime/PythonTypes/PyFloat.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ namespace Python.Runtime
/// PY3: https://docs.python.org/3/c-api/float.html
/// for details.
/// </summary>
public class PyFloat : PyNumber
public partial class PyFloat : PyNumber
{
internal PyFloat(in StolenReference ptr) : base(ptr)
{
Expand Down Expand Up @@ -100,6 +100,8 @@ public static PyFloat AsFloat(PyObject value)
return new PyFloat(op.Steal());
}

public double ToDouble() => Runtime.PyFloat_AsDouble(obj);

public override TypeCode GetTypeCode() => TypeCode.Double;
}
}
128 changes: 128 additions & 0 deletions src/runtime/PythonTypes/PyInt.IComparable.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
using System;

namespace Python.Runtime;

partial class PyInt : IComparable<long>, IComparable<int>, IComparable<sbyte>, IComparable<short>
, IComparable<ulong>, IComparable<uint>, IComparable<ushort>, IComparable<byte>
, IEquatable<long>, IEquatable<int>, IEquatable<short>, IEquatable<sbyte>
, IEquatable<ulong>, IEquatable<uint>, IEquatable<ushort>, IEquatable<byte>
{
public override bool Equals(object o)
{
using var _ = Py.GIL();
return o switch
{
long i64 => this.Equals(i64),
int i32 => this.Equals(i32),
short i16 => this.Equals(i16),
sbyte i8 => this.Equals(i8),

ulong u64 => this.Equals(u64),
uint u32 => this.Equals(u32),
ushort u16 => this.Equals(u16),
byte u8 => this.Equals(u8),

_ => base.Equals(o),
};
}

#region Signed
public int CompareTo(long other)
{
using var pyOther = Runtime.PyInt_FromInt64(other);
return this.CompareTo(pyOther.BorrowOrThrow());
}

public int CompareTo(int other)
{
using var pyOther = Runtime.PyInt_FromInt32(other);
return this.CompareTo(pyOther.BorrowOrThrow());
}

public int CompareTo(short other)
{
using var pyOther = Runtime.PyInt_FromInt32(other);
return this.CompareTo(pyOther.BorrowOrThrow());
}

public int CompareTo(sbyte other)
{
using var pyOther = Runtime.PyInt_FromInt32(other);
return this.CompareTo(pyOther.BorrowOrThrow());
}

public bool Equals(long other)
{
using var pyOther = Runtime.PyInt_FromInt64(other);
return this.Equals(pyOther.BorrowOrThrow());
}

public bool Equals(int other)
{
using var pyOther = Runtime.PyInt_FromInt32(other);
return this.Equals(pyOther.BorrowOrThrow());
}

public bool Equals(short other)
{
using var pyOther = Runtime.PyInt_FromInt32(other);
return this.Equals(pyOther.BorrowOrThrow());
}

public bool Equals(sbyte other)
{
using var pyOther = Runtime.PyInt_FromInt32(other);
return this.Equals(pyOther.BorrowOrThrow());
}
#endregion Signed

#region Unsigned
public int CompareTo(ulong other)
{
using var pyOther = Runtime.PyLong_FromUnsignedLongLong(other);
return this.CompareTo(pyOther.BorrowOrThrow());
}

public int CompareTo(uint other)
{
using var pyOther = Runtime.PyLong_FromUnsignedLongLong(other);
return this.CompareTo(pyOther.BorrowOrThrow());
}

public int CompareTo(ushort other)
{
using var pyOther = Runtime.PyLong_FromUnsignedLongLong(other);
return this.CompareTo(pyOther.BorrowOrThrow());
}

public int CompareTo(byte other)
{
using var pyOther = Runtime.PyLong_FromUnsignedLongLong(other);
return this.CompareTo(pyOther.BorrowOrThrow());
}

public bool Equals(ulong other)
{
using var pyOther = Runtime.PyLong_FromUnsignedLongLong(other);
return this.Equals(pyOther.BorrowOrThrow());
}

public bool Equals(uint other)
{
using var pyOther = Runtime.PyLong_FromUnsignedLongLong(other);
return this.Equals(pyOther.BorrowOrThrow());
}

public bool Equals(ushort other)
{
using var pyOther = Runtime.PyLong_FromUnsignedLongLong(other);
return this.Equals(pyOther.BorrowOrThrow());
}

public bool Equals(byte other)
{
using var pyOther = Runtime.PyLong_FromUnsignedLongLong(other);
return this.Equals(pyOther.BorrowOrThrow());
}
#endregion Unsigned
}
2 changes: 1 addition & 1 deletion src/runtime/PythonTypes/PyInt.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ namespace Python.Runtime
/// Represents a Python integer object.
/// See the documentation at https://docs.python.org/3/c-api/long.html
/// </summary>
public class PyInt : PyNumber, IFormattable
public partial class PyInt : PyNumber, IFormattable
{
internal PyInt(in StolenReference ptr) : base(ptr)
{
Expand Down
19 changes: 18 additions & 1 deletion src/runtime/PythonTypes/PyObject.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1136,6 +1136,23 @@ public long Refcount
}
}

internal int CompareTo(BorrowedReference other)
{
int greater = Runtime.PyObject_RichCompareBool(this.Reference, other, Runtime.Py_GT);
Debug.Assert(greater != -1);
if (greater > 0)
return 1;
int less = Runtime.PyObject_RichCompareBool(this.Reference, other, Runtime.Py_LT);
Debug.Assert(less != -1);
return less > 0 ? -1 : 0;
}

internal bool Equals(BorrowedReference other)
{
int equal = Runtime.PyObject_RichCompareBool(this.Reference, other, Runtime.Py_EQ);
Debug.Assert(equal != -1);
return equal > 0;
}

public override bool TryGetMember(GetMemberBinder binder, out object? result)
{
Expand Down Expand Up @@ -1325,7 +1342,7 @@ private bool TryCompare(PyObject arg, int op, out object @out)
}
return true;
}

public override bool TryBinaryOperation(BinaryOperationBinder binder, object arg, out object? result)
{
using var _ = Py.GIL();
Expand Down
21 changes: 20 additions & 1 deletion src/runtime/PythonTypes/PyString.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System;
using System.Diagnostics;
using System.Runtime.Serialization;

namespace Python.Runtime
Expand All @@ -13,7 +14,7 @@ namespace Python.Runtime
/// 2011-01-29: ...Then why does the string constructor call PyUnicode_FromUnicode()???
/// </remarks>
[Serializable]
public class PyString : PySequence
public class PyString : PySequence, IComparable<string>, IEquatable<string>
{
internal PyString(in StolenReference reference) : base(reference) { }
internal PyString(BorrowedReference reference) : base(reference) { }
Expand Down Expand Up @@ -61,5 +62,23 @@ public static bool IsStringType(PyObject value)
}

public override TypeCode GetTypeCode() => TypeCode.String;

internal string ToStringUnderGIL()
{
string? result = Runtime.GetManagedString(this.Reference);
Debug.Assert(result is not null);
return result!;
}

public bool Equals(string? other)
=> this.ToStringUnderGIL().Equals(other, StringComparison.CurrentCulture);
public int CompareTo(string? other)
=> string.Compare(this.ToStringUnderGIL(), other, StringComparison.CurrentCulture);

public override string ToString()
{
using var _ = Py.GIL();
return this.ToStringUnderGIL();
}
}
}

0 comments on commit 4c84ca8

Please sign in to comment.