Skip to content

Commit

Permalink
Merge pull request #110 from greymistcube/refactor/binary-equality
Browse files Browse the repository at this point in the history
Streamline `Binary` equality and comparison
  • Loading branch information
greymistcube authored Oct 19, 2023
2 parents 6d30b55 + df50054 commit f7f265d
Show file tree
Hide file tree
Showing 6 changed files with 93 additions and 133 deletions.
21 changes: 0 additions & 21 deletions Bencodex.Tests/Misc/ByteArrayComparerTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,27 +7,6 @@ namespace Bencodex.Tests.Misc
{
public class ByteArrayComparerTest
{
[Fact]
public void CompareMutableArrays()
{
var comparer = default(ByteArrayComparer);
ComparerTestUtils.TestComparison(
comparer,
new List<byte[]>()
{
new byte[] { },
new byte[] { 0x00 },
new byte[] { 0x00, 0x00 },
new byte[] { 0x00, 0x80 },
new byte[] { 0x00, 0xff },
new byte[] { 0x01 },
new byte[] { 0x01, 0x01 },
new byte[] { 0x01, 0x80 },
new byte[] { 0x01, 0xff },
}
);
}

[Fact]
public void CompareImmutableArrays()
{
Expand Down
4 changes: 2 additions & 2 deletions Bencodex.Tests/Misc/ImplicitConversionTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -41,10 +41,10 @@ public void Binary()
{
var binary = new Binary(new byte[] { 0x01, 0x02, 0x03 });

ImmutableArray<byte> immutable = binary;
ImmutableArray<byte> immutable = (ImmutableArray<byte>)binary;
Assert.Equal(immutable, binary.ByteArray);

byte[] mutable = binary;
byte[] mutable = (byte[])binary;
Assert.Equal(mutable, binary.ToByteArray());
}

Expand Down
90 changes: 58 additions & 32 deletions Bencodex.Tests/Types/BinaryTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,64 @@ public void DefaultConstructor()
Assert.Empty(default(Binary).ToByteArray());
}

[Fact]
public void Equality()
{
byte[] b = new byte[] { 0, 1 };
ImmutableArray<byte> i = ImmutableArray.Create(b);
Binary x = new Binary(i);
object ob = (object)b;
object oi = (object)i;
object ox = (object)x;

#pragma warning disable CS1718 // Comparison made to same variable
Assert.True(x == x);
Assert.True(x.Equals(x));
Assert.True(x.Equals(ox));
Assert.True(ox.Equals(x));
Assert.True(ox.Equals(ox));
#pragma warning restore CS1718

// Unlike Integer and Text, implicit conversion is not supported.
Assert.False(b.Equals(x));
Assert.False(i.Equals(x));
Assert.False(x.Equals(b));
Assert.False(x.Equals(i));

Assert.False(b.Equals(ox));
Assert.False(i.Equals(ox));
Assert.False(ox.Equals(b));
Assert.False(ox.Equals(i));

Assert.False(ob.Equals(ox));
Assert.False(oi.Equals(ox));
Assert.False(ox.Equals(ob));
Assert.False(ox.Equals(oi));

Binary empty = new Binary(Array.Empty<byte>());
IValue n = Null.Value;
Assert.False(empty.Equals(x));
Assert.False(x.Equals(empty));
Assert.False(empty.Equals(n));
Assert.False(n.Equals(empty));
}

[Fact]
public void Comparison()
{
Binary b0 = new Binary(new byte[] { 0 });
Binary b1 = new Binary(new byte[] { 1 });
Binary b00 = new Binary(new byte[] { 0, 0 });

Assert.Equal(0, b0.CompareTo(b0));
Assert.True(b0.CompareTo(b1) < 0);
Assert.True(b1.CompareTo(b0) > 0);
Assert.True(b0.CompareTo(b00) < 0);
Assert.True(b00.CompareTo(b0) > 0);
Assert.True(b1.CompareTo(b00) > 0);
Assert.True(b00.CompareTo(b1) < 0);
}

[Fact]
public void ConstructorTakingImmutableByteArray()
{
Expand Down Expand Up @@ -140,38 +198,6 @@ public void ToByteArray()
);
}

[Fact]
public void Equality()
{
Assert.Equal(_empty, new Binary(new byte[0]));
Assert.Equal<IValue>(_empty, new Binary(new byte[0]));
Assert.Equal(_empty, ImmutableArray<byte>.Empty);
Assert.Equal(_empty, new byte[0]);

Assert.Equal(
_hello,
new Binary(new byte[] { 0x68, 0x65, 0x6c, 0x6c, 0x6f })
);
Assert.Equal(
_hello,
new byte[] { 0x68, 0x65, 0x6c, 0x6c, 0x6f }.ToImmutableArray<byte>()
);
Assert.Equal(
_hello,
new byte[] { 0x68, 0x65, 0x6c, 0x6c, 0x6f }
);

Assert.NotEqual(_empty, _hello);
Assert.NotEqual<IValue>(_empty, _hello);
Assert.NotEqual(
_hello,
new Binary(new byte[] { 0x68, 0x65, 0x6c, 0x6f, 0x6f })
);

Assert.NotEqual<IValue>(Null.Value, _empty);
Assert.NotEqual<IValue>(Null.Value, _hello);
}

[Fact]
public void EncodingLength()
{
Expand Down
15 changes: 1 addition & 14 deletions Bencodex/Misc/ByteArrayComparer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,26 +9,13 @@ namespace Bencodex.Misc
/// Similar to <see cref="StringComparer"/> but for <see cref="byte"/>s instead of Unicode
/// <see cref="string"/>s.
/// </summary>
public struct ByteArrayComparer
: IComparer<byte[]>, IComparer<ImmutableArray<byte>>, IComparer<IReadOnlyList<byte>>
public struct ByteArrayComparer : IComparer<ImmutableArray<byte>>
{
private static readonly ByteArrayComparer<byte[]> _mutableArrayComparer =
new ByteArrayComparer<byte[]>();

private static readonly ByteArrayComparer<ImmutableArray<byte>> _immutableArrayComparer =
new ByteArrayComparer<ImmutableArray<byte>>();

private static readonly ByteArrayComparer<IReadOnlyList<byte>> _readOnlyListComparer =
new ByteArrayComparer<IReadOnlyList<byte>>();

public int Compare(byte[] x, byte[] y) =>
_mutableArrayComparer.Compare(x, y);

public int Compare(ImmutableArray<byte> x, ImmutableArray<byte> y) =>
_immutableArrayComparer.Compare(x, y);

public int Compare(IReadOnlyList<byte> x, IReadOnlyList<byte> y) =>
_readOnlyListComparer.Compare(x, y);
}

internal class ByteArrayComparer<T> : IComparer<T>
Expand Down
88 changes: 24 additions & 64 deletions Bencodex/Types/Binary.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,7 @@ namespace Bencodex.Types
{
public readonly struct Binary :
IKey,
IEquatable<ImmutableArray<byte>>,
IEquatable<byte[]>,
IEquatable<Binary>,
IComparable<ImmutableArray<byte>>,
IComparable<byte[]>,
IComparable<Binary>,
IComparable,
IEnumerable<byte>
Expand Down Expand Up @@ -89,29 +85,21 @@ public Fingerprint Fingerprint
[Obsolete("Deprecated in favour of " + nameof(Inspect) + "() method.")]
public string Inspection => Inspect(true);

public static implicit operator Binary(ImmutableArray<byte> bytes) =>
public static explicit operator Binary(ImmutableArray<byte> bytes) =>
new Binary(bytes);

public static implicit operator ImmutableArray<byte>(Binary binary) =>
public static explicit operator ImmutableArray<byte>(Binary binary) =>
binary.ByteArray;

public static implicit operator Binary(byte[] bytes)
{
return new Binary(bytes);
}
public static explicit operator Binary(byte[] bytes) =>
new Binary(bytes);

public static implicit operator byte[](Binary binary) =>
public static explicit operator byte[](Binary binary) =>
binary.ToByteArray();

public static bool operator ==(Binary left, Binary right)
{
return left.Equals(right);
}
public static bool operator ==(Binary left, Binary right) => left.Equals(right);

public static bool operator !=(Binary left, Binary right)
{
return !left.Equals(right);
}
public static bool operator !=(Binary left, Binary right) => !left.Equals(right);

/// <summary>
/// Creates a new <see cref="Binary"/> instance from a binary turned into
Expand Down Expand Up @@ -229,30 +217,11 @@ public static Binary FromBase64(string base64)
return new Binary(moved);
}

bool IEquatable<ImmutableArray<byte>>.Equals(ImmutableArray<byte> other) =>
ByteArray.SequenceEqual(other);
public override bool Equals(object? obj) => obj is Binary other && Equals(other);

bool IEquatable<byte[]>.Equals(byte[] other) =>
ByteArray.SequenceEqual(other);
public bool Equals(IValue other) => other is Binary i && Equals(i);

bool IEquatable<Binary>.Equals(Binary other) =>
((IEquatable<ImmutableArray<byte>>)this).Equals(other.ByteArray);

bool IEquatable<IValue>.Equals(IValue other) =>
other is Binary o && ((IEquatable<Binary>)this).Equals(o);

public override bool Equals(object obj) =>
obj switch
{
Binary b =>
((IEquatable<Binary>)this).Equals(b),
ImmutableArray<byte> b =>
((IEquatable<ImmutableArray<byte>>)this).Equals(b),
byte[] b =>
((IEquatable<byte[]>)this).Equals(b),
_ =>
false,
};
public bool Equals(Binary other) => ByteArray.SequenceEqual(other.ByteArray);

public override int GetHashCode()
{
Expand Down Expand Up @@ -287,32 +256,23 @@ public override int GetHashCode()
return hash;
}

int IComparable<ImmutableArray<byte>>.CompareTo(ImmutableArray<byte> other) =>
ByteArrayComparer.Compare(ByteArray, other);

int IComparable<byte[]>.CompareTo(byte[] other) =>
ByteArrayComparer.Compare(ByteArray, other);
public int CompareTo(Binary other) =>
ByteArrayComparer.Compare(ByteArray, other.ByteArray);

int IComparable<Binary>.CompareTo(Binary other) =>
((IComparable<ImmutableArray<byte>>)this).CompareTo(other.ByteArray);
public int CompareTo(object? obj)
{
if (obj is null)
{
return 1;
}

int IComparable.CompareTo(object obj) =>
obj switch
if (obj is Binary b)
{
null =>
1,
Binary binary =>
((IComparable<Binary>)this).CompareTo(binary),
ImmutableArray<byte> bytes =>
((IComparable<ImmutableArray<byte>>)this).CompareTo(bytes),
byte[] bytes =>
((IComparable<byte[]>)this).CompareTo(bytes),
_ =>
throw new ArgumentException(
"the argument is neither Binary nor Byte[]",
nameof(obj)
),
};
return CompareTo(b);
}

throw new ArgumentException($"Object must be of type {nameof(Binary)}");
}

public IEnumerator<byte> GetEnumerator() =>
((IEnumerable<byte>)ByteArray).GetEnumerator();
Expand Down
8 changes: 8 additions & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,20 @@ To be released.
- Removed `IEquatable<string>` and `IComparable<string>` from `Text`.
[[#104], [#108]]
- Removed `CompositeComparer<TA, TB>` struct. [[#109]]
- Removed `IEquatable<byte[]>`, `IEquatable<ImmutableArray<byte>>`,
`IComparable<byte[]>`, and `IComparable<ImmutableArray<byte>>` from
`Binary`. [[#104], [#110]]
- Removed `IComparer<byte[]>` and `IComparer<ReadOnlyList<byte>>` from
`ByteArrayComparer`. [[#110]]
- Changed the behaviors of `Binary.Equals()` and `Binary.CompareTo()`
to be more consistent. [[#106], [#110]]

[#104]: https://github.com/planetarium/bencodex.net/issues/104
[#106]: https://github.com/planetarium/bencodex.net/issues/106
[#107]: https://github.com/planetarium/bencodex.net/pull/107
[#108]: https://github.com/planetarium/bencodex.net/pull/108
[#109]: https://github.com/planetarium/bencodex.net/pull/109
[#110]: https://github.com/planetarium/bencodex.net/pull/110


Version 0.14.0
Expand Down

0 comments on commit f7f265d

Please sign in to comment.