Last active
May 18, 2019 15:35
-
-
Save vanbukin/f4ad3ec311edc7c3d8d21554db4ce736 to your computer and use it in GitHub Desktop.
Fast UUIDv1
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.Runtime.CompilerServices; | |
| using System.Runtime.InteropServices; | |
| namespace Dodo.Types | |
| { | |
| [StructLayout(LayoutKind.Sequential, Size = 16, CharSet = CharSet.Ansi, Pack = 1)] | |
| public struct Uuidv1 | |
| { | |
| static Uuidv1() | |
| { | |
| for (var i = 0; i < 256; i++) | |
| { | |
| var chars = Convert.ToString(i, 16).PadLeft(2, '0').ToUpperInvariant(); | |
| TableToHex[i] = ((uint) chars[1] << 16) | chars[0]; | |
| } | |
| } | |
| private static readonly uint[] TableToHex = new uint[256]; | |
| private readonly byte Byte0; | |
| private readonly byte Byte1; | |
| private readonly byte Byte2; | |
| private readonly byte Byte3; | |
| private readonly byte Byte4; | |
| private readonly byte Byte5; | |
| private readonly byte Byte6; | |
| private readonly byte Byte7; | |
| private readonly byte Byte8; | |
| private readonly byte Byte9; | |
| private readonly byte Byte10; | |
| private readonly byte Byte11; | |
| private readonly byte Byte12; | |
| private readonly byte Byte13; | |
| private readonly byte Byte14; | |
| private readonly byte Byte15; | |
| public Uuidv1( | |
| byte byte0, | |
| byte byte1, | |
| byte byte2, | |
| byte byte3, | |
| byte byte4, | |
| byte byte5, | |
| byte byte6, | |
| byte byte7, | |
| byte byte8, | |
| byte byte9, | |
| byte byte10, | |
| byte byte11, | |
| byte byte12, | |
| byte byte13, | |
| byte byte14, | |
| byte byte15) | |
| { | |
| Byte0 = byte0; | |
| Byte1 = byte1; | |
| Byte2 = byte2; | |
| Byte3 = byte3; | |
| Byte4 = byte4; | |
| Byte5 = byte5; | |
| Byte6 = byte6; | |
| Byte7 = byte7; | |
| Byte8 = byte8; | |
| Byte9 = byte9; | |
| Byte10 = byte10; | |
| Byte11 = byte11; | |
| Byte12 = byte12; | |
| Byte13 = byte13; | |
| Byte14 = byte14; | |
| Byte15 = byte15; | |
| } | |
| public Uuidv1(byte[] bytes) | |
| { | |
| if (bytes == null) | |
| throw new ArgumentNullException(nameof(bytes)); | |
| if (bytes.Length != 16) | |
| throw new ArgumentOutOfRangeException(nameof(bytes)); | |
| Byte15 = bytes[15]; | |
| Byte14 = bytes[14]; | |
| Byte13 = bytes[13]; | |
| Byte12 = bytes[12]; | |
| Byte11 = bytes[11]; | |
| Byte10 = bytes[10]; | |
| Byte9 = bytes[9]; | |
| Byte8 = bytes[8]; | |
| Byte7 = bytes[7]; | |
| Byte6 = bytes[6]; | |
| Byte5 = bytes[5]; | |
| Byte4 = bytes[4]; | |
| Byte3 = bytes[3]; | |
| Byte2 = bytes[2]; | |
| Byte1 = bytes[1]; | |
| Byte0 = bytes[0]; | |
| } | |
| public unsafe Uuidv1(byte* bytes) | |
| { | |
| if (bytes == null) | |
| throw new NullReferenceException(nameof(bytes)); | |
| Byte15 = bytes[15]; | |
| Byte14 = bytes[14]; | |
| Byte13 = bytes[13]; | |
| Byte12 = bytes[12]; | |
| Byte11 = bytes[11]; | |
| Byte10 = bytes[10]; | |
| Byte9 = bytes[9]; | |
| Byte8 = bytes[8]; | |
| Byte7 = bytes[7]; | |
| Byte6 = bytes[6]; | |
| Byte5 = bytes[5]; | |
| Byte4 = bytes[4]; | |
| Byte3 = bytes[3]; | |
| Byte2 = bytes[2]; | |
| Byte1 = bytes[1]; | |
| Byte0 = bytes[0]; | |
| } | |
| public Uuidv1(Span<byte> bytes) | |
| { | |
| if (bytes == null) | |
| throw new NullReferenceException(nameof(bytes)); | |
| Byte15 = bytes[15]; | |
| Byte14 = bytes[14]; | |
| Byte13 = bytes[13]; | |
| Byte12 = bytes[12]; | |
| Byte11 = bytes[11]; | |
| Byte10 = bytes[10]; | |
| Byte9 = bytes[9]; | |
| Byte8 = bytes[8]; | |
| Byte7 = bytes[7]; | |
| Byte6 = bytes[6]; | |
| Byte5 = bytes[5]; | |
| Byte4 = bytes[4]; | |
| Byte3 = bytes[3]; | |
| Byte2 = bytes[2]; | |
| Byte1 = bytes[1]; | |
| Byte0 = bytes[0]; | |
| } | |
| public byte[] ToByteArray() | |
| { | |
| return new[] | |
| { | |
| Byte0, | |
| Byte1, | |
| Byte2, | |
| Byte3, | |
| Byte4, | |
| Byte5, | |
| Byte6, | |
| Byte7, | |
| Byte8, | |
| Byte9, | |
| Byte10, | |
| Byte11, | |
| Byte12, | |
| Byte13, | |
| Byte14, | |
| Byte15 | |
| }; | |
| } | |
| public override unsafe string ToString() | |
| { | |
| var charsAsInts = stackalloc uint[16]; | |
| charsAsInts[0] = TableToHex[Byte0]; | |
| charsAsInts[1] = TableToHex[Byte1]; | |
| charsAsInts[2] = TableToHex[Byte2]; | |
| charsAsInts[3] = TableToHex[Byte3]; | |
| charsAsInts[4] = TableToHex[Byte4]; | |
| charsAsInts[5] = TableToHex[Byte5]; | |
| charsAsInts[6] = TableToHex[Byte6]; | |
| charsAsInts[7] = TableToHex[Byte7]; | |
| charsAsInts[8] = TableToHex[Byte8]; | |
| charsAsInts[9] = TableToHex[Byte9]; | |
| charsAsInts[10] = TableToHex[Byte10]; | |
| charsAsInts[11] = TableToHex[Byte11]; | |
| charsAsInts[12] = TableToHex[Byte12]; | |
| charsAsInts[13] = TableToHex[Byte13]; | |
| charsAsInts[14] = TableToHex[Byte14]; | |
| charsAsInts[15] = TableToHex[Byte15]; | |
| return new string((char*) charsAsInts, 0, 32); | |
| } | |
| [MethodImpl(MethodImplOptions.AggressiveInlining)] | |
| public void Write(Span<byte> output) | |
| { | |
| output[0] = Byte0; | |
| output[1] = Byte1; | |
| output[2] = Byte2; | |
| output[3] = Byte3; | |
| output[4] = Byte4; | |
| output[5] = Byte5; | |
| output[6] = Byte6; | |
| output[7] = Byte7; | |
| output[8] = Byte8; | |
| output[9] = Byte9; | |
| output[10] = Byte10; | |
| output[11] = Byte11; | |
| output[12] = Byte12; | |
| output[13] = Byte13; | |
| output[14] = Byte14; | |
| output[15] = Byte15; | |
| } | |
| [MethodImpl(MethodImplOptions.AggressiveInlining)] | |
| public void WriteHex(Span<char> output) | |
| { | |
| var outputSpan = MemoryMarshal.Cast<char, uint>(output); | |
| outputSpan[0] = TableToHex[Byte0]; | |
| outputSpan[1] = TableToHex[Byte1]; | |
| outputSpan[2] = TableToHex[Byte2]; | |
| outputSpan[3] = TableToHex[Byte3]; | |
| outputSpan[4] = TableToHex[Byte4]; | |
| outputSpan[5] = TableToHex[Byte5]; | |
| outputSpan[6] = TableToHex[Byte6]; | |
| outputSpan[7] = TableToHex[Byte7]; | |
| outputSpan[8] = TableToHex[Byte8]; | |
| outputSpan[9] = TableToHex[Byte9]; | |
| outputSpan[10] = TableToHex[Byte10]; | |
| outputSpan[11] = TableToHex[Byte11]; | |
| outputSpan[12] = TableToHex[Byte12]; | |
| outputSpan[13] = TableToHex[Byte13]; | |
| outputSpan[14] = TableToHex[Byte14]; | |
| outputSpan[15] = TableToHex[Byte15]; | |
| } | |
| private static readonly byte[] StringToHexPos0 = | |
| { | |
| 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | |
| 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | |
| 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | |
| 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | |
| 0, 0, 0, 0, 0, 0, 0, 0, 16, 32, | |
| 48, 64, 80, 96, 112, 128, 144, 0, 0, 0, | |
| 0, 0, 0, 0, 160, 176, 192, 208, 224, 240, | |
| 0, 0, 0, 0, 0, 0, 0, 0, 0 | |
| }; | |
| private static readonly byte[] StringToHexPos1 = | |
| { | |
| 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | |
| 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | |
| 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | |
| 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | |
| 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, | |
| 3, 4, 5, 6, 7, 8, 9, 0, 0, 0, | |
| 0, 0, 0, 0, 10, 11, 12, 13, 14, 15, | |
| 0, 0, 0, 0, 0, 0, 0, 0, 0 | |
| }; | |
| public static Uuidv1 Parse(string input) | |
| { | |
| if (input == null) | |
| throw new ArgumentNullException(nameof(input)); | |
| if (input.Length != 32) | |
| throw new ArgumentException("Input allow only strings with 32 characters!", nameof(input)); | |
| foreach (var c in input) | |
| { | |
| var isHex = c >= '0' && c <= '9' || c >= 'A' && c <= 'F'; | |
| if (!isHex) | |
| throw new ArgumentException("Input does not contains hex string", nameof(input)); | |
| } | |
| return new Uuidv1( | |
| (byte) (StringToHexPos0[(byte) input[0]] + StringToHexPos1[(byte) input[1]]), | |
| (byte) (StringToHexPos0[(byte) input[2]] + StringToHexPos1[(byte) input[3]]), | |
| (byte) (StringToHexPos0[(byte) input[4]] + StringToHexPos1[(byte) input[5]]), | |
| (byte) (StringToHexPos0[(byte) input[6]] + StringToHexPos1[(byte) input[7]]), | |
| (byte) (StringToHexPos0[(byte) input[8]] + StringToHexPos1[(byte) input[9]]), | |
| (byte) (StringToHexPos0[(byte) input[10]] + StringToHexPos1[(byte) input[11]]), | |
| (byte) (StringToHexPos0[(byte) input[12]] + StringToHexPos1[(byte) input[13]]), | |
| (byte) (StringToHexPos0[(byte) input[14]] + StringToHexPos1[(byte) input[15]]), | |
| (byte) (StringToHexPos0[(byte) input[16]] + StringToHexPos1[(byte) input[17]]), | |
| (byte) (StringToHexPos0[(byte) input[18]] + StringToHexPos1[(byte) input[19]]), | |
| (byte) (StringToHexPos0[(byte) input[20]] + StringToHexPos1[(byte) input[21]]), | |
| (byte) (StringToHexPos0[(byte) input[22]] + StringToHexPos1[(byte) input[23]]), | |
| (byte) (StringToHexPos0[(byte) input[24]] + StringToHexPos1[(byte) input[25]]), | |
| (byte) (StringToHexPos0[(byte) input[26]] + StringToHexPos1[(byte) input[27]]), | |
| (byte) (StringToHexPos0[(byte) input[28]] + StringToHexPos1[(byte) input[29]]), | |
| (byte) (StringToHexPos0[(byte) input[30]] + StringToHexPos1[(byte) input[31]]) | |
| ); | |
| } | |
| public static Uuidv1 Parse(ReadOnlySpan<char> input) | |
| { | |
| if (input == null) | |
| throw new ArgumentNullException(nameof(input)); | |
| if (input.Length != 32) | |
| throw new ArgumentException("Input allow only strings with 32 characters!", nameof(input)); | |
| foreach (var c in input) | |
| { | |
| var isHex = c >= '0' && c <= '9' || c >= 'A' && c <= 'F'; | |
| if (!isHex) | |
| throw new ArgumentException("Input does not contains hex string", nameof(input)); | |
| } | |
| return new Uuidv1( | |
| (byte) (StringToHexPos0[(byte) input[0]] + StringToHexPos1[(byte) input[1]]), | |
| (byte) (StringToHexPos0[(byte) input[2]] + StringToHexPos1[(byte) input[3]]), | |
| (byte) (StringToHexPos0[(byte) input[4]] + StringToHexPos1[(byte) input[5]]), | |
| (byte) (StringToHexPos0[(byte) input[6]] + StringToHexPos1[(byte) input[7]]), | |
| (byte) (StringToHexPos0[(byte) input[8]] + StringToHexPos1[(byte) input[9]]), | |
| (byte) (StringToHexPos0[(byte) input[10]] + StringToHexPos1[(byte) input[11]]), | |
| (byte) (StringToHexPos0[(byte) input[12]] + StringToHexPos1[(byte) input[13]]), | |
| (byte) (StringToHexPos0[(byte) input[14]] + StringToHexPos1[(byte) input[15]]), | |
| (byte) (StringToHexPos0[(byte) input[16]] + StringToHexPos1[(byte) input[17]]), | |
| (byte) (StringToHexPos0[(byte) input[18]] + StringToHexPos1[(byte) input[19]]), | |
| (byte) (StringToHexPos0[(byte) input[20]] + StringToHexPos1[(byte) input[21]]), | |
| (byte) (StringToHexPos0[(byte) input[22]] + StringToHexPos1[(byte) input[23]]), | |
| (byte) (StringToHexPos0[(byte) input[24]] + StringToHexPos1[(byte) input[25]]), | |
| (byte) (StringToHexPos0[(byte) input[26]] + StringToHexPos1[(byte) input[27]]), | |
| (byte) (StringToHexPos0[(byte) input[28]] + StringToHexPos1[(byte) input[29]]), | |
| (byte) (StringToHexPos0[(byte) input[30]] + StringToHexPos1[(byte) input[31]]) | |
| ); | |
| } | |
| public static bool TryParse(string input, out Uuidv1 result) | |
| { | |
| if (input == null) | |
| { | |
| result = default; | |
| return false; | |
| } | |
| if (input.Length != 32) | |
| { | |
| result = default; | |
| return false; | |
| } | |
| foreach (var c in input) | |
| { | |
| var isHex = c >= '0' && c <= '9' || c >= 'A' && c <= 'F'; | |
| if (!isHex) | |
| { | |
| result = default; | |
| return false; | |
| } | |
| } | |
| result = new Uuidv1( | |
| (byte) (StringToHexPos0[(byte) input[0]] + StringToHexPos1[(byte) input[1]]), | |
| (byte) (StringToHexPos0[(byte) input[2]] + StringToHexPos1[(byte) input[3]]), | |
| (byte) (StringToHexPos0[(byte) input[4]] + StringToHexPos1[(byte) input[5]]), | |
| (byte) (StringToHexPos0[(byte) input[6]] + StringToHexPos1[(byte) input[7]]), | |
| (byte) (StringToHexPos0[(byte) input[8]] + StringToHexPos1[(byte) input[9]]), | |
| (byte) (StringToHexPos0[(byte) input[10]] + StringToHexPos1[(byte) input[11]]), | |
| (byte) (StringToHexPos0[(byte) input[12]] + StringToHexPos1[(byte) input[13]]), | |
| (byte) (StringToHexPos0[(byte) input[14]] + StringToHexPos1[(byte) input[15]]), | |
| (byte) (StringToHexPos0[(byte) input[16]] + StringToHexPos1[(byte) input[17]]), | |
| (byte) (StringToHexPos0[(byte) input[18]] + StringToHexPos1[(byte) input[19]]), | |
| (byte) (StringToHexPos0[(byte) input[20]] + StringToHexPos1[(byte) input[21]]), | |
| (byte) (StringToHexPos0[(byte) input[22]] + StringToHexPos1[(byte) input[23]]), | |
| (byte) (StringToHexPos0[(byte) input[24]] + StringToHexPos1[(byte) input[25]]), | |
| (byte) (StringToHexPos0[(byte) input[26]] + StringToHexPos1[(byte) input[27]]), | |
| (byte) (StringToHexPos0[(byte) input[28]] + StringToHexPos1[(byte) input[29]]), | |
| (byte) (StringToHexPos0[(byte) input[30]] + StringToHexPos1[(byte) input[31]]) | |
| ); | |
| return true; | |
| } | |
| public static bool TryParse(ReadOnlySpan<char> input, out Uuidv1 result) | |
| { | |
| if (input == null) | |
| { | |
| result = default; | |
| return false; | |
| } | |
| if (input.Length != 32) | |
| { | |
| result = default; | |
| return false; | |
| } | |
| foreach (var c in input) | |
| { | |
| var isHex = c >= '0' && c <= '9' || c >= 'A' && c <= 'F'; | |
| if (!isHex) | |
| { | |
| result = default; | |
| return false; | |
| } | |
| } | |
| result = new Uuidv1( | |
| (byte) (StringToHexPos0[(byte) input[0]] + StringToHexPos1[(byte) input[1]]), | |
| (byte) (StringToHexPos0[(byte) input[2]] + StringToHexPos1[(byte) input[3]]), | |
| (byte) (StringToHexPos0[(byte) input[4]] + StringToHexPos1[(byte) input[5]]), | |
| (byte) (StringToHexPos0[(byte) input[6]] + StringToHexPos1[(byte) input[7]]), | |
| (byte) (StringToHexPos0[(byte) input[8]] + StringToHexPos1[(byte) input[9]]), | |
| (byte) (StringToHexPos0[(byte) input[10]] + StringToHexPos1[(byte) input[11]]), | |
| (byte) (StringToHexPos0[(byte) input[12]] + StringToHexPos1[(byte) input[13]]), | |
| (byte) (StringToHexPos0[(byte) input[14]] + StringToHexPos1[(byte) input[15]]), | |
| (byte) (StringToHexPos0[(byte) input[16]] + StringToHexPos1[(byte) input[17]]), | |
| (byte) (StringToHexPos0[(byte) input[18]] + StringToHexPos1[(byte) input[19]]), | |
| (byte) (StringToHexPos0[(byte) input[20]] + StringToHexPos1[(byte) input[21]]), | |
| (byte) (StringToHexPos0[(byte) input[22]] + StringToHexPos1[(byte) input[23]]), | |
| (byte) (StringToHexPos0[(byte) input[24]] + StringToHexPos1[(byte) input[25]]), | |
| (byte) (StringToHexPos0[(byte) input[26]] + StringToHexPos1[(byte) input[27]]), | |
| (byte) (StringToHexPos0[(byte) input[28]] + StringToHexPos1[(byte) input[29]]), | |
| (byte) (StringToHexPos0[(byte) input[30]] + StringToHexPos1[(byte) input[31]]) | |
| ); | |
| return true; | |
| } | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment