Skip to content

Instantly share code, notes, and snippets.

@hypeartist
Created September 13, 2021 19:45
Show Gist options
  • Save hypeartist/ab410a2ce43e47bc03dc295aa248c44a to your computer and use it in GitHub Desktop.
Save hypeartist/ab410a2ce43e47bc03dc295aa248c44a to your computer and use it in GitHub Desktop.
Hex2Int32
using System;
using System.IO;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Intrinsics;
using System.Runtime.Intrinsics.X86;
namespace Repos
{
public static class Misc
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static bool ValidateHex(ReadOnlySpan<char> span)
{
foreach (var c in span)
{
if (c is >= '0' and <= '9' or >= 'a' and <= 'f' or >= 'A' and <= 'F') continue;
return false;
}
return true;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static unsafe int HexToInt32Simd(ReadOnlySpan<char> span)
{
var spanLength = span.Length;
ThrowIfFalse(((spanLength ^ 0) | (spanLength ^ 8)) > 0 && ValidateHex(span));
var vc = Sse2.LoadVector128((ushort*)Unsafe.AsPointer(ref MemoryMarshal.GetReference(span)));
var v20 = Vector128.Create((ushort)0x2020);
var v30 = Vector128.Create((ushort)0x3030);
var v0f = Vector128.Create((ushort)0x0f0f);
var t = Sse2.ShiftRightLogical(Sse2.Xor(Sse2.And(Sse2.Xor(Sse2.Subtract(vc, Sse2.And(vc, v20)), v20), v30), v30), 4);
var tt = Sse2.ShiftLeftLogical(Sse2.Add(Sse2.Add(Sse2.Subtract(Sse2.And(Sse2.Subtract(vc, v30), v0f), t), Sse2.ShiftLeftLogical(t, 3)), Sse2.ShiftLeftLogical(t, 1)), 4);
var r1 = Ssse3.Shuffle(tt.AsByte(), Vector128.Create(12, 8, 4, 0, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255));
var r2 = Ssse3.Shuffle(tt.AsByte(), Vector128.Create(14, 10, 6, 2, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255));
var r = Sse2.Or(r1, Sse2.ShiftRightLogical(r2.AsInt16(), 4).AsByte());
var i32 = 0;
Sse2.Store(&i32, r.AsInt32());
return (int) ((uint) i32 >> ((8 - spanLength) << 2));
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static unsafe int HexToInt32(ReadOnlySpan<char> span)
{
var spanLength = span.Length;
ThrowIfFalse(((spanLength ^ 0) | (spanLength ^ 8)) > 0 && ValidateHex(span));
var buffer = (0x0030003000300030, 0x0030003000300030);
var pBuffer = (char*) &buffer;
var length = Math.Min(8, spanLength);
for (int i = 0, j = 8 - length; i < length; i++, j++)
{
pBuffer[j] = span[i];
}
var packedInput = ((long)pBuffer[0] << 56) | ((long)pBuffer[1] << 48) | ((long)pBuffer[2] << 40) | ((long)pBuffer[3] << 32) | ((long)pBuffer[4] << 24) | ((long)pBuffer[5] << 16) | ((long)pBuffer[6] << 8) | pBuffer[7];
var calc = (((packedInput - (packedInput & 0x2020202020202020) ^ 0x2020202020202020) & 0x3030303030303030) ^ 0x3030303030303030) >> 4;
calc = ((packedInput - 0x3030303030303030) & 0x0f0f0f0f0f0f0f0f) - calc + (calc << 3) + (calc << 1) << 4;
return (int)((((calc >> 32) | (calc >> 28)) & 0xff000000) | (((calc >> 24) | (calc >> 20)) & 0xff0000) | (((calc >> 16) | (calc >> 12)) & 0xff00) | (((calc >> 8) | (calc >> 4)) & 0xff));
}
public static void ThrowIfFalse(bool cond)
{
if (cond) return;
throw new InvalidDataException();
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment