Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Streamline Binary equality and comparison #110

Merged
merged 4 commits into from
Oct 19, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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()`
greymistcube marked this conversation as resolved.
Show resolved Hide resolved
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
Loading