Make decode even faster

This commit is contained in:
Bond_009 2019-10-20 00:05:04 +02:00
parent a245f5a0d4
commit b6627af65f
2 changed files with 51 additions and 11 deletions

View file

@ -1,5 +1,5 @@
using System;
using System.Globalization;
using System.Diagnostics.CodeAnalysis;
namespace MediaBrowser.Common
{
@ -11,6 +11,23 @@ namespace MediaBrowser.Common
internal const string HexCharsLower = "0123456789abcdef";
internal const string HexCharsUpper = "0123456789ABCDEF";
internal const int LastHexSymbol = 0x66; // 102: f
/// <summary>
/// Map from an ASCII char to its hex value shifted,
/// e.g. <c>b</c> -> 11. 0xFF means it's not a hex symbol.
/// </summary>
/// <value></value>
internal static ReadOnlySpan<byte> HexLookup => new byte[] {
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f
};
/// <summary>
/// Encodes <c>bytes</c> as a hex string.
/// </summary>
@ -41,17 +58,37 @@ namespace MediaBrowser.Common
/// <returns>The decoded bytes.</returns>
public static byte[] Decode(ReadOnlySpan<char> str)
{
byte[] bytes = new byte[str.Length / 2];
int j = 0;
for (int i = 0; i < str.Length; i += 2)
if (str.Length == 0)
{
bytes[j++] = byte.Parse(
str.Slice(i, 2),
NumberStyles.HexNumber,
CultureInfo.InvariantCulture);
return Array.Empty<byte>();
}
var unHex = HexLookup;
int byteLen = str.Length / 2;
byte[] bytes = new byte[byteLen];
int i = 0;
for (int j = 0; j < byteLen; j++)
{
byte a;
byte b;
if (str[i] > LastHexSymbol
|| (a = unHex[str[i++]]) == 0xFF
|| str[i] > LastHexSymbol
|| (b = unHex[str[i++]]) == 0xFF)
{
ThrowArgumentException(nameof(str));
break; // Unreachable
}
bytes[j] = (byte)((a << 4) | b);
}
return bytes;
}
[DoesNotReturn]
private static void ThrowArgumentException(string paramName)
=> throw new ArgumentException("Character is not a hex symbol.", paramName);
}
}

View file

@ -9,10 +9,13 @@ namespace Jellyfin.Common.Benches
[MemoryDiagnoser]
public class HexDecodeBenches
{
private const int N = 1000000;
private readonly string data;
[Params(0, 10, 100, 1000, 10000, 1000000)]
public int N { get; set; }
public HexDecodeBenches()
private string data;
[GlobalSetup]
public void GlobalSetup()
{
var tmp = new byte[N];
new Random(42).NextBytes(tmp);