diff --git a/Measure-Coverage.ps1 b/Measure-Coverage.ps1
index 12c3312..a214bbb 100644
--- a/Measure-Coverage.ps1
+++ b/Measure-Coverage.ps1
@@ -15,10 +15,10 @@ try {
Get-ChildItem -Directory src/*.Test*/TestResults/* | Remove-Item -Recurse
# rebuild target project to generate source generator files
- dotnet build src/QuantitiesDotNet.slnx --no-incremental --property:EmitCompilerGeneratedFiles=true
+ dotnet build QuantitiesDotNet.slnx --no-incremental --property:EmitCompilerGeneratedFiles=true
# test and measure coverage
- dotnet test src/QuantitiesDotNet.slnx --collect:"XPlat Code Coverage" --settings src/etc/coverlet.runsettings
+ dotnet test QuantitiesDotNet.slnx --collect:"XPlat Code Coverage" --settings src/etc/coverlet.runsettings
# export HTML coverage report
Get-ChildItem src/*.Test*/TestResults/*/coverage.cobertura.xml `
diff --git a/global.json b/global.json
index c30100d..1e2cd47 100644
--- a/global.json
+++ b/global.json
@@ -1,6 +1,6 @@
{
"sdk": {
- "version": "10.0.101",
+ "version": "10.0.0",
"rollForward": "latestFeature"
}
}
diff --git a/src/QuantitiesDotNet.Generators/QuantityImplementBuilder.cs b/src/QuantitiesDotNet.Generators/QuantityImplementBuilder.cs
index b6e715c..5aa7418 100644
--- a/src/QuantitiesDotNet.Generators/QuantityImplementBuilder.cs
+++ b/src/QuantitiesDotNet.Generators/QuantityImplementBuilder.cs
@@ -308,25 +308,27 @@ private void GenerateSelfOperatorsShape(SourceBuilderSlim sb)
///
///
///
- public static bool Equals({{TypeName}} x, {{TypeName}} y)
- => x._rawValue == y._rawValue;
+ public static bool Equals({{TypeName}} x, {{TypeName}} y) =>
+ x._rawValue == y._rawValue;
/// Determines which value is greater than another.
///
///
///
- public static int Compare({{TypeName}} x, {{TypeName}} y)
- {
- if (x._rawValue == y._rawValue) { return 0; }
- return x._rawValue < y._rawValue ? -1 : 1;
- }
-
- /** */ public static bool operator ==({{TypeName}} x, {{TypeName}} y) => Equals(x, y);
- /** */ public static bool operator !=({{TypeName}} x, {{TypeName}} y) => !Equals(x, y);
- /** */ public static bool operator < ({{TypeName}} x, {{TypeName}} y) => Compare(x, y) < 0;
- /** */ public static bool operator > ({{TypeName}} x, {{TypeName}} y) => Compare(x, y) > 0;
- /** */ public static bool operator <=({{TypeName}} x, {{TypeName}} y) => Compare(x, y) <= 0;
- /** */ public static bool operator >=({{TypeName}} x, {{TypeName}} y) => Compare(x, y) >= 0;
+ public static int Compare({{TypeName}} x, {{TypeName}} y) =>
+ (x._rawValue < y._rawValue, x._rawValue > y._rawValue) switch
+ {
+ (true, false) => -1,
+ (false, true) => +1,
+ _ => 0,
+ };
+
+ /** */ public static bool operator ==({{TypeName}} x, {{TypeName}} y) => x._rawValue == y._rawValue;
+ /** */ public static bool operator !=({{TypeName}} x, {{TypeName}} y) => x._rawValue != y._rawValue;
+ /** */ public static bool operator < ({{TypeName}} x, {{TypeName}} y) => x._rawValue < y._rawValue;
+ /** */ public static bool operator > ({{TypeName}} x, {{TypeName}} y) => x._rawValue > y._rawValue;
+ /** */ public static bool operator <=({{TypeName}} x, {{TypeName}} y) => x._rawValue <= y._rawValue;
+ /** */ public static bool operator >=({{TypeName}} x, {{TypeName}} y) => x._rawValue >= y._rawValue;
#endregion comparison operator implements
diff --git a/src/QuantitiesDotNet.Test/QuantityTest.cs b/src/QuantitiesDotNet.Test/QuantityTest.cs
index 1ade5b1..d5c5cc5 100644
--- a/src/QuantitiesDotNet.Test/QuantityTest.cs
+++ b/src/QuantitiesDotNet.Test/QuantityTest.cs
@@ -60,8 +60,12 @@ public void Compare_NonGeneric(T placeHolder)
where T : struct, IQuantity
{
InternalHelpers.NoUse(placeHolder);
- var _0 = Unsafe.BitCast(0.0);
+ var p0 = Unsafe.BitCast(+0.0);
+ var n0 = Unsafe.BitCast(-0.0);
var _1 = Unsafe.BitCast(1.0);
+ var nan = Unsafe.BitCast(double.NaN);
+ var pinf = Unsafe.BitCast(double.PositiveInfinity);
+ var ninf = Unsafe.BitCast(double.NegativeInfinity);
Assert.Equal(_1, _1);
Assert.True (_1.Equals(_1));
@@ -75,34 +79,90 @@ public void Compare_NonGeneric(T placeHolder)
Assert.False(_1 > _1);
Assert.True (_1 <= _1);
Assert.False(_1 < _1);
+ Assert.Equal(_1.GetHashCode(), _1.GetHashCode());
+
+ Assert.NotEqual(p0, _1);
+ Assert.False(p0.Equals(_1));
+ Assert.False(p0.Equals((object)_1));
+ Assert.False(T.Equals(p0, _1));
+ Assert.True(0 > T.Compare(p0, _1));
+ Assert.True(0 > p0.CompareTo(_1));
+ Assert.False(p0 == _1);
+ Assert.True (p0 != _1);
+ Assert.False(p0 >= _1);
+ Assert.False(p0 > _1);
+ Assert.True (p0 <= _1);
+ Assert.True (p0 < _1);
+
+ Assert.NotEqual(_1, p0);
+ Assert.False(_1.Equals(p0));
+ Assert.False(_1.Equals((object)p0));
+ Assert.False(T.Equals(_1, p0));
+ Assert.True(0 < T.Compare(_1, p0));
+ Assert.True(0 < _1.CompareTo(p0));
+ Assert.False(_1 == p0);
+ Assert.True (_1 != p0);
+ Assert.True (_1 >= p0);
+ Assert.True (_1 > p0);
+ Assert.False(_1 <= p0);
+ Assert.False(_1 < p0);
+
+ Assert.False(p0.Equals(new object()));
+
+ Assert.Equal(+0.0.GetHashCode(), p0.GetHashCode());
+ Assert.Equal(-0.0.GetHashCode(), n0.GetHashCode());
+ Assert.Equal(1.0.GetHashCode(), _1.GetHashCode());
+ Assert.Equal(double.NaN.GetHashCode(), nan.GetHashCode());
+ Assert.Equal(double.PositiveInfinity.GetHashCode(), pinf.GetHashCode());
+ Assert.Equal(double.NegativeInfinity.GetHashCode(), ninf.GetHashCode());
+
+#pragma warning disable format
+#pragma warning disable CA2242
+ static int compare(double x, double y) =>
+ (x < y, x > y) switch
+ {
+ (true, false) => -1,
+ (false, true) => +1,
+ _ => 0,
+ };
+
+ Assert.Equal(+0.0 == +0.0, p0 == p0);
+ Assert.Equal(+0.0 < +0.0, p0 < p0);
+ Assert.Equal(+0.0 > +0.0, p0 > p0);
+ Assert.Equal(+0.0 <= +0.0, p0 <= p0);
+ Assert.Equal(+0.0 >= +0.0, p0 >= p0);
+ Assert.Equal(compare(+0.0, +0.0), T.Compare(p0, p0));
+
+ Assert.Equal(+0.0 == -0.0, p0 == n0);
+ Assert.Equal(+0.0 < -0.0, p0 < n0);
+ Assert.Equal(+0.0 > -0.0, p0 > n0);
+ Assert.Equal(+0.0 <= -0.0, p0 <= n0);
+ Assert.Equal(+0.0 >= -0.0, p0 >= n0);
+ Assert.Equal(compare(+0.0, -0.0), T.Compare(p0, n0));
+
+ Assert.Equal(double.NaN == double.NaN, nan == nan);
+ Assert.Equal(double.NaN < double.NaN, nan < nan);
+ Assert.Equal(double.NaN > double.NaN, nan > nan);
+ Assert.Equal(double.NaN <= double.NaN, nan <= nan);
+ Assert.Equal(double.NaN >= double.NaN, nan >= nan);
+ Assert.Equal(compare(double.NaN, double.NaN), T.Compare(nan, nan));
+
+ Assert.Equal(double.PositiveInfinity == double.PositiveInfinity, pinf == pinf);
+ Assert.Equal(double.PositiveInfinity < double.PositiveInfinity, pinf < pinf);
+ Assert.Equal(double.PositiveInfinity > double.PositiveInfinity, pinf > pinf);
+ Assert.Equal(double.PositiveInfinity <= double.PositiveInfinity, pinf <= pinf);
+ Assert.Equal(double.PositiveInfinity >= double.PositiveInfinity, pinf >= pinf);
+ Assert.Equal(compare(double.PositiveInfinity, double.PositiveInfinity), T.Compare(pinf, pinf));
+
+ Assert.Equal(double.NegativeInfinity == double.NegativeInfinity, ninf == ninf);
+ Assert.Equal(double.NegativeInfinity < double.NegativeInfinity, ninf < ninf);
+ Assert.Equal(double.NegativeInfinity > double.NegativeInfinity, ninf > ninf);
+ Assert.Equal(double.NegativeInfinity <= double.NegativeInfinity, ninf <= ninf);
+ Assert.Equal(double.NegativeInfinity >= double.NegativeInfinity, ninf >= ninf);
+ Assert.Equal(compare(double.NegativeInfinity, double.NegativeInfinity), T.Compare(ninf, ninf));
+#pragma warning restore CA2242
+#pragma warning restore format
- Assert.NotEqual(_0, _1);
- Assert.False(_0.Equals(_1));
- Assert.False(_0.Equals((object)_1));
- Assert.False(T.Equals(_0, _1));
- Assert.True(0 > T.Compare(_0, _1));
- Assert.True(0 > _0.CompareTo(_1));
- Assert.False(_0 == _1);
- Assert.True (_0 != _1);
- Assert.False(_0 >= _1);
- Assert.False(_0 > _1);
- Assert.True (_0 <= _1);
- Assert.True (_0 < _1);
-
- Assert.NotEqual(_1, _0);
- Assert.False(_1.Equals(_0));
- Assert.False(_1.Equals((object)_0));
- Assert.False(T.Equals(_1, _0));
- Assert.True(0 < T.Compare(_1, _0));
- Assert.True(0 < _1.CompareTo(_0));
- Assert.False(_1 == _0);
- Assert.True (_1 != _0);
- Assert.True (_1 >= _0);
- Assert.True (_1 > _0);
- Assert.False(_1 <= _0);
- Assert.False(_1 < _0);
-
- Assert.False(_0.Equals(new object()));
}
[Theory]
@@ -111,7 +171,8 @@ public void Compare_Generic(T placeHolder)
where T : struct, IQuantity
{
InternalHelpers.NoUse(placeHolder);
- var _0 = Unsafe.BitCast(0.0m);
+ var p0 = Unsafe.BitCast(+0.0m);
+ var n0 = Unsafe.BitCast(-0.0m);
var _1 = Unsafe.BitCast(1.0m);
Assert.Equal(_1, _1);
@@ -126,34 +187,65 @@ public void Compare_Generic(T placeHolder)
Assert.False(_1 > _1);
Assert.True (_1 <= _1);
Assert.False(_1 < _1);
-
- Assert.NotEqual(_0, _1);
- Assert.False(_0.Equals(_1));
- Assert.False(_0.Equals((object)_1));
- Assert.False(T.Equals(_0, _1));
- Assert.True(0 > T.Compare(_0, _1));
- Assert.True(0 > _0.CompareTo(_1));
- Assert.False(_0 == _1);
- Assert.True (_0 != _1);
- Assert.False(_0 >= _1);
- Assert.False(_0 > _1);
- Assert.True (_0 <= _1);
- Assert.True (_0 < _1);
-
- Assert.NotEqual(_1, _0);
- Assert.False(_1.Equals(_0));
- Assert.False(_1.Equals((object)_0));
- Assert.False(T.Equals(_1, _0));
- Assert.True(0 < T.Compare(_1, _0));
- Assert.True(0 < _1.CompareTo(_0));
- Assert.False(_1 == _0);
- Assert.True (_1 != _0);
- Assert.True (_1 >= _0);
- Assert.True (_1 > _0);
- Assert.False(_1 <= _0);
- Assert.False(_1 < _0);
-
- Assert.False(_0.Equals(new object()));
+ Assert.Equal(_1.GetHashCode(), _1.GetHashCode());
+
+ Assert.NotEqual(p0, _1);
+ Assert.False(p0.Equals(_1));
+ Assert.False(p0.Equals((object)_1));
+ Assert.False(T.Equals(p0, _1));
+ Assert.True(0 > T.Compare(p0, _1));
+ Assert.True(0 > p0.CompareTo(_1));
+ Assert.False(p0 == _1);
+ Assert.True (p0 != _1);
+ Assert.False(p0 >= _1);
+ Assert.False(p0 > _1);
+ Assert.True (p0 <= _1);
+ Assert.True (p0 < _1);
+
+ Assert.NotEqual(_1, p0);
+ Assert.False(_1.Equals(p0));
+ Assert.False(_1.Equals((object)p0));
+ Assert.False(T.Equals(_1, p0));
+ Assert.True(0 < T.Compare(_1, p0));
+ Assert.True(0 < _1.CompareTo(p0));
+ Assert.False(_1 == p0);
+ Assert.True (_1 != p0);
+ Assert.True (_1 >= p0);
+ Assert.True (_1 > p0);
+ Assert.False(_1 <= p0);
+ Assert.False(_1 < p0);
+
+ Assert.False(p0.Equals(new object()));
+
+ Assert.Equal(+0.0m.GetHashCode(), p0.GetHashCode());
+ Assert.Equal(-0.0m.GetHashCode(), n0.GetHashCode());
+ Assert.Equal(1.0m.GetHashCode(), _1.GetHashCode());
+
+#pragma warning disable format
+#pragma warning disable CA2242
+ static int compare(double x, double y) =>
+ (x < y, x > y) switch
+ {
+ (true, false) => -1,
+ (false, true) => +1,
+ _ => 0,
+ };
+
+ Assert.Equal(+0.0 == +0.0, p0 == p0);
+ Assert.Equal(+0.0 < +0.0, p0 < p0);
+ Assert.Equal(+0.0 > +0.0, p0 > p0);
+ Assert.Equal(+0.0 <= +0.0, p0 <= p0);
+ Assert.Equal(+0.0 >= +0.0, p0 >= p0);
+ Assert.Equal(compare(+0.0, +0.0), T.Compare(p0, p0));
+
+ Assert.Equal(+0.0 == -0.0, p0 == n0);
+ Assert.Equal(+0.0 < -0.0, p0 < n0);
+ Assert.Equal(+0.0 > -0.0, p0 > n0);
+ Assert.Equal(+0.0 <= -0.0, p0 <= n0);
+ Assert.Equal(+0.0 >= -0.0, p0 >= n0);
+ Assert.Equal(compare(+0.0, -0.0), T.Compare(p0, n0));
+#pragma warning restore CA2242
+#pragma warning restore format
}
#pragma warning restore CS1718
diff --git a/src/QuantitiesDotNet/IQuantity.cs b/src/QuantitiesDotNet/IQuantity.cs
index 0418cde..87ef13a 100644
--- a/src/QuantitiesDotNet/IQuantity.cs
+++ b/src/QuantitiesDotNet/IQuantity.cs
@@ -39,13 +39,36 @@ public interface IQuantity
///
///
///
+ ///
+ /// The implementation must be x.RawValue == y.RawValue.
+ /// The behaviour for edge cases conforms to the implementation of .
+ ///
public static abstract bool Equals(TSelf x, TSelf y);
/// Determines which value is greater than another.
///
///
///
+ ///
+ /// The implementation must be x.RawValue == y.RawValue ? 0 : (x.RawValue < y.RawValue ? -1 : 1).
+ /// The behaviour for edge cases conforms to the implementation of .
+ ///
public static abstract int Compare(TSelf x, TSelf y);
+ ///
+ ///
+ /// The implementation must be:
+ ///
+ /// (x.RawValue < y.RawValue, x.RawValue > y.RawValue) switch
+ /// {
+ /// (true, false) => -1,
+ /// (false, true) => +1,
+ /// _ => 0,
+ /// }
+ ///
+ /// The behaviour for edge cases conforms to the implementation of .
+ ///
+ public int GetHashCode();
+
#endif
}