Skip to content

Instantly share code, notes, and snippets.

@xoofx
Created June 16, 2024 05:11
Show Gist options
  • Select an option

  • Save xoofx/15faa78e5fcb0b6ba5e1432fc42843b6 to your computer and use it in GitHub Desktop.

Select an option

Save xoofx/15faa78e5fcb0b6ba5e1432fc42843b6 to your computer and use it in GitHub Desktop.

Revisions

  1. xoofx created this gist Jun 16, 2024.
    48 changes: 48 additions & 0 deletions UUIDv7Fast.cs
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,48 @@
    // From a discussion on mastodon https://mastodon.social/@[email protected]/112620103070756332
    // This version:
    // * simplifies the setup (an inline array is already a Span)
    // * uses BinaryPrimitives.ReverseEndianness to batch writing the long to the buffer
    // * uses SkipLocalsInit on the ctor to avoid some zero init
    // Should be ~ 15% faster than the revised version with Span
    // Anyway most of the time is spent in DateTimeOffset.UtcNow and RandomNumberGenerator.Fill
    using System.Buffers.Binary;
    using System.Diagnostics.CodeAnalysis;
    using System.Runtime.CompilerServices;
    using System.Runtime.InteropServices;
    using System.Security.Cryptography;

    public readonly struct UUIDv7Fast
    {
    private readonly InteriorStruct _interior;

    [SkipLocalsInit]
    public UUIDv7Fast()
    {
    long timestamp = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();
    Unsafe.As<InteriorStruct, long>(ref _interior) = BitConverter.IsLittleEndian ? BinaryPrimitives.ReverseEndianness(timestamp << 16) : timestamp << 16;
    Span<byte> value = _interior;
    RandomNumberGenerator.Fill(value.Slice(6));
    // version and variant
    value[6] = (byte)((value[6] & 0x0F) | 0x70);
    value[8] = (byte)((value[8] & 0x3F) | 0x80);
    }

    public byte[] GetBytes() => ((ReadOnlySpan<byte>)_interior).ToArray();

    public void CopyTo(Span<byte> destination) => ((ReadOnlySpan<byte>)_interior).CopyTo(destination);

    public override string ToString() => Convert.ToHexString(_interior);

    public override int GetHashCode()
    {
    HashCode hc = new();
    hc.AddBytes(_interior);
    return hc.ToHashCode();
    }

    [InlineArray(16)]
    private struct InteriorStruct
    {
    private byte _element;
    }
    }