diff --git a/.gitignore b/.gitignore index 1358af3bde..5bf30d8fb6 100644 --- a/.gitignore +++ b/.gitignore @@ -257,3 +257,5 @@ paket-files/ PublishProfiles /.vscode launchSettings.json +/coverages +**/.DS_Store diff --git a/src/Neo.VM/Types/ByteString.cs b/src/Neo.VM/Types/ByteString.cs index 2d2df2d862..4a669dbfd5 100644 --- a/src/Neo.VM/Types/ByteString.cs +++ b/src/Neo.VM/Types/ByteString.cs @@ -85,7 +85,7 @@ internal bool Equals(StackItem? other, ref uint limits) public override bool GetBoolean() { if (Size > Integer.MaxSize) throw new InvalidCastException(); - return Unsafe.NotZero(GetSpan()); + return GetSpan().NotZero(); } public override int GetHashCode() diff --git a/src/Neo.VM/Unsafe.cs b/src/Neo.VM/Unsafe.cs deleted file mode 100644 index e3f4366be2..0000000000 --- a/src/Neo.VM/Unsafe.cs +++ /dev/null @@ -1,42 +0,0 @@ -// Copyright (C) 2015-2024 The Neo Project. -// -// Unsafe.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 System; -using System.Runtime.CompilerServices; - -namespace Neo.VM -{ - unsafe internal static class Unsafe - { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool NotZero(ReadOnlySpan x) - { - int len = x.Length; - if (len == 0) return false; - fixed (byte* xp = x) - { - long* xlp = (long*)xp; - for (; len >= 8; len -= 8) - { - if (*xlp != 0) return true; - xlp++; - } - byte* xbp = (byte*)xlp; - for (; len > 0; len--) - { - if (*xbp != 0) return true; - xbp++; - } - } - return false; - } - } -} diff --git a/src/Neo.VM/Utility.cs b/src/Neo.VM/Utility.cs index 7c1852b7f9..0821d77f08 100644 --- a/src/Neo.VM/Utility.cs +++ b/src/Neo.VM/Utility.cs @@ -27,6 +27,17 @@ static Utility() StrictUTF8.EncoderFallback = EncoderFallback.ExceptionFallback; } + /// + /// All bytes are zero or not in a byte array + /// + /// The byte array + /// false if all bytes are zero, true otherwise + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool NotZero(this ReadOnlySpan x) + { + return x.IndexOfAnyExcept((byte)0) >= 0; + } + public static bool TryGetString(this ReadOnlySpan bytes, out string? value) { try diff --git a/tests/Neo.VM.Tests/UT_Unsafe.cs b/tests/Neo.VM.Tests/UT_Unsafe.cs deleted file mode 100644 index e3b4b8708f..0000000000 --- a/tests/Neo.VM.Tests/UT_Unsafe.cs +++ /dev/null @@ -1,33 +0,0 @@ -// Copyright (C) 2015-2024 The Neo Project. -// -// UT_Unsafe.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 Microsoft.VisualStudio.TestTools.UnitTesting; -using Neo.VM; - -namespace Neo.Test -{ - [TestClass] - public class UT_Unsafe - { - [TestMethod] - public void TestNotZero() - { - Assert.IsFalse(Unsafe.NotZero(System.Array.Empty())); - Assert.IsFalse(Unsafe.NotZero(new byte[4])); - Assert.IsFalse(Unsafe.NotZero(new byte[8])); - Assert.IsFalse(Unsafe.NotZero(new byte[11])); - - Assert.IsTrue(Unsafe.NotZero(new byte[4] { 0x00, 0x00, 0x00, 0x01 })); - Assert.IsTrue(Unsafe.NotZero(new byte[8] { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 })); - Assert.IsTrue(Unsafe.NotZero(new byte[11] { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 })); - } - } -} diff --git a/tests/Neo.VM.Tests/UT_Utility.cs b/tests/Neo.VM.Tests/UT_Utility.cs index e87bcbcda7..8c2d4d2b4a 100644 --- a/tests/Neo.VM.Tests/UT_Utility.cs +++ b/tests/Neo.VM.Tests/UT_Utility.cs @@ -101,5 +101,36 @@ public void TestModInverseTest() Assert.AreEqual(new BigInteger(52), new BigInteger(19).ModInverse(141)); } + + [TestMethod] + public void TestNotZero() + { + Assert.IsFalse(new ReadOnlySpan(System.Array.Empty()).NotZero()); + Assert.IsFalse(new ReadOnlySpan(new byte[4]).NotZero()); + Assert.IsFalse(new ReadOnlySpan(new byte[7]).NotZero()); + Assert.IsFalse(new ReadOnlySpan(new byte[8]).NotZero()); + Assert.IsFalse(new ReadOnlySpan(new byte[9]).NotZero()); + Assert.IsFalse(new ReadOnlySpan(new byte[11]).NotZero()); + + Assert.IsTrue(new ReadOnlySpan(new byte[4] { 0x00, 0x00, 0x00, 0x01 }).NotZero()); + Assert.IsTrue(new ReadOnlySpan(new byte[7] { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 }).NotZero()); + Assert.IsTrue(new ReadOnlySpan(new byte[8] { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 }).NotZero()); + Assert.IsTrue(new ReadOnlySpan(new byte[9] { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00 }).NotZero()); + Assert.IsTrue(new ReadOnlySpan(new byte[11] { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 }).NotZero()); + + var bytes = new byte[64]; + for (int i = 0; i < bytes.Length; i++) + { + ReadOnlySpan span = bytes.AsSpan(); + Assert.IsFalse(span[i..].NotZero()); + + for (int j = i; j < bytes.Length; j++) + { + bytes[j] = 0x01; + Assert.IsTrue(span[i..].NotZero()); + bytes[j] = 0x00; + } + } + } } }