Skip to content

Instantly share code, notes, and snippets.

@vanbukin
Created August 21, 2019 19:54
Show Gist options
  • Save vanbukin/fd958e039bb666e8348df2bd5510ffa4 to your computer and use it in GitHub Desktop.
Save vanbukin/fd958e039bb666e8348df2bd5510ffa4 to your computer and use it in GitHub Desktop.
using System;
using System.Diagnostics;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
namespace Uuid1
{
public struct Uuidv1 : IFormattable
{
static Uuidv1()
{
for (var i = 0; i < 256; i++)
{
var chars = Convert.ToString(i, 16).PadLeft(2, '0');
TableToHex[i] = ((uint) chars[1] << 16) | chars[0];
}
}
private static readonly uint[] TableToHex = new uint[256];
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 unsafe Uuidv1(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 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)
{
if (BitConverter.IsLittleEndian) return MemoryMarshal.TryWrite(destination, ref this);
// slower path for BigEndian
if (destination.Length < 16)
return false;
destination[0] = Byte0;
destination[1] = Byte1;
destination[2] = Byte2;
destination[3] = Byte3;
destination[4] = Byte4;
destination[5] = Byte5;
destination[6] = Byte6;
destination[7] = Byte7;
destination[8] = Byte8;
destination[9] = Byte9;
destination[10] = Byte10;
destination[11] = Byte11;
destination[12] = Byte12;
destination[13] = Byte13;
destination[14] = Byte14;
destination[15] = Byte15;
return true;
}
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\".");
int guidSize;
switch (format[0])
{
case 'D':
case 'd':
guidSize = 36;
break;
case 'N':
case 'n':
guidSize = 32;
break;
case 'B':
case 'b':
case 'P':
case 'p':
guidSize = 38;
break;
case 'X':
case 'x':
guidSize = 68;
break;
default:
throw new FormatException(
"Format string can be only \"D\", \"d\", \"N\", \"n\", \"P\", \"p\", \"B\", \"b\", \"X\" or \"x\".");
}
Span<char> guidString = stackalloc char[guidSize];
var result = TryFormat(guidString, out var bytesWritten, format);
Debug.Assert(result && bytesWritten == guidString.Length, "Formatting Uuidv1 should have succeeded.");
return new string(guidString);
}
public bool TryFormat(Span<char> destination, out int charsWritten, ReadOnlySpan<char> format = default)
{
if (format.Length == 0) 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\".");
var dash = true;
var hex = false;
var braces = 0;
int guidSize;
switch (format[0])
{
case 'D':
case 'd':
guidSize = 36;
break;
case 'N':
case 'n':
dash = false;
guidSize = 32;
break;
case 'B':
case 'b':
braces = '{' + ('}' << 16);
guidSize = 38;
break;
case 'P':
case 'p':
braces = '(' + (')' << 16);
guidSize = 38;
break;
case 'X':
case 'x':
braces = '{' + ('}' << 16);
dash = false;
hex = true;
guidSize = 68;
break;
default:
throw new FormatException(
"Format string can be only \"D\", \"d\", \"N\", \"n\", \"P\", \"p\", \"B\", \"b\", \"X\" or \"x\".");
}
if (destination.Length < guidSize)
{
charsWritten = 0;
return false;
}
unsafe
{
fixed (char* guidCharsReference = &MemoryMarshal.GetReference(destination))
{
var chars = guidCharsReference;
var uints = (uint*) chars;
var bytes = (byte**) &uints;
if (braces != 0)
{
*chars++ = (char) braces;
*bytes += 2;
}
if (hex)
{
// {0xdddddddd,0xdddd,0xdddd,{0xdd,0xdd,0xdd,0xdd,0xdd,0xdd,0xdd,0xdd}}
*chars++ = '0';
*chars++ = 'x';
*bytes += 4;
uints[0] = TableToHex[Byte0];
uints[1] = TableToHex[Byte1];
uints[2] = TableToHex[Byte2];
uints[3] = TableToHex[Byte3];
chars += 8;
*bytes += 16;
*chars++ = ',';
*chars++ = '0';
*chars++ = 'x';
*bytes += 6;
uints[0] = TableToHex[Byte4];
uints[1] = TableToHex[Byte5];
chars += 4;
*bytes += 8;
*chars++ = ',';
*chars++ = '0';
*chars++ = 'x';
*bytes += 6;
uints[0] = TableToHex[Byte6];
uints[1] = TableToHex[Byte7];
chars += 4;
*bytes += 8;
*chars++ = ',';
*chars++ = '{';
*bytes += 4;
*chars++ = '0';
*chars++ = 'x';
*bytes += 4;
uints[0] = TableToHex[Byte8];
chars += 2;
*bytes += 4;
*chars++ = ',';
*bytes += 2;
*chars++ = '0';
*chars++ = 'x';
*bytes += 4;
uints[0] = TableToHex[Byte9];
chars += 2;
*bytes += 4;
*chars++ = ',';
*bytes += 2;
*chars++ = '0';
*chars++ = 'x';
*bytes += 4;
uints[0] = TableToHex[Byte10];
chars += 2;
*bytes += 4;
*chars++ = ',';
*bytes += 2;
*chars++ = '0';
*chars++ = 'x';
*bytes += 4;
uints[0] = TableToHex[Byte11];
chars += 2;
*bytes += 4;
*chars++ = ',';
*bytes += 2;
*chars++ = '0';
*chars++ = 'x';
*bytes += 4;
uints[0] = TableToHex[Byte12];
chars += 2;
*bytes += 4;
*chars++ = ',';
*bytes += 2;
*chars++ = '0';
*chars++ = 'x';
*bytes += 4;
uints[0] = TableToHex[Byte13];
chars += 2;
*bytes += 4;
*chars++ = ',';
*bytes += 2;
*chars++ = '0';
*chars++ = 'x';
*bytes += 4;
uints[0] = TableToHex[Byte14];
chars += 2;
*bytes += 4;
*chars++ = ',';
*bytes += 2;
*chars++ = '0';
*chars++ = 'x';
*bytes += 4;
uints[0] = TableToHex[Byte15];
chars += 2;
*bytes += 4;
*chars++ = '}';
*bytes += 2;
}
else
{
// [{|(]dddddddd[-]dddd[-]dddd[-]dddd[-]dddddddddddd[}|)]
uints[0] = TableToHex[Byte0];
uints[1] = TableToHex[Byte1];
uints[2] = TableToHex[Byte2];
uints[3] = TableToHex[Byte3];
chars += 8;
*bytes += 16;
if (dash)
{
*chars++ = '-';
*bytes += 2;
}
uints[0] = TableToHex[Byte4];
uints[1] = TableToHex[Byte5];
chars += 4;
*bytes += 8;
if (dash)
{
*chars++ = '-';
*bytes += 2;
}
uints[0] = TableToHex[Byte6];
uints[1] = TableToHex[Byte7];
chars += 4;
*bytes += 8;
if (dash)
{
*chars++ = '-';
*bytes += 2;
}
uints[0] = TableToHex[Byte8];
uints[1] = TableToHex[Byte9];
chars += 4;
*bytes += 8;
if (dash)
{
*chars++ = '-';
*bytes += 2;
}
uints[0] = TableToHex[Byte10];
uints[1] = TableToHex[Byte11];
uints[2] = TableToHex[Byte12];
uints[3] = TableToHex[Byte13];
uints[4] = TableToHex[Byte14];
uints[5] = TableToHex[Byte15];
chars += 12;
*bytes += 24;
}
if (braces != 0)
{
*chars++ = (char) (braces >> 16);
*bytes += 2;
}
Debug.Assert(chars - guidCharsReference == guidSize);
}
}
charsWritten = guidSize;
return true;
}
}
}
@krddevdays-bot
Copy link

dich

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment