diff --git a/src/Nethermind/Nethermind.Trie/HexPrefix.cs b/src/Nethermind/Nethermind.Trie/HexPrefix.cs index 7b7af249182..4ea50910708 100644 --- a/src/Nethermind/Nethermind.Trie/HexPrefix.cs +++ b/src/Nethermind/Nethermind.Trie/HexPrefix.cs @@ -2,6 +2,9 @@ // SPDX-License-Identifier: LGPL-3.0-only using System; +using System.Diagnostics; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; namespace Nethermind.Trie { @@ -39,23 +42,45 @@ public static byte[] ToBytes(byte[] path, bool isLeaf) public static (byte[] key, bool isLeaf) FromBytes(ReadOnlySpan bytes) { - bool isLeaf = bytes[0] >= 32; bool isEven = (bytes[0] & 16) == 0; int nibblesCount = bytes.Length * 2 - (isEven ? 2 : 1); byte[] path = new byte[nibblesCount]; - for (int i = 0; i < nibblesCount; i++) + Span span = new(path); + if (!isEven) + { + span[0] = (byte)(bytes[0] & 0xF); + span = span.Slice(1); + } + bool isLeaf = bytes[0] >= 32; + bytes = bytes.Slice(1); + + Span nibbles = MemoryMarshal.CreateSpan( + ref Unsafe.As(ref MemoryMarshal.GetReference(span)), + span.Length / 2); + + Debug.Assert(nibbles.Length == bytes.Length); + + ref byte byteRef = ref MemoryMarshal.GetReference(bytes); + ref ushort lookup16 = ref MemoryMarshal.GetArrayDataReference(Lookup16); + for (int i = 0; i < nibbles.Length; i++) { - path[i] = - isEven - ? i % 2 == 0 - ? (byte)((bytes[1 + i / 2] & 240) / 16) - : (byte)(bytes[1 + i / 2] & 15) - : i % 2 == 0 - ? (byte)(bytes[i / 2] & 15) - : (byte)((bytes[1 + i / 2] & 240) / 16); + nibbles[i] = Unsafe.Add(ref lookup16, Unsafe.Add(ref byteRef, i)); } return (path, isLeaf); } + + private static readonly ushort[] Lookup16 = CreateLookup16("x2"); + + private static ushort[] CreateLookup16(string format) + { + ushort[] result = new ushort[256]; + for (int i = 0; i < 256; i++) + { + result[i] = (ushort)(((i & 0xF) << 8) | ((i & 240) >> 4)); + } + + return result; + } } }