diff --git a/benchmarks/Neo.Benchmarks/Benchmarks.UInt160.cs b/benchmarks/Neo.Benchmarks/Benchmarks.UInt160.cs
new file mode 100644
index 0000000000..37fa701ff9
--- /dev/null
+++ b/benchmarks/Neo.Benchmarks/Benchmarks.UInt160.cs
@@ -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;
+ }
+}
diff --git a/benchmarks/Neo.Benchmarks/Neo.Benchmarks.csproj b/benchmarks/Neo.Benchmarks/Neo.Benchmarks.csproj
index c4b1a35da9..a59fc6e728 100644
--- a/benchmarks/Neo.Benchmarks/Neo.Benchmarks.csproj
+++ b/benchmarks/Neo.Benchmarks/Neo.Benchmarks.csproj
@@ -5,6 +5,7 @@
net8.0
Neo
enable
+ true
diff --git a/benchmarks/Neo.Benchmarks/OldUInt160.cs b/benchmarks/Neo.Benchmarks/OldUInt160.cs
new file mode 100644
index 0000000000..965ac985ea
--- /dev/null
+++ b/benchmarks/Neo.Benchmarks/OldUInt160.cs
@@ -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
+{
+ ///
+ /// Represents a 160-bit unsigned integer.
+ ///
+ [StructLayout(LayoutKind.Explicit, Size = 20)]
+ public class OldUInt160 : IComparable, IEquatable, ISerializable
+ {
+ ///
+ /// The length of values.
+ ///
+ public const int Length = 20;
+
+ ///
+ /// Represents 0.
+ ///
+ 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;
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ public OldUInt160()
+ {
+ }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The value of the .
+ public unsafe OldUInt160(ReadOnlySpan value)
+ {
+ if (value.Length != Length) throw new FormatException();
+ fixed (ulong* p = &value1)
+ {
+ Span 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;
+ }
+
+ ///
+ /// Parses an from the specified .
+ ///
+ /// An represented by a .
+ /// The parsed .
+ /// is not in the correct format.
+ 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);
+ }
+
+ ///
+ /// Parses an from the specified .
+ ///
+ /// An represented by a .
+ /// The parsed .
+ /// if an is successfully parsed; otherwise, .
+ 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;
+ }
+ }
+}
diff --git a/benchmarks/Neo.Benchmarks/Program.cs b/benchmarks/Neo.Benchmarks/Program.cs
index e39ef23ff7..c44b76f839 100644
--- a/benchmarks/Neo.Benchmarks/Program.cs
+++ b/benchmarks/Neo.Benchmarks/Program.cs
@@ -12,4 +12,5 @@
using BenchmarkDotNet.Running;
using Neo.Benchmark;
-BenchmarkRunner.Run();
+// BenchmarkRunner.Run();
+BenchmarkRunner.Run();
diff --git a/src/Neo/UInt160.cs b/src/Neo/UInt160.cs
index db317ef7e5..da4c920cbe 100644
--- a/src/Neo/UInt160.cs
+++ b/src/Neo/UInt160.cs
@@ -14,6 +14,8 @@
using System;
using System.Globalization;
using System.IO;
+using System.Linq;
+using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
namespace Neo
@@ -32,20 +34,18 @@ public class UInt160 : IComparable, IEquatable, ISerializable
///
/// Represents 0.
///
- public static readonly UInt160 Zero = new();
+ public readonly static UInt160 Zero = new();
- [FieldOffset(0)] private ulong value1;
- [FieldOffset(8)] private ulong value2;
- [FieldOffset(16)] private uint value3;
+ [FieldOffset(0)] private ulong _value1;
+ [FieldOffset(8)] private ulong _value2;
+ [FieldOffset(16)] private uint _value3;
public int Size => Length;
///
/// Initializes a new instance of the class.
///
- public UInt160()
- {
- }
+ public UInt160() { }
///
/// Initializes a new instance of the class.
@@ -53,47 +53,52 @@ public UInt160()
/// The value of the .
public unsafe UInt160(ReadOnlySpan value)
{
- if (value.Length != Length) throw new FormatException();
- fixed (ulong* p = &value1)
+ if (value.Length != Length)
+ throw new FormatException();
+
+ fixed (void* p = &_value1)
{
Span dst = new(p, Length);
value[..Length].CopyTo(dst);
}
}
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
public int CompareTo(UInt160 other)
{
- int result = value3.CompareTo(other.value3);
+ var result = _value3.CompareTo(other._value3);
if (result != 0) return result;
- result = value2.CompareTo(other.value2);
+ result = _value2.CompareTo(other._value2);
if (result != 0) return result;
- return value1.CompareTo(other.value1);
+ return _value1.CompareTo(other._value1);
}
public void Deserialize(ref MemoryReader reader)
{
- value1 = reader.ReadUInt64();
- value2 = reader.ReadUInt64();
- value3 = reader.ReadUInt32();
+ _value1 = reader.ReadUInt64();
+ _value2 = reader.ReadUInt64();
+ _value3 = reader.ReadUInt32();
}
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
public override bool Equals(object obj)
{
if (ReferenceEquals(obj, this)) return true;
return Equals(obj as UInt160);
}
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool Equals(UInt160 other)
{
- if (other is null) return false;
- return value1 == other.value1
- && value2 == other.value2
- && value3 == other.value3;
+ if (other == null) return false;
+ return _value1 == other._value1 &&
+ _value2 == other._value2 &&
+ _value3 == other._value3;
}
public override int GetHashCode()
{
- return (int)value1;
+ return HashCode.Combine(_value1, _value2, _value3);
}
///
@@ -110,9 +115,9 @@ public static UInt160 Parse(string value)
public void Serialize(BinaryWriter writer)
{
- writer.Write(value1);
- writer.Write(value2);
- writer.Write(value3);
+ writer.Write(_value1);
+ writer.Write(_value2);
+ writer.Write(_value3);
}
public override string ToString()
@@ -123,44 +128,61 @@ public override string ToString()
///
/// Parses an from the specified .
///
- /// An represented by a .
+ /// An represented by a .
/// The parsed .
/// if an is successfully parsed; otherwise, .
- public static bool TryParse(string s, out UInt160 result)
+ public static bool TryParse(string str, out UInt160 result)
{
- if (s == null)
+ var startIndex = 0;
+
+ result = null;
+
+ if (string.IsNullOrWhiteSpace(str)) return false;
+
+ if (str.StartsWith("0x", StringComparison.InvariantCultureIgnoreCase))
+ startIndex = 2;
+
+ if ((str.Length - startIndex) != Length * 2) return false;
+
+ try
{
- result = null;
- return false;
+ var data = new byte[Length];
+ for (var i = 0; i < Length; i++)
+ {
+ if (!byte.TryParse(str.AsSpan(i * 2 + startIndex, 2), NumberStyles.HexNumber, null, out data[Length - i - 1]))
+ return false;
+ }
+ result = new(data);
+ return true;
}
- if (s.StartsWith("0x", StringComparison.InvariantCultureIgnoreCase))
- s = s[2..];
- if (s.Length != Length * 2)
+ catch
{
- 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 UInt160(data);
- return true;
+ }
+
+ public static implicit operator UInt160(string s)
+ {
+ return Parse(s);
+ }
+
+ public static implicit operator UInt160(byte[] b)
+ {
+ return new UInt160(b);
}
public static bool operator ==(UInt160 left, UInt160 right)
{
- if (ReferenceEquals(left, right)) return true;
- if (left is null || right is null) return false;
+ if (left is null || right is null)
+ return Equals(left, right);
return left.Equals(right);
}
public static bool operator !=(UInt160 left, UInt160 right)
{
- return !(left == right);
+ if (left is null || right is null)
+ return !Equals(left, right);
+ return !left.Equals(right);
}
public static bool operator >(UInt160 left, UInt160 right)
diff --git a/tests/Neo.UnitTests/UT_UInt160.cs b/tests/Neo.UnitTests/UT_UInt160.cs
index 4799a80d19..3502c7cf90 100644
--- a/tests/Neo.UnitTests/UT_UInt160.cs
+++ b/tests/Neo.UnitTests/UT_UInt160.cs
@@ -9,11 +9,10 @@
// Redistribution and use in source and binary forms with or without
// modifications are permitted.
-#pragma warning disable CS1718
-
using FluentAssertions;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System;
+using System.Security.Cryptography;
namespace Neo.UnitTests.IO
{
@@ -36,8 +35,16 @@ public void TestGernerator1()
[TestMethod]
public void TestGernerator2()
{
- UInt160 uInt160 = new UInt160(new byte[20]);
+ UInt160 uInt160 = new byte[20];
+ Assert.IsNotNull(uInt160);
+ }
+
+ [TestMethod]
+ public void TestGernerator3()
+ {
+ UInt160 uInt160 = "0xff00000000000000000000000000000000000001";
Assert.IsNotNull(uInt160);
+ Assert.IsTrue(uInt160.ToString() == "0xff00000000000000000000000000000000000001");
}
[TestMethod]
@@ -57,9 +64,13 @@ public void TestEquals()
byte[] temp = new byte[20];
temp[19] = 0x01;
UInt160 result = new UInt160(temp);
- Assert.AreEqual(true, UInt160.Zero.Equals(UInt160.Zero));
- Assert.AreEqual(false, UInt160.Zero.Equals(result));
- Assert.AreEqual(false, result.Equals(null));
+ Assert.IsTrue(UInt160.Zero.Equals(UInt160.Zero));
+ Assert.IsFalse(UInt160.Zero.Equals(result));
+ Assert.IsFalse(result.Equals(null));
+ Assert.IsTrue(UInt160.Zero == UInt160.Zero);
+ Assert.IsFalse(UInt160.Zero != UInt160.Zero);
+ Assert.IsTrue(UInt160.Zero == "0x0000000000000000000000000000000000000000");
+ Assert.IsFalse(UInt160.Zero == "0x0000000000000000000000000000000000000001");
}
[TestMethod]
@@ -92,24 +103,28 @@ public void TestTryParse()
public void TestOperatorLarger()
{
Assert.AreEqual(false, UInt160.Zero > UInt160.Zero);
+ Assert.IsFalse(UInt160.Zero > "0x0000000000000000000000000000000000000000");
}
[TestMethod]
public void TestOperatorLargerAndEqual()
{
Assert.AreEqual(true, UInt160.Zero >= UInt160.Zero);
+ Assert.IsTrue(UInt160.Zero >= "0x0000000000000000000000000000000000000000");
}
[TestMethod]
public void TestOperatorSmaller()
{
Assert.AreEqual(false, UInt160.Zero < UInt160.Zero);
+ Assert.IsFalse(UInt160.Zero < "0x0000000000000000000000000000000000000000");
}
[TestMethod]
public void TestOperatorSmallerAndEqual()
{
Assert.AreEqual(true, UInt160.Zero <= UInt160.Zero);
+ Assert.IsTrue(UInt160.Zero >= "0x0000000000000000000000000000000000000000");
}
}
}