Skip to content

Commit

Permalink
Implement <, >, <=, >= (#156)
Browse files Browse the repository at this point in the history
* Implement <, >, <=, >=
  • Loading branch information
AaronRobinsonMSFT authored Aug 23, 2024
1 parent da49285 commit ad9217c
Show file tree
Hide file tree
Showing 2 changed files with 115 additions and 19 deletions.
47 changes: 45 additions & 2 deletions src/CSnakes.Runtime.Tests/Python/PyObjectTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
namespace CSnakes.Runtime.Tests.Python;
public class PyObjectTests : RuntimeTestBase
{

[Fact]
public void TestToString()
{
Expand Down Expand Up @@ -63,7 +62,7 @@ public void TestObjectIsNone()

[Fact]
public void TestObjectIsSmallIntegers() {
// Small numbers are the same object in Python, weird implementation detail.
// Small numbers are the same object in Python, weird implementation detail.
var obj1 = PyObject.From(42);
var obj2 = PyObject.From(42);
Assert.True(obj1!.Is(obj2!));
Expand Down Expand Up @@ -114,4 +113,48 @@ public void TestObjectNotEqualsCollection()
Assert.True(obj1!.NotEquals(obj2));
Assert.True(obj1 != obj2);
}

[InlineData(null, null, false, false)]
[InlineData(0, null, false, false)]
[InlineData(null, 0, false, false)]
[InlineData(long.MaxValue, 0, false, true)]
[InlineData(long.MinValue, 0, true, false)]
[InlineData(0, long.MaxValue, true, false)]
[InlineData(0, long.MinValue, false, true)]
[InlineData((long)-1, 1, true, false)]
[InlineData(1, (long)-1, false, true)]
[InlineData("a", "b", true, false)]
[InlineData("b", "a", false, true)]
[InlineData(3.0, 3.2, true, false)]
[Theory]
public void TestObjectStrictInequality(object? o1, object? o2, bool expectedLT, bool expectedGT)
{
using var obj1 = o1 is null ? null : PyObject.From(o1);
using var obj2 = o2 is null ? null : PyObject.From(o2);
Assert.Equal(expectedLT, obj1 < obj2);
Assert.Equal(expectedGT, obj1 > obj2);
}

[InlineData(null, null, true, true)]
[InlineData(0, null, false, false)]
[InlineData(null, 0, false, false)]
[InlineData(long.MaxValue, 0, false, true)]
[InlineData(long.MinValue, 0, true, false)]
[InlineData(0, long.MaxValue, true, false)]
[InlineData(0, long.MinValue, false, true)]
[InlineData((long)-1, 1, true, false)]
[InlineData(1, (long)-1, false, true)]
[InlineData("a", "b", true, false)]
[InlineData("b", "a", false, true)]
[InlineData(3.0, 3.2, true, false)]
[InlineData("b", "b", true, true)]
[InlineData(3.0, 3.0, true, true)]
[Theory]
public void TestObjectNotStrictInequality(object? o1, object? o2, bool expectedLT, bool expectedGT)
{
using var obj1 = o1 is null ? null : PyObject.From(o1);
using var obj2 = o2 is null ? null : PyObject.From(o2);
Assert.Equal(expectedLT, obj1 <= obj2);
Assert.Equal(expectedGT, obj1 >= obj2);
}
}
87 changes: 70 additions & 17 deletions src/CSnakes.Runtime/Python/PyObject.cs
Original file line number Diff line number Diff line change
Expand Up @@ -183,14 +183,10 @@ public virtual bool Is(PyObject other)

public override bool Equals(object? obj)
{
if (obj is PyObject pyObj1) {
if (obj is PyObject pyObj1) {
if (Is(pyObj1))
return true;

using (GIL.Acquire())
{
return CPythonAPI.PyObject_RichCompare(this, pyObj1, CPythonAPI.RichComparisonType.Equal);
}
return Compare(this, pyObj1, CPythonAPI.RichComparisonType.Equal);
}
return base.Equals(obj);
}
Expand All @@ -201,26 +197,83 @@ public bool NotEquals(object? obj)
{
if (Is(pyObj1))
return false;

using (GIL.Acquire())
{
return CPythonAPI.PyObject_RichCompare(this, pyObj1, CPythonAPI.RichComparisonType.NotEqual);
}
return Compare(this, pyObj1, CPythonAPI.RichComparisonType.NotEqual);
}
return !base.Equals(obj);
}

public static bool operator ==(PyObject? left, PyObject? right)
{
if (left is null)
return right is null;
return left.Equals(right);
return (left, right) switch
{
(null, null) => true,
(_, null) => false,
(null, _) => false,
(_, _) => left.Equals(right),
};
}

public static bool operator !=(PyObject? left, PyObject? right)
{
if (left is null)
return right is not null;
return left.NotEquals(right);
return (left, right) switch
{
(null, null) => false,
(_, null) => true,
(null, _) => true,
(_, _) => left.NotEquals(right),
};
}

public static bool operator <=(PyObject? left, PyObject? right)
{
return (left, right) switch
{
(null, null) => true,
(_, null) => false,
(null, _) => false,
(_, _) => left.Is(right) || Compare(left, right, CPythonAPI.RichComparisonType.LessThanEqual),
};
}

public static bool operator >=(PyObject? left, PyObject? right)
{
return (left, right) switch
{
(null, null) => true,
(_, null) => false,
(null, _) => false,
(_, _) => left.Is(right) || Compare(left, right, CPythonAPI.RichComparisonType.GreaterThanEqual),
};
}

public static bool operator <(PyObject? left, PyObject? right)
{
return (left, right) switch
{
(null, null) => false,
(_, null) => false,
(null, _) => false,
(_, _) => Compare(left, right, CPythonAPI.RichComparisonType.LessThan),
};
}

public static bool operator >(PyObject? left, PyObject? right)
{
return (left, right) switch
{
(null, null) => false,
(_, null) => false,
(null, _) => false,
(_, _) => Compare(left, right, CPythonAPI.RichComparisonType.GreaterThan),
};
}

private static bool Compare(PyObject left, PyObject right, CPythonAPI.RichComparisonType type)
{
using (GIL.Acquire())
{
return CPythonAPI.PyObject_RichCompare(left, right, type);
}
}

public override int GetHashCode()
Expand Down

0 comments on commit ad9217c

Please sign in to comment.