Skip to content

Commit

Permalink
[fixes] UInt160 Class (#3422)
Browse files Browse the repository at this point in the history
* Fixed `UInt160` and expanded class

* Cleaned up code for `TryParse`

* Fixed `TryParse`

* Fixed small bug with `TryParse`

* Change `UInt160.Zero` to `static readonly`

* benchmark UInt160

* Fix benchmark

* Fixed bugs and added features for `UInt160` class

* Revert and just keep bug fixes

* Made @shargon changes

* Set `InvariantCultureIgnoreCase` back for `0x` and `0X`

---------

Co-authored-by: Shargon <shargon@gmail.com>
Co-authored-by: Jimmy <jinghui@wayne.edu>
Co-authored-by: Jimmy <jimmy@r3e.network>
  • Loading branch information
4 people committed Aug 29, 2024
1 parent 9ce9c6f commit 5fe5462
Show file tree
Hide file tree
Showing 6 changed files with 430 additions and 51 deletions.
156 changes: 156 additions & 0 deletions benchmarks/Neo.Benchmarks/Benchmarks.UInt160.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,156 @@
// Copyright (C) 2015-2024 The Neo Project.
//
// Benchmarks.UInt160.cs file belongs to the neo project and is free
// software distributed under the MIT software license, see the
// accompanying file LICENSE in the main directory of the
// repository or http://www.opensource.org/licenses/mit-license.php
// for more details.
//
// Redistribution and use in source and binary forms with or without
// modifications are permitted.

using BenchmarkDotNet.Attributes;

namespace Neo.Benchmark;

public class Benchmarks_UInt160
{
static readonly OldUInt160 s_oldUInt160 = new([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1]);
static readonly UInt160 s_newUInt160 = new([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1]);

[Benchmark]
public void TestOldUInt160Gernerator1()
{
_ = new OldUInt160();
}

[Benchmark]
public void TestOldUInt160Gernerator2()
{
_ = new OldUInt160(new byte[20]);
}

[Benchmark]
public void TestOldUInt160CompareTo()
{
OldUInt160.Zero.CompareTo(OldUInt160.Zero);
OldUInt160.Zero.CompareTo(s_oldUInt160);
s_oldUInt160.CompareTo(OldUInt160.Zero);
}

[Benchmark]
public void TestOldUInt160Equals()
{
OldUInt160.Zero.Equals(OldUInt160.Zero);
OldUInt160.Zero.Equals(s_oldUInt160);
s_oldUInt160.Equals(null);
}

[Benchmark]
public void TestOldUInt160Parse()
{
_ = OldUInt160.Parse("0x0000000000000000000000000000000000000000");
_ = OldUInt160.Parse("0000000000000000000000000000000000000000");
}

[Benchmark]
public void TestOldUInt160TryParse()
{
OldUInt160.TryParse(null, out _);
OldUInt160.TryParse("0x0000000000000000000000000000000000000000", out var temp);
OldUInt160.TryParse("0x1230000000000000000000000000000000000000", out temp);
OldUInt160.TryParse("000000000000000000000000000000000000000", out _);
}

[Benchmark]
public void TestOldUInt160OperatorLarger()
{
_ = s_oldUInt160 > OldUInt160.Zero;
}

[Benchmark]
public void TestOldUInt160OperatorLargerAndEqual()
{
_ = s_oldUInt160 >= OldUInt160.Zero;
}

[Benchmark]
public void TestOldUInt160OperatorSmaller()
{
_ = s_oldUInt160 < OldUInt160.Zero;
}

[Benchmark]
public void TestOldUInt160OperatorSmallerAndEqual()
{
_ = s_oldUInt160 <= OldUInt160.Zero;
}

[Benchmark]
public void TestGernerator1()
{
_ = new UInt160();
}

[Benchmark]
public void TestGernerator2()
{
_ = new UInt160(new byte[20]);
}

[Benchmark]
public void TestCompareTo()
{
UInt160.Zero.CompareTo(UInt160.Zero);
UInt160.Zero.CompareTo(s_newUInt160);
s_newUInt160.CompareTo(UInt160.Zero);
}

[Benchmark]
public void TestEquals()
{
UInt160.Zero.Equals(UInt160.Zero);
UInt160.Zero.Equals(s_newUInt160);
s_newUInt160.Equals(null);
}

[Benchmark]
public void TestParse()
{
_ = UInt160.Parse("0x0000000000000000000000000000000000000000");
_ = UInt160.Parse("0000000000000000000000000000000000000000");
}

[Benchmark]
public void TestTryParse()
{
UInt160.TryParse(null, out _);
UInt160.TryParse("0x0000000000000000000000000000000000000000", out var temp);
UInt160.TryParse("0x1230000000000000000000000000000000000000", out temp);
UInt160.TryParse("000000000000000000000000000000000000000", out _);
}

[Benchmark]
public void TestOperatorLarger()
{
_ = s_newUInt160 > UInt160.Zero;
}

[Benchmark]
public void TestOperatorLargerAndEqual()
{
_ = s_newUInt160 >= UInt160.Zero;
}

[Benchmark]
public void TestOperatorSmaller()
{
_ = s_newUInt160 < UInt160.Zero;
}

[Benchmark]
public void TestOperatorSmallerAndEqual()
{
_ = s_newUInt160 <= UInt160.Zero;
}
}
1 change: 1 addition & 0 deletions benchmarks/Neo.Benchmarks/Neo.Benchmarks.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
<TargetFrameworks>net8.0</TargetFrameworks>
<RootNamespace>Neo</RootNamespace>
<ImplicitUsings>enable</ImplicitUsings>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>

<ItemGroup>
Expand Down
184 changes: 184 additions & 0 deletions benchmarks/Neo.Benchmarks/OldUInt160.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,184 @@
// Copyright (C) 2015-2024 The Neo Project.
//
// OldUInt160.cs file belongs to the neo project and is free
// software distributed under the MIT software license, see the
// accompanying file LICENSE in the main directory of the
// repository or http://www.opensource.org/licenses/mit-license.php
// for more details.
//
// Redistribution and use in source and binary forms with or without
// modifications are permitted.

using Neo.Extensions;
using Neo.IO;
using System.Globalization;
using System.Runtime.InteropServices;

namespace Neo
{
/// <summary>
/// Represents a 160-bit unsigned integer.
/// </summary>
[StructLayout(LayoutKind.Explicit, Size = 20)]
public class OldUInt160 : IComparable<OldUInt160>, IEquatable<OldUInt160>, ISerializable
{
/// <summary>
/// The length of <see cref="OldUInt160"/> values.
/// </summary>
public const int Length = 20;

/// <summary>
/// Represents 0.
/// </summary>
public static readonly OldUInt160 Zero = new();

[FieldOffset(0)] private ulong value1;
[FieldOffset(8)] private ulong value2;
[FieldOffset(16)] private uint value3;

public int Size => Length;

/// <summary>
/// Initializes a new instance of the <see cref="OldUInt160"/> class.
/// </summary>
public OldUInt160()
{
}

/// <summary>
/// Initializes a new instance of the <see cref="OldUInt160"/> class.
/// </summary>
/// <param name="value">The value of the <see cref="OldUInt160"/>.</param>
public unsafe OldUInt160(ReadOnlySpan<byte> value)
{
if (value.Length != Length) throw new FormatException();
fixed (ulong* p = &value1)
{
Span<byte> dst = new(p, Length);
value[..Length].CopyTo(dst);
}
}

public int CompareTo(OldUInt160 other)
{
int result = value3.CompareTo(other.value3);
if (result != 0) return result;
result = value2.CompareTo(other.value2);
if (result != 0) return result;
return value1.CompareTo(other.value1);
}

public void Deserialize(ref MemoryReader reader)
{
value1 = reader.ReadUInt64();
value2 = reader.ReadUInt64();
value3 = reader.ReadUInt32();
}

public override bool Equals(object obj)
{
if (ReferenceEquals(obj, this)) return true;
return Equals(obj as OldUInt160);
}

public bool Equals(OldUInt160 other)
{
if (other is null) return false;
return value1 == other.value1
&& value2 == other.value2
&& value3 == other.value3;
}

public override int GetHashCode()
{
return (int)value1;
}

/// <summary>
/// Parses an <see cref="OldUInt160"/> from the specified <see cref="string"/>.
/// </summary>
/// <param name="value">An <see cref="OldUInt160"/> represented by a <see cref="string"/>.</param>
/// <returns>The parsed <see cref="OldUInt160"/>.</returns>
/// <exception cref="FormatException"><paramref name="value"/> is not in the correct format.</exception>
public static OldUInt160 Parse(string value)
{
if (!TryParse(value, out var result)) throw new FormatException();
return result;
}

public void Serialize(BinaryWriter writer)
{
writer.Write(value1);
writer.Write(value2);
writer.Write(value3);
}

public override string ToString()
{
return "0x" + this.ToArray().ToHexString(reverse: true);
}

/// <summary>
/// Parses an <see cref="OldUInt160"/> from the specified <see cref="string"/>.
/// </summary>
/// <param name="s">An <see cref="OldUInt160"/> represented by a <see cref="string"/>.</param>
/// <param name="result">The parsed <see cref="OldUInt160"/>.</param>
/// <returns><see langword="true"/> if an <see cref="OldUInt160"/> is successfully parsed; otherwise, <see langword="false"/>.</returns>
public static bool TryParse(string s, out OldUInt160 result)
{
if (s == null)
{
result = null;
return false;
}
if (s.StartsWith("0x", StringComparison.InvariantCultureIgnoreCase))
s = s[2..];
if (s.Length != Length * 2)
{
result = null;
return false;
}
byte[] data = new byte[Length];
for (int i = 0; i < Length; i++)
if (!byte.TryParse(s.Substring(i * 2, 2), NumberStyles.AllowHexSpecifier, null, out data[Length - i - 1]))
{
result = null;
return false;
}
result = new OldUInt160(data);
return true;
}

public static bool operator ==(OldUInt160 left, OldUInt160 right)
{
if (ReferenceEquals(left, right)) return true;
if (left is null || right is null) return false;
return left.Equals(right);
}

public static bool operator !=(OldUInt160 left, OldUInt160 right)
{
return !(left == right);
}

public static bool operator >(OldUInt160 left, OldUInt160 right)
{
return left.CompareTo(right) > 0;
}

public static bool operator >=(OldUInt160 left, OldUInt160 right)
{
return left.CompareTo(right) >= 0;
}

public static bool operator <(OldUInt160 left, OldUInt160 right)
{
return left.CompareTo(right) < 0;
}

public static bool operator <=(OldUInt160 left, OldUInt160 right)
{
return left.CompareTo(right) <= 0;
}
}
}
3 changes: 2 additions & 1 deletion benchmarks/Neo.Benchmarks/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,5 @@
using BenchmarkDotNet.Running;
using Neo.Benchmark;

BenchmarkRunner.Run<Benchmarks_PoCs>();
// BenchmarkRunner.Run<Benchmarks_PoCs>();
BenchmarkRunner.Run<Benchmarks_UInt160>();
Loading

0 comments on commit 5fe5462

Please sign in to comment.