Created
August 31, 2019 01:11
-
-
Save vanbukin/136432ae1c85c7e3c980d452fadd8653 to your computer and use it in GitHub Desktop.
This file contains 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.Diagnostics.CodeAnalysis; | |
using System.Reflection; | |
using System.Runtime.InteropServices; | |
namespace Uuid1 | |
{ | |
public unsafe struct Uuidv1 : IFormattable | |
{ | |
static Uuidv1() | |
{ | |
TableToHex = (uint*) Marshal.AllocHGlobal(sizeof(uint) * 256).ToPointer(); | |
for (var i = 0; i < 256; i++) | |
{ | |
var chars = Convert.ToString(i, 16).PadLeft(2, '0'); | |
TableToHex[i] = ((uint) chars[1] << 16) | chars[0]; | |
} | |
// ReSharper disable once PossibleNullReferenceException | |
FastAllocateString = (Func<int, string>) typeof(string) | |
.GetMethod(nameof(FastAllocateString), BindingFlags.Static | BindingFlags.NonPublic) | |
.CreateDelegate(typeof(Func<int, string>)); | |
} | |
private static readonly uint* TableToHex; | |
private static readonly Func<int, string> FastAllocateString; | |
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; | |
} | |
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[] bytes) | |
{ | |
if (bytes == null) | |
throw new ArgumentNullException(nameof(bytes)); | |
if (bytes.Length != 16) | |
throw new ArgumentOutOfRangeException(nameof(bytes)); | |
_byte15 = bytes[15]; | |
_byte0 = bytes[0]; | |
_byte1 = bytes[1]; | |
_byte2 = bytes[2]; | |
_byte3 = bytes[3]; | |
_byte4 = bytes[4]; | |
_byte5 = bytes[5]; | |
_byte6 = bytes[6]; | |
_byte7 = bytes[7]; | |
_byte8 = bytes[8]; | |
_byte9 = bytes[9]; | |
_byte10 = bytes[10]; | |
_byte11 = bytes[11]; | |
_byte12 = bytes[12]; | |
_byte13 = bytes[13]; | |
_byte14 = bytes[14]; | |
} | |
public Uuidv1(byte* bytes) | |
{ | |
_byte15 = bytes[15]; | |
_byte0 = bytes[0]; | |
_byte1 = bytes[1]; | |
_byte2 = bytes[2]; | |
_byte3 = bytes[3]; | |
_byte4 = bytes[4]; | |
_byte5 = bytes[5]; | |
_byte6 = bytes[6]; | |
_byte7 = bytes[7]; | |
_byte8 = bytes[8]; | |
_byte9 = bytes[9]; | |
_byte10 = bytes[10]; | |
_byte11 = bytes[11]; | |
_byte12 = bytes[12]; | |
_byte13 = bytes[13]; | |
_byte14 = bytes[14]; | |
} | |
public Uuidv1(Span<byte> bytes) | |
{ | |
if (bytes == null) | |
throw new NullReferenceException(nameof(bytes)); | |
_byte15 = bytes[15]; | |
_byte0 = bytes[0]; | |
_byte1 = bytes[1]; | |
_byte2 = bytes[2]; | |
_byte3 = bytes[3]; | |
_byte4 = bytes[4]; | |
_byte5 = bytes[5]; | |
_byte6 = bytes[6]; | |
_byte7 = bytes[7]; | |
_byte8 = bytes[8]; | |
_byte9 = bytes[9]; | |
_byte10 = bytes[10]; | |
_byte11 = bytes[11]; | |
_byte12 = bytes[12]; | |
_byte13 = bytes[13]; | |
_byte14 = bytes[14]; | |
} | |
public byte[] ToByteArray() | |
{ | |
return new[] | |
{ | |
_byte0, | |
_byte1, | |
_byte2, | |
_byte3, | |
_byte4, | |
_byte5, | |
_byte6, | |
_byte7, | |
_byte8, | |
_byte9, | |
_byte10, | |
_byte11, | |
_byte12, | |
_byte13, | |
_byte14, | |
_byte15 | |
}; | |
} | |
public bool TryWriteBytes(Span<byte> destination) | |
{ | |
return MemoryMarshal.TryWrite(destination, ref this); | |
} | |
public override string ToString() => ToString("D", null); | |
public string ToString(string? format) | |
{ | |
return ToString(format, null); | |
} | |
public string ToString(string format, IFormatProvider? provider) | |
{ | |
if (string.IsNullOrEmpty(format)) format = "D"; | |
// all acceptable format strings are of length 1 | |
if (format.Length != 1) | |
throw new FormatException( | |
"Format string can be only \"D\", \"d\", \"N\", \"n\", \"P\", \"p\", \"B\", \"b\", \"X\" or \"x\"."); | |
switch (format[0]) | |
{ | |
case 'D': | |
case 'd': | |
{ | |
var guidString = FastAllocateString(36); | |
fixed (char* guidChars = &guidString.GetPinnableReference()) | |
{ | |
FormatD(guidChars); | |
} | |
return guidString; | |
} | |
case 'N': | |
case 'n': | |
{ | |
var guidString = FastAllocateString(32); | |
fixed (char* guidChars = &guidString.GetPinnableReference()) | |
{ | |
FormatN(guidChars); | |
} | |
return guidString; | |
} | |
case 'B': | |
case 'b': | |
{ | |
var guidString = FastAllocateString(38); | |
fixed (char* guidChars = &guidString.GetPinnableReference()) | |
{ | |
FormatB(guidChars); | |
} | |
return guidString; | |
} | |
case 'P': | |
case 'p': | |
{ | |
var guidString = FastAllocateString(38); | |
fixed (char* guidChars = &guidString.GetPinnableReference()) | |
{ | |
FormatP(guidChars); | |
} | |
return guidString; | |
} | |
case 'X': | |
case 'x': | |
{ | |
var guidString = FastAllocateString(68); | |
fixed (char* guidChars = &guidString.GetPinnableReference()) | |
{ | |
FormatX(guidChars); | |
} | |
return guidString; | |
} | |
default: | |
throw new FormatException( | |
"Format string can be only \"D\", \"d\", \"N\", \"n\", \"P\", \"p\", \"B\", \"b\", \"X\" or \"x\"."); | |
} | |
} | |
[SuppressMessage("ReSharper", "RedundantAssignment")] | |
private void FormatD(char* dest) | |
{ | |
// dddddddd-dddd-dddd-dddd-dddddddddddd | |
var uintDest = (uint*) dest; | |
var uintDestAsChars = (char**) &uintDest; | |
dest[8] = dest[13] = dest[18] = dest[23] = '-'; | |
uintDest[0] = TableToHex[_byte0]; | |
uintDest[1] = TableToHex[_byte1]; | |
uintDest[2] = TableToHex[_byte2]; | |
uintDest[3] = TableToHex[_byte3]; | |
uintDest[7] = TableToHex[_byte6]; | |
uintDest[8] = TableToHex[_byte7]; | |
uintDest[12] = TableToHex[_byte10]; | |
uintDest[13] = TableToHex[_byte11]; | |
uintDest[14] = TableToHex[_byte12]; | |
uintDest[15] = TableToHex[_byte13]; | |
uintDest[16] = TableToHex[_byte14]; | |
uintDest[17] = TableToHex[_byte15]; | |
*uintDestAsChars += 1; | |
uintDest[4] = TableToHex[_byte4]; | |
uintDest[5] = TableToHex[_byte5]; | |
uintDest[9] = TableToHex[_byte8]; | |
uintDest[10] = TableToHex[_byte9]; | |
} | |
[SuppressMessage("ReSharper", "RedundantAssignment")] | |
private void FormatN(char* dest) | |
{ | |
// dddddddddddddddddddddddddddddddd | |
var destUints = (uint*) dest; | |
destUints[0] = TableToHex[_byte0]; | |
destUints[1] = TableToHex[_byte1]; | |
destUints[2] = TableToHex[_byte2]; | |
destUints[3] = TableToHex[_byte3]; | |
destUints[4] = TableToHex[_byte4]; | |
destUints[5] = TableToHex[_byte5]; | |
destUints[6] = TableToHex[_byte6]; | |
destUints[7] = TableToHex[_byte7]; | |
destUints[8] = TableToHex[_byte8]; | |
destUints[9] = TableToHex[_byte9]; | |
destUints[10] = TableToHex[_byte10]; | |
destUints[11] = TableToHex[_byte11]; | |
destUints[12] = TableToHex[_byte12]; | |
destUints[13] = TableToHex[_byte13]; | |
destUints[14] = TableToHex[_byte14]; | |
destUints[15] = TableToHex[_byte15]; | |
} | |
[SuppressMessage("ReSharper", "RedundantAssignment")] | |
private void FormatB(char* dest) | |
{ | |
// {dddddddd-dddd-dddd-dddd-dddddddddddd} | |
var destUints = (uint*) dest; | |
var destUintsAsChars = (char**) &destUints; | |
dest[0] = '{'; | |
dest[9] = dest[14] = dest[19] = dest[24] = '-'; | |
dest[37] = '}'; | |
destUints[5] = TableToHex[_byte4]; | |
destUints[6] = TableToHex[_byte5]; | |
destUints[10] = TableToHex[_byte8]; | |
destUints[11] = TableToHex[_byte9]; | |
*destUintsAsChars += 1; | |
destUints[0] = TableToHex[_byte0]; | |
destUints[1] = TableToHex[_byte1]; | |
destUints[2] = TableToHex[_byte2]; | |
destUints[3] = TableToHex[_byte3]; | |
destUints[7] = TableToHex[_byte6]; | |
destUints[8] = TableToHex[_byte7]; | |
destUints[12] = TableToHex[_byte10]; | |
destUints[13] = TableToHex[_byte11]; | |
destUints[14] = TableToHex[_byte12]; | |
destUints[15] = TableToHex[_byte13]; | |
destUints[16] = TableToHex[_byte14]; | |
destUints[17] = TableToHex[_byte15]; | |
} | |
[SuppressMessage("ReSharper", "RedundantAssignment")] | |
private void FormatP(char* dest) | |
{ | |
// (dddddddd-dddd-dddd-dddd-dddddddddddd) | |
var destUints = (uint*) dest; | |
var destUintsAsChars = (char**) &destUints; | |
dest[0] = '('; | |
dest[9] = dest[14] = dest[19] = dest[24] = '-'; | |
dest[37] = ')'; | |
destUints[5] = TableToHex[_byte4]; | |
destUints[6] = TableToHex[_byte5]; | |
destUints[10] = TableToHex[_byte8]; | |
destUints[11] = TableToHex[_byte9]; | |
*destUintsAsChars += 1; | |
destUints[0] = TableToHex[_byte0]; | |
destUints[1] = TableToHex[_byte1]; | |
destUints[2] = TableToHex[_byte2]; | |
destUints[3] = TableToHex[_byte3]; | |
destUints[7] = TableToHex[_byte6]; | |
destUints[8] = TableToHex[_byte7]; | |
destUints[12] = TableToHex[_byte10]; | |
destUints[13] = TableToHex[_byte11]; | |
destUints[14] = TableToHex[_byte12]; | |
destUints[15] = TableToHex[_byte13]; | |
destUints[16] = TableToHex[_byte14]; | |
destUints[17] = TableToHex[_byte15]; | |
} | |
private const uint ZeroX = 7864368; // 0x | |
private const uint CommaBrace = 8060972; // ,{ | |
private const uint CloseBraces = 8192125; // }} | |
[SuppressMessage("ReSharper", "RedundantAssignment")] | |
[SuppressMessage("ReSharper", "InconsistentNaming")] | |
private void FormatX(char* dest) | |
{ | |
// {0xdddddddd,0xdddd,0xdddd,{0xdd,0xdd,0xdd,0xdd,0xdd,0xdd,0xdd,0xdd}} | |
var uintDest = (uint*) dest; | |
var uintDestAsChars = (char**) &uintDest; | |
dest[0] = '{'; | |
dest[11] = dest[18] = dest[31] = dest[36] = dest[41] = dest[46] = dest[51] = dest[56] = dest[61] = ','; | |
uintDest[6] = uintDest[16] = uintDest[21] = uintDest[26] = uintDest[31] = ZeroX; // 0x | |
uintDest[7] = TableToHex[_byte4]; | |
uintDest[8] = TableToHex[_byte5]; | |
uintDest[17] = TableToHex[_byte9]; | |
uintDest[22] = TableToHex[_byte11]; | |
uintDest[27] = TableToHex[_byte13]; | |
uintDest[32] = TableToHex[_byte15]; | |
uintDest[33] = CloseBraces; // }} | |
*uintDestAsChars += 1; | |
uintDest[0] = uintDest[9] = uintDest[13] = uintDest[18] = uintDest[23] = uintDest[28] = ZeroX; // 0x | |
uintDest[1] = TableToHex[_byte0]; | |
uintDest[2] = TableToHex[_byte1]; | |
uintDest[3] = TableToHex[_byte2]; | |
uintDest[4] = TableToHex[_byte3]; | |
uintDest[10] = TableToHex[_byte6]; | |
uintDest[11] = TableToHex[_byte7]; | |
uintDest[12] = CommaBrace; // ,{ | |
uintDest[14] = TableToHex[_byte8]; | |
uintDest[19] = TableToHex[_byte10]; | |
uintDest[24] = TableToHex[_byte12]; | |
uintDest[29] = TableToHex[_byte14]; | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment