Created
September 13, 2021 19:45
-
-
Save hypeartist/ab410a2ce43e47bc03dc295aa248c44a to your computer and use it in GitHub Desktop.
Hex2Int32
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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