Skip to content

Commit

Permalink
Added shuffle method and targeted .Net 6+ only
Browse files Browse the repository at this point in the history
  • Loading branch information
TimothyMakkison committed Jan 8, 2023
1 parent 82ff62f commit 3698799
Show file tree
Hide file tree
Showing 3 changed files with 81 additions and 65 deletions.
72 changes: 40 additions & 32 deletions src/Ulid.Unity/Assets/Scripts/Ulid/Ulid.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
using System.Runtime.InteropServices;
using System.Runtime.Serialization;
using System.Text;
#if NETCOREAPP3_0_OR_GREATER
#if NET6_0_OR_GREATER
using System.Diagnostics.CodeAnalysis;
using System.Runtime.Intrinsics.X86;
using System.Runtime.Intrinsics;
Expand Down Expand Up @@ -183,30 +183,16 @@ internal Ulid(ReadOnlySpan<char> base32)
randomness8 = (byte)((CharToBase32[base32[22]] << 7) | (CharToBase32[base32[23]] << 2) | (CharToBase32[base32[24]] >> 3));
}

#if NETCOREAPP3_0_OR_GREATER
private static readonly Vector128<byte> guidVecShuffle = Vector128.Create((byte)3, 2, 1, 0, 5, 4, 7, 6, 8, 9, 10, 11, 12, 13, 14, 15);
#endif

// HACK: We assume the layout of a Guid is the following:
// Int32, Int16, Int16, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8
// source: https://github.com/dotnet/runtime/blob/4f9ae42d861fcb4be2fcd5d3d55d5f227d30e723/src/libraries/System.Private.CoreLib/src/System/Guid.cs
public Ulid(Guid guid)
{
#if NET7_0_OR_GREATER
if (Vector128.IsHardwareAccelerated && BitConverter.IsLittleEndian)
{
var vector = Unsafe.As<Guid, Vector128<byte>>(ref guid);
var shuffled = Vector128.Shuffle(vector, Vector128.Create((byte)3, 2, 1, 0, 5, 4, 7, 6, 8, 9, 10, 11, 12, 13, 14, 15));

this = Unsafe.As<Vector128<byte>, Ulid>(ref shuffled);
return;
}
#endif
#if NETCOREAPP3_0_OR_GREATER
if (Ssse3.IsSupported && BitConverter.IsLittleEndian)
#if NET6_0_OR_GREATER
if (IsVector128Supported && BitConverter.IsLittleEndian)
{
var vector = Unsafe.As<Guid, Vector128<byte>>(ref guid);
var shuffled = Ssse3.Shuffle(vector, guidVecShuffle);
var shuffled = Shuffle(vector, Vector128.Create((byte)3, 2, 1, 0, 5, 4, 7, 6, 8, 9, 10, 11, 12, 13, 14, 15));

this = Unsafe.As<Vector128<byte>, Ulid>(ref shuffled);
return;
Expand Down Expand Up @@ -536,7 +522,7 @@ private static bool EqualsCore(in Ulid left, in Ulid right)
return Unsafe.As<Ulid, Vector128<byte>>(ref Unsafe.AsRef(in left)) == Unsafe.As<Ulid, Vector128<byte>>(ref Unsafe.AsRef(in right));
}
#endif
#if NETCOREAPP3_0_OR_GREATER
#if NET6_0_OR_GREATER
if (Sse2.IsSupported)
{
var vA = Unsafe.As<Ulid, Vector128<byte>>(ref Unsafe.AsRef(in left));
Expand Down Expand Up @@ -619,20 +605,11 @@ public static explicit operator Guid(Ulid _this)
/// <returns>The converted <c>Guid</c> value</returns>
public Guid ToGuid()
{
#if NET7_0_OR_GREATER
if (Vector128.IsHardwareAccelerated && BitConverter.IsLittleEndian)
{
var vector = Unsafe.As<Ulid, Vector128<byte>>(ref this);
var shuffled = Vector128.Shuffle(vector, guidVecShuffle);

return Unsafe.As<Vector128<byte>, Guid>(ref shuffled);
}
#endif
#if NETCOREAPP3_0_OR_GREATER
if (Ssse3.IsSupported && BitConverter.IsLittleEndian)
#if NET6_0_OR_GREATER
if (IsVector128Supported && BitConverter.IsLittleEndian)
{
var vector = Unsafe.As<Ulid, Vector128<byte>>(ref this);
var shuffled = Ssse3.Shuffle(vector, Vector128.Create((byte)3, 2, 1, 0, 5, 4, 7, 6, 8, 9, 10, 11, 12, 13, 14, 15));
var shuffled = Shuffle(vector, Vector128.Create((byte)3, 2, 1, 0, 5, 4, 7, 6, 8, 9, 10, 11, 12, 13, 14, 15));

return Unsafe.As<Vector128<byte>, Guid>(ref shuffled);
}
Expand Down Expand Up @@ -662,5 +639,36 @@ public Guid ToGuid()

return MemoryMarshal.Read<Guid>(buf);
}
}

#if NET6_0_OR_GREATER
private static bool IsVector128Supported
{
get
{
#if NET7_0_OR_GREATER
return Vector128.IsHardwareAccelerated;
#endif
return Sse3.IsSupported;
}
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static Vector128<byte> Shuffle(Vector128<byte> value, Vector128<byte> mask)
{
Debug.Assert(BitConverter.IsLittleEndian);
Debug.Assert(IsVector128Supported);

#if NET7_0_OR_GREATER
if (Vector128.IsHardwareAccelerated)
{
return Vector128.Shuffle(value, mask);
}
#endif
if (Ssse3.IsSupported)
{
return Ssse3.Shuffle(value, mask);
}
throw new NotImplementedException();
}
#endif
}
}
72 changes: 40 additions & 32 deletions src/Ulid/Ulid.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
using System.Runtime.InteropServices;
using System.Runtime.Serialization;
using System.Text;
#if NETCOREAPP3_0_OR_GREATER
#if NET6_0_OR_GREATER
using System.Diagnostics.CodeAnalysis;
using System.Runtime.Intrinsics.X86;
using System.Runtime.Intrinsics;
Expand Down Expand Up @@ -183,30 +183,16 @@ internal Ulid(ReadOnlySpan<char> base32)
randomness8 = (byte)((CharToBase32[base32[22]] << 7) | (CharToBase32[base32[23]] << 2) | (CharToBase32[base32[24]] >> 3));
}

#if NETCOREAPP3_0_OR_GREATER
private static readonly Vector128<byte> guidVecShuffle = Vector128.Create((byte)3, 2, 1, 0, 5, 4, 7, 6, 8, 9, 10, 11, 12, 13, 14, 15);
#endif

// HACK: We assume the layout of a Guid is the following:
// Int32, Int16, Int16, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8
// source: https://github.com/dotnet/runtime/blob/4f9ae42d861fcb4be2fcd5d3d55d5f227d30e723/src/libraries/System.Private.CoreLib/src/System/Guid.cs
public Ulid(Guid guid)
{
#if NET7_0_OR_GREATER
if (Vector128.IsHardwareAccelerated && BitConverter.IsLittleEndian)
{
var vector = Unsafe.As<Guid, Vector128<byte>>(ref guid);
var shuffled = Vector128.Shuffle(vector, Vector128.Create((byte)3, 2, 1, 0, 5, 4, 7, 6, 8, 9, 10, 11, 12, 13, 14, 15));

this = Unsafe.As<Vector128<byte>, Ulid>(ref shuffled);
return;
}
#endif
#if NETCOREAPP3_0_OR_GREATER
if (Ssse3.IsSupported && BitConverter.IsLittleEndian)
#if NET6_0_OR_GREATER
if (IsVector128Supported && BitConverter.IsLittleEndian)
{
var vector = Unsafe.As<Guid, Vector128<byte>>(ref guid);
var shuffled = Ssse3.Shuffle(vector, guidVecShuffle);
var shuffled = Shuffle(vector, Vector128.Create((byte)3, 2, 1, 0, 5, 4, 7, 6, 8, 9, 10, 11, 12, 13, 14, 15));

this = Unsafe.As<Vector128<byte>, Ulid>(ref shuffled);
return;
Expand Down Expand Up @@ -536,7 +522,7 @@ private static bool EqualsCore(in Ulid left, in Ulid right)
return Unsafe.As<Ulid, Vector128<byte>>(ref Unsafe.AsRef(in left)) == Unsafe.As<Ulid, Vector128<byte>>(ref Unsafe.AsRef(in right));
}
#endif
#if NETCOREAPP3_0_OR_GREATER
#if NET6_0_OR_GREATER
if (Sse2.IsSupported)
{
var vA = Unsafe.As<Ulid, Vector128<byte>>(ref Unsafe.AsRef(in left));
Expand Down Expand Up @@ -619,20 +605,11 @@ public static explicit operator Guid(Ulid _this)
/// <returns>The converted <c>Guid</c> value</returns>
public Guid ToGuid()
{
#if NET7_0_OR_GREATER
if (Vector128.IsHardwareAccelerated && BitConverter.IsLittleEndian)
{
var vector = Unsafe.As<Ulid, Vector128<byte>>(ref this);
var shuffled = Vector128.Shuffle(vector, guidVecShuffle);

return Unsafe.As<Vector128<byte>, Guid>(ref shuffled);
}
#endif
#if NETCOREAPP3_0_OR_GREATER
if (Ssse3.IsSupported && BitConverter.IsLittleEndian)
#if NET6_0_OR_GREATER
if (IsVector128Supported && BitConverter.IsLittleEndian)
{
var vector = Unsafe.As<Ulid, Vector128<byte>>(ref this);
var shuffled = Ssse3.Shuffle(vector, Vector128.Create((byte)3, 2, 1, 0, 5, 4, 7, 6, 8, 9, 10, 11, 12, 13, 14, 15));
var shuffled = Shuffle(vector, Vector128.Create((byte)3, 2, 1, 0, 5, 4, 7, 6, 8, 9, 10, 11, 12, 13, 14, 15));

return Unsafe.As<Vector128<byte>, Guid>(ref shuffled);
}
Expand Down Expand Up @@ -662,5 +639,36 @@ public Guid ToGuid()

return MemoryMarshal.Read<Guid>(buf);
}
}

#if NET6_0_OR_GREATER
private static bool IsVector128Supported
{
get
{
#if NET7_0_OR_GREATER
return Vector128.IsHardwareAccelerated;
#endif
return Sse3.IsSupported;
}
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static Vector128<byte> Shuffle(Vector128<byte> value, Vector128<byte> mask)
{
Debug.Assert(BitConverter.IsLittleEndian);
Debug.Assert(IsVector128Supported);

#if NET7_0_OR_GREATER
if (Vector128.IsHardwareAccelerated)
{
return Vector128.Shuffle(value, mask);
}
#endif
if (Ssse3.IsSupported)
{
return Ssse3.Shuffle(value, mask);
}
throw new NotImplementedException();
}
#endif
}
}
2 changes: 1 addition & 1 deletion src/Ulid/Ulid.csproj
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFrameworks>netstandard2.0;netcoreapp2.1;netcoreapp3.1;net5.0;net7.0</TargetFrameworks>
<TargetFrameworks>netstandard2.0;netcoreapp2.1;netcoreapp3.1;net5.0;net6.0;net7.0</TargetFrameworks>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<RootNamespace>System</RootNamespace>
<SignAssembly>true</SignAssembly>
Expand Down

0 comments on commit 3698799

Please sign in to comment.