From 662619f791d16e30cf3a587fad256461b20f9672 Mon Sep 17 00:00:00 2001
From: amsga <49681949+amsga@users.noreply.github.com>
Date: Wed, 5 Jun 2024 23:03:17 +0800
Subject: [PATCH] Added UUID v7 generated based on current system date and time
as well as Fixed Bit-Length Dedicated Counter (Method 1). Added UUID v7
generated based on current system date and time as well as Replace Leftmost
Random Bits with Increased Clock Precision (Method 3).
---
.github/workflows/dotnet.yml | 2 +-
CHANGELOG.md | 8 +
README.md | 2 +-
UUIDUtil/UUIDNamespace.cs | 10 +-
UUIDUtil/UUIDUtil.csproj | 4 +-
UUIDUtil/UUIDv1.cs | 136 ++++++++---------
UUIDUtil/UUIDv6.cs | 106 ++++++-------
UUIDUtil/UUIDv7.cs | 143 +++++++++++++-----
UUIDUtil/Uuid.cs | 41 +++--
XUnitTestProjectUUID/UnitTestUUIDv7.cs | 78 +++++++++-
.../XUnitTestProjectUUID.csproj | 10 +-
11 files changed, 357 insertions(+), 183 deletions(-)
diff --git a/.github/workflows/dotnet.yml b/.github/workflows/dotnet.yml
index 060f0e4..3a90210 100644
--- a/.github/workflows/dotnet.yml
+++ b/.github/workflows/dotnet.yml
@@ -13,7 +13,7 @@ jobs:
strategy:
matrix:
- dotnet: [ '6.0.x' ]
+ dotnet: [ '8.0.x' ]
name: .NET ${{ matrix.dotnet }}
steps:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 46df061..607242e 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -9,6 +9,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## [Unreleased]
+## [v2.1.0-beta] - 2024-06-05
+[v2.1.0-beta](https://github.com/TensionDev/UUIDUtil/releases/tag/v2.1.0-beta)
+
+### Changed
+- Added UUID v7 generated based on current system date and time as well as Fixed Bit-Length Dedicated Counter (Method 1).
+- Added UUID v7 generated based on current system date and time as well as Replace Leftmost Random Bits with Increased Clock Precision (Method 3).
+
+
## [v2.1.0-alpha] - 2023-06-15
[v2.1.0-alpha](https://github.com/TensionDev/UUIDUtil/releases/tag/v2.1.0-alpha)
diff --git a/README.md b/README.md
index b36e8fc..defb031 100644
--- a/README.md
+++ b/README.md
@@ -9,4 +9,4 @@ This project references the following documents for implementation.
- [Universally unique identifier - Wikipedia](https://en.wikipedia.org/wiki/Universally_unique_identifier)
- [MySQL :: MySQL 8.0 Reference Manual :: 12.24 Miscellaneous Functions](https://dev.mysql.com/doc/refman/8.0/en/miscellaneous-functions.html#function_uuid)
- [rfc4122](https://datatracker.ietf.org/doc/html/rfc4122)
-- [draft-ietf-uuidrev-rfc4122bis-14](https://datatracker.ietf.org/doc/html/draft-ietf-uuidrev-rfc4122bis)
+- [rfc9562](https://datatracker.ietf.org/doc/html/rfc9562)
diff --git a/UUIDUtil/UUIDNamespace.cs b/UUIDUtil/UUIDNamespace.cs
index e1f3be1..c437d4e 100644
--- a/UUIDUtil/UUIDNamespace.cs
+++ b/UUIDUtil/UUIDNamespace.cs
@@ -23,23 +23,23 @@ namespace TensionDev.UUID
///
/// Class Library to generate Universally Unique Identifier (UUID) / Globally Unique Identifier (GUID) based on Version 3 (MD5 namespace name-based).
///
- public class UUIDNamespace
+ public static class UUIDNamespace
{
///
/// Namespace for Domain Name System
///
- public static Uuid DNS = new Uuid(0x6ba7b810, 0x9dad, 0x11d1, 0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30, 0xc8);
+ public static readonly Uuid DNS = new Uuid(0x6ba7b810, 0x9dad, 0x11d1, 0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30, 0xc8);
///
/// Namespace for URLs
///
- public static Uuid URL = new Uuid(0x6ba7b811, 0x9dad, 0x11d1, 0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30, 0xc8);
+ public static readonly Uuid URL = new Uuid(0x6ba7b811, 0x9dad, 0x11d1, 0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30, 0xc8);
///
/// Namespace for ISO Object IDs (OIDs)
///
- public static Uuid OID = new Uuid(0x6ba7b812, 0x9dad, 0x11d1, 0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30, 0xc8);
+ public static readonly Uuid OID = new Uuid(0x6ba7b812, 0x9dad, 0x11d1, 0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30, 0xc8);
///
/// Namespace for X.500 Distinguished Names(DNs)
///
- public static Uuid X500 = new Uuid(0x6ba7b814, 0x9dad, 0x11d1, 0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30, 0xc8);
+ public static readonly Uuid X500 = new Uuid(0x6ba7b814, 0x9dad, 0x11d1, 0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30, 0xc8);
}
}
diff --git a/UUIDUtil/UUIDUtil.csproj b/UUIDUtil/UUIDUtil.csproj
index 19c1d51..543a7b6 100644
--- a/UUIDUtil/UUIDUtil.csproj
+++ b/UUIDUtil/UUIDUtil.csproj
@@ -7,12 +7,12 @@
true
true
TensionDev.UUID
- 2.1.0-alpha
+ 2.1.0-beta
TensionDev amsga
TensionDev
TensionDev.UUID
A project to store various UUID functions within a library for future use.
- Copyright (c) TensionDev 2021 - 2023
+ Copyright (c) TensionDev 2021
Apache-2.0
https://github.com/TensionDev/UUIDUtil
https://github.com/TensionDev/UUIDUtil
diff --git a/UUIDUtil/UUIDv1.cs b/UUIDUtil/UUIDv1.cs
index 77ec578..7165ff5 100644
--- a/UUIDUtil/UUIDv1.cs
+++ b/UUIDUtil/UUIDv1.cs
@@ -25,10 +25,10 @@ public class UUIDv1
{
protected internal static System.Net.NetworkInformation.PhysicalAddress s_physicalAddress = System.Net.NetworkInformation.PhysicalAddress.None;
protected internal static Int32 s_clock = Int32.MinValue;
- protected internal static DateTime s_epoch = new DateTime(1582, 10, 15, 0, 0, 0, DateTimeKind.Utc);
+ protected internal static readonly DateTime s_epoch = new DateTime(1582, 10, 15, 0, 0, 0, DateTimeKind.Utc);
- protected internal static Object s_initLock = new Object();
- protected internal static Object s_clockLock = new Object();
+ protected internal static readonly Object s_initLock = new Object();
+ protected internal static readonly Object s_clockLock = new Object();
///
/// Initialises a new GUID/UUID based on Version 1 (date-time and MAC address)
@@ -39,68 +39,6 @@ public static Uuid NewUUIDv1()
return NewUUIDv1(DateTime.UtcNow);
}
- ///
- /// Initialises the 48-bit Node ID and returns it.
- /// Returns the MAC Address of a Network Interface Card, if available.
- /// Otherwise, returns a randomly genrated 48-bit Node ID.
- ///
- /// A byte-array representing the 48-bit Node ID
- public static Byte[] GetNodeID()
- {
- if (System.Net.NetworkInformation.PhysicalAddress.None.Equals(s_physicalAddress))
- {
- System.Net.NetworkInformation.NetworkInterface[] networkInterfaces = System.Net.NetworkInformation.NetworkInterface.GetAllNetworkInterfaces();
- if (networkInterfaces.Length > 0)
- {
- s_physicalAddress = networkInterfaces[0].GetPhysicalAddress();
- }
- else
- {
- using (System.Security.Cryptography.RNGCryptoServiceProvider cryptoServiceProvider = new System.Security.Cryptography.RNGCryptoServiceProvider())
- {
- Byte[] fakeNode = new Byte[6];
- cryptoServiceProvider.GetBytes(fakeNode);
- fakeNode[0] = (Byte)(fakeNode[0] | 0x01);
- s_physicalAddress = new System.Net.NetworkInformation.PhysicalAddress(fakeNode);
- }
- }
- }
-
- return s_physicalAddress.GetAddressBytes();
- }
-
- ///
- /// Intialises the 14-bit Clock Sequence and returns the current value with the Variant.
- /// Will return an incremented Clock Sequence on each call, modulo 14-bit.
- ///
- /// A byte-array representing the 14-bit Clock Sequence, together with the Variant
- public static Byte[] GetClockSequence()
- {
- lock (s_initLock)
- {
- if (s_clock < 0)
- {
- using (System.Security.Cryptography.RNGCryptoServiceProvider cryptoServiceProvider = new System.Security.Cryptography.RNGCryptoServiceProvider())
- {
- Byte[] clockInit = new Byte[4];
- cryptoServiceProvider.GetBytes(clockInit);
- s_clock = BitConverter.ToInt32(clockInit, 0) & 0x3FFF;
- s_clock |= 0x8000;
- }
- }
- }
-
- Int32 result;
- lock (s_clockLock)
- {
- result = s_clock++;
- if (s_clock >= 0xC000)
- s_clock = 0x8000;
- }
-
- return BitConverter.GetBytes(System.Net.IPAddress.HostToNetworkOrder((Int16)result));
- }
-
///
/// Initialises a new GUID/UUID based on Version 1 (date-time and MAC address), based on the given date and time.
///
@@ -146,10 +84,10 @@ public static Uuid NewUUIDv1(DateTime dateTime, Byte[] clockSequence, Byte[] nod
if (nodeID.Length < 6)
throw new ArgumentException(String.Format("Node ID contains less than 48-bit: {0} bytes", nodeID.Length), nameof(nodeID));
- TimeSpan timesince = dateTime.ToUniversalTime() - s_epoch.ToUniversalTime();
- Int64 timeinterval = timesince.Ticks;
+ TimeSpan timeSince = dateTime.ToUniversalTime() - s_epoch.ToUniversalTime();
+ Int64 timeInterval = timeSince.Ticks;
- Byte[] time = BitConverter.GetBytes(System.Net.IPAddress.HostToNetworkOrder(timeinterval));
+ Byte[] time = BitConverter.GetBytes(System.Net.IPAddress.HostToNetworkOrder(timeInterval));
Byte[] hex = new Byte[16];
@@ -178,5 +116,67 @@ public static Uuid NewUUIDv1(DateTime dateTime, Byte[] clockSequence, Byte[] nod
return Id;
}
+
+ ///
+ /// Initialises the 48-bit Node ID and returns it.
+ /// Returns the MAC Address of a Network Interface Card, if available.
+ /// Otherwise, returns a randomly genrated 48-bit Node ID.
+ ///
+ /// A byte-array representing the 48-bit Node ID
+ public static Byte[] GetNodeID()
+ {
+ if (System.Net.NetworkInformation.PhysicalAddress.None.Equals(s_physicalAddress))
+ {
+ System.Net.NetworkInformation.NetworkInterface[] networkInterfaces = System.Net.NetworkInformation.NetworkInterface.GetAllNetworkInterfaces();
+ if (networkInterfaces.Length > 0)
+ {
+ s_physicalAddress = networkInterfaces[0].GetPhysicalAddress();
+ }
+ else
+ {
+ using (System.Security.Cryptography.RNGCryptoServiceProvider cryptoServiceProvider = new System.Security.Cryptography.RNGCryptoServiceProvider())
+ {
+ Byte[] fakeNode = new Byte[6];
+ cryptoServiceProvider.GetBytes(fakeNode);
+ fakeNode[0] = (Byte)(fakeNode[0] | 0x01);
+ s_physicalAddress = new System.Net.NetworkInformation.PhysicalAddress(fakeNode);
+ }
+ }
+ }
+
+ return s_physicalAddress.GetAddressBytes();
+ }
+
+ ///
+ /// Intialises the 14-bit Clock Sequence and returns the current value with the Variant.
+ /// Will return an incremented Clock Sequence on each call, modulo 14-bit.
+ ///
+ /// A byte-array representing the 14-bit Clock Sequence, together with the Variant
+ public static Byte[] GetClockSequence()
+ {
+ lock (s_initLock)
+ {
+ if (s_clock < 0)
+ {
+ using (System.Security.Cryptography.RNGCryptoServiceProvider cryptoServiceProvider = new System.Security.Cryptography.RNGCryptoServiceProvider())
+ {
+ Byte[] clockInit = new Byte[4];
+ cryptoServiceProvider.GetBytes(clockInit);
+ s_clock = BitConverter.ToInt32(clockInit, 0) & 0x3FFF;
+ s_clock |= 0x8000;
+ }
+ }
+ }
+
+ Int32 result;
+ lock (s_clockLock)
+ {
+ result = s_clock++;
+ if (s_clock >= 0xC000)
+ s_clock = 0x8000;
+ }
+
+ return BitConverter.GetBytes(System.Net.IPAddress.HostToNetworkOrder((Int16)result));
+ }
}
}
diff --git a/UUIDUtil/UUIDv6.cs b/UUIDUtil/UUIDv6.cs
index de4c991..81424c4 100644
--- a/UUIDUtil/UUIDv6.cs
+++ b/UUIDUtil/UUIDv6.cs
@@ -24,10 +24,10 @@ namespace TensionDev.UUID
public class UUIDv6
{
protected internal static Int32 s_clock = Int32.MinValue;
- protected internal static DateTime s_epoch = new DateTime(1582, 10, 15, 0, 0, 0, DateTimeKind.Utc);
+ protected internal static readonly DateTime s_epoch = new DateTime(1582, 10, 15, 0, 0, 0, DateTimeKind.Utc);
- protected internal static Object s_initLock = new Object();
- protected internal static Object s_clockLock = new Object();
+ protected internal static readonly Object s_initLock = new Object();
+ protected internal static readonly Object s_clockLock = new Object();
///
/// Initialises a new GUID/UUID based on Version 6 (date-time)
@@ -38,53 +38,6 @@ public static Uuid NewUUIDv6()
return NewUUIDv6(DateTime.UtcNow);
}
- ///
- /// Initialises the 48-bit Node ID and returns it.
- /// Returns a randomly genrated 48-bit Node ID.
- ///
- /// A byte-array representing the 48-bit Node ID
- public static Byte[] GetNodeID()
- {
- using (System.Security.Cryptography.RNGCryptoServiceProvider cryptoServiceProvider = new System.Security.Cryptography.RNGCryptoServiceProvider())
- {
- Byte[] fakeNode = new Byte[6];
- cryptoServiceProvider.GetBytes(fakeNode);
- return fakeNode;
- }
- }
-
- ///
- /// Intialises the 14-bit Clock Sequence and returns the current value with the Variant.
- /// Will return an incremented Clock Sequence on each call, modulo 14-bit.
- ///
- /// A byte-array representing the 14-bit Clock Sequence, together with the Variant
- public static Byte[] GetClockSequence()
- {
- lock (s_initLock)
- {
- if (s_clock < 0)
- {
- using (System.Security.Cryptography.RNGCryptoServiceProvider cryptoServiceProvider = new System.Security.Cryptography.RNGCryptoServiceProvider())
- {
- Byte[] clockInit = new Byte[4];
- cryptoServiceProvider.GetBytes(clockInit);
- s_clock = BitConverter.ToInt32(clockInit, 0) & 0x3FFF;
- s_clock |= 0x8000;
- }
- }
- }
-
- Int32 result;
- lock (s_clockLock)
- {
- result = s_clock++;
- if (s_clock >= 0xC000)
- s_clock = 0x8000;
- }
-
- return BitConverter.GetBytes(System.Net.IPAddress.HostToNetworkOrder((Int16)result));
- }
-
///
/// Initialises a new GUID/UUID based on Version 6 (date-time), based on the given date and time.
///
@@ -130,10 +83,10 @@ public static Uuid NewUUIDv6(DateTime dateTime, Byte[] clockSequence, Byte[] nod
if (nodeID.Length < 6)
throw new ArgumentException(String.Format("Node ID contains less than 48-bit: {0} bytes", nodeID.Length), nameof(nodeID));
- TimeSpan timesince = dateTime.ToUniversalTime() - s_epoch.ToUniversalTime();
- Int64 timeinterval = timesince.Ticks << 4;
+ TimeSpan timeSince = dateTime.ToUniversalTime() - s_epoch.ToUniversalTime();
+ Int64 timeInterval = timeSince.Ticks << 4;
- Byte[] time = BitConverter.GetBytes(System.Net.IPAddress.HostToNetworkOrder(timeinterval));
+ Byte[] time = BitConverter.GetBytes(System.Net.IPAddress.HostToNetworkOrder(timeInterval));
Byte[] hex = new Byte[16];
@@ -162,5 +115,52 @@ public static Uuid NewUUIDv6(DateTime dateTime, Byte[] clockSequence, Byte[] nod
return Id;
}
+
+ ///
+ /// Initialises the 48-bit Node ID and returns it.
+ /// Returns a randomly genrated 48-bit Node ID.
+ ///
+ /// A byte-array representing the 48-bit Node ID
+ public static Byte[] GetNodeID()
+ {
+ using (System.Security.Cryptography.RNGCryptoServiceProvider cryptoServiceProvider = new System.Security.Cryptography.RNGCryptoServiceProvider())
+ {
+ Byte[] fakeNode = new Byte[6];
+ cryptoServiceProvider.GetBytes(fakeNode);
+ return fakeNode;
+ }
+ }
+
+ ///
+ /// Intialises the 14-bit Clock Sequence and returns the current value with the Variant.
+ /// Will return an incremented Clock Sequence on each call, modulo 14-bit.
+ ///
+ /// A byte-array representing the 14-bit Clock Sequence, together with the Variant
+ public static Byte[] GetClockSequence()
+ {
+ lock (s_initLock)
+ {
+ if (s_clock < 0)
+ {
+ using (System.Security.Cryptography.RNGCryptoServiceProvider cryptoServiceProvider = new System.Security.Cryptography.RNGCryptoServiceProvider())
+ {
+ Byte[] clockInit = new Byte[4];
+ cryptoServiceProvider.GetBytes(clockInit);
+ s_clock = BitConverter.ToInt32(clockInit, 0) & 0x3FFF;
+ s_clock |= 0x8000;
+ }
+ }
+ }
+
+ Int32 result;
+ lock (s_clockLock)
+ {
+ result = s_clock++;
+ if (s_clock >= 0xC000)
+ s_clock = 0x8000;
+ }
+
+ return BitConverter.GetBytes(System.Net.IPAddress.HostToNetworkOrder((Int16)result));
+ }
}
}
diff --git a/UUIDUtil/UUIDv7.cs b/UUIDUtil/UUIDv7.cs
index b7b37d5..ef173db 100644
--- a/UUIDUtil/UUIDv7.cs
+++ b/UUIDUtil/UUIDv7.cs
@@ -15,6 +15,7 @@
// limitations under the License.
using System;
+using System.Threading;
namespace TensionDev.UUID
{
@@ -23,45 +24,35 @@ namespace TensionDev.UUID
///
public class UUIDv7
{
- protected internal static DateTime s_epoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
+ protected internal static readonly DateTime s_epoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
- ///
- /// Initialises a new GUID/UUID based on Version 7 (date-time)
- ///
- /// A new Uuid object
- public static Uuid NewUUIDv7()
- {
- return NewUUIDv7(DateTime.UtcNow);
- }
+ protected internal static UInt16 s_counter = 0;
+ protected internal static readonly Object s_counterLock = new Object();
- ///
- /// Initialises the 12-bit rand_a and returns it.
- /// Returns a randomly genrated 16-bit rand_a.
- ///
- /// A byte-array representing the 16-bit rand_a
- public static Byte[] GetRandomA()
+ public enum GenerationMethod
{
- using (System.Security.Cryptography.RNGCryptoServiceProvider cryptoServiceProvider = new System.Security.Cryptography.RNGCryptoServiceProvider())
- {
- Byte[] fakeNode = new Byte[2];
- cryptoServiceProvider.GetBytes(fakeNode);
- return fakeNode;
- }
+ ///
+ /// Random bits for the remaining 74 bits.
+ ///
+ Random = 0,
+ ///
+ /// Fixed Bit-Length Dedicated Counter (Method 1)
+ ///
+ Method1 = 1,
+ //Method2 = 2,
+ ///
+ /// Replace Leftmost Random Bits with Increased Clock Precision (Method 3)
+ ///
+ Method3 = 3,
}
///
- /// Initialises the 62-bit rand_b and returns it.
- /// Returns a randomly genrated 64-bit rand_b.
+ /// Initialises a new GUID/UUID based on Version 7 (date-time)
///
- /// A byte-array representing the 64-bit rand_b
- public static Byte[] GetRandomB()
+ /// A new Uuid object
+ public static Uuid NewUUIDv7(GenerationMethod method = GenerationMethod.Random)
{
- using (System.Security.Cryptography.RNGCryptoServiceProvider cryptoServiceProvider = new System.Security.Cryptography.RNGCryptoServiceProvider())
- {
- Byte[] fakeNode = new Byte[8];
- cryptoServiceProvider.GetBytes(fakeNode);
- return fakeNode;
- }
+ return NewUUIDv7(DateTime.UtcNow, method);
}
///
@@ -69,9 +60,20 @@ public static Byte[] GetRandomB()
///
/// Given Date and Time
/// A new Uuid object
- public static Uuid NewUUIDv7(DateTime dateTime)
+ public static Uuid NewUUIDv7(DateTime dateTime, GenerationMethod method = GenerationMethod.Random)
{
- return NewUUIDv7(dateTime, GetRandomA(), GetRandomB());
+ switch (method)
+ {
+ default:
+ case GenerationMethod.Random:
+ return NewUUIDv7(dateTime, GetRandomA(), GetRandomB());
+
+ case GenerationMethod.Method1:
+ return NewUUIDv7(dateTime, GetFixedBitLengthDedicatedCounterA(), GetRandomB());
+
+ case GenerationMethod.Method3:
+ return NewUUIDv7(dateTime, GetIncreasedClockPrecisionA(dateTime), GetRandomB());
+ }
}
///
@@ -97,10 +99,10 @@ public static Uuid NewUUIDv7(DateTime dateTime, Byte[] randomA, Byte[] randomB)
if (randomB.Length < 8)
throw new ArgumentException(String.Format("rand_b contains less than 64-bit: {0} bytes", randomB.Length), nameof(randomB));
- TimeSpan timesince = dateTime.ToUniversalTime() - s_epoch.ToUniversalTime();
- Int64 timeinterval = ((Int64)timesince.TotalMilliseconds) << 16;
+ TimeSpan timeSince = dateTime.ToUniversalTime() - s_epoch.ToUniversalTime();
+ Int64 timeInterval = ((Int64)timeSince.TotalMilliseconds) << 16;
- Byte[] time = BitConverter.GetBytes(System.Net.IPAddress.HostToNetworkOrder(timeinterval));
+ Byte[] time = BitConverter.GetBytes(System.Net.IPAddress.HostToNetworkOrder(timeInterval));
Byte[] hex = new Byte[16];
@@ -128,5 +130,74 @@ public static Uuid NewUUIDv7(DateTime dateTime, Byte[] randomA, Byte[] randomB)
return Id;
}
+
+ ///
+ /// Initialises the 12-bit rand_a and returns it.
+ /// Returns a randomly genrated 16-bit rand_a.
+ ///
+ /// A byte-array representing the 16-bit rand_a
+ public static Byte[] GetRandomA()
+ {
+ using (System.Security.Cryptography.RNGCryptoServiceProvider cryptoServiceProvider = new System.Security.Cryptography.RNGCryptoServiceProvider())
+ {
+ Byte[] fakeNode = new Byte[2];
+ cryptoServiceProvider.GetBytes(fakeNode);
+ return fakeNode;
+ }
+ }
+
+ ///
+ /// Initialises the 12-bit rand_a based on Method 1 in Section 6.2 and returns it.
+ /// Returns a Fixed-Length Dedicated Counter 16-bit rand_a.
+ ///
+ /// A byte-array representing the 16-bit rand_a
+ public static Byte[] GetFixedBitLengthDedicatedCounterA()
+ {
+ lock (s_counterLock)
+ {
+ Int16 value = Convert.ToInt16(s_counter);
+ Byte[] counter = BitConverter.GetBytes(System.Net.IPAddress.HostToNetworkOrder(value));
+
+ ++s_counter;
+ if (s_counter >= 0x1000)
+ s_counter = 0;
+
+ return counter;
+ }
+ }
+
+ ///
+ /// Initialises the 12-bit rand_a based on Method 3 in Section 6.2 and returns it.
+ /// Returns a Increased Clock Precision 16-bit rand_a.
+ ///
+ ///
+ /// A byte-array representing the 16-bit rand_a
+ public static Byte[] GetIncreasedClockPrecisionA(DateTime currentDateTime)
+ {
+ TimeSpan timeSince = currentDateTime.ToUniversalTime() - s_epoch.ToUniversalTime();
+ Int64 timeInterval = ((Int64)timeSince.TotalMilliseconds);
+ Double precisionInterval = timeSince.TotalMilliseconds - timeInterval;
+ Int16 precisionA = (Int16)Math.Floor(precisionInterval * 0x1000);
+
+ Byte[] bytes = BitConverter.GetBytes(System.Net.IPAddress.HostToNetworkOrder(precisionA));
+
+ return bytes;
+
+ }
+
+ ///
+ /// Initialises the 62-bit rand_b and returns it.
+ /// Returns a randomly genrated 64-bit rand_b.
+ ///
+ /// A byte-array representing the 64-bit rand_b
+ public static Byte[] GetRandomB()
+ {
+ using (System.Security.Cryptography.RNGCryptoServiceProvider cryptoServiceProvider = new System.Security.Cryptography.RNGCryptoServiceProvider())
+ {
+ Byte[] fakeNode = new Byte[8];
+ cryptoServiceProvider.GetBytes(fakeNode);
+ return fakeNode;
+ }
+ }
}
}
diff --git a/UUIDUtil/Uuid.cs b/UUIDUtil/Uuid.cs
index 306ae35..9842b4e 100644
--- a/UUIDUtil/Uuid.cs
+++ b/UUIDUtil/Uuid.cs
@@ -20,7 +20,7 @@
namespace TensionDev.UUID
{
- public class Uuid : IComparable, IEquatable
+ public sealed class Uuid : IComparable, IEquatable
{
private uint _time_low;
private ushort _time_mid;
@@ -162,8 +162,8 @@ public Uuid(uint a, ushort b, ushort c, byte d, byte e, byte[] f) : this()
throw new ArgumentException("f is not 6 bytes long");
_time_low = (uint)System.Net.IPAddress.HostToNetworkOrder((int)a);
- _time_mid = (ushort)System.Net.IPAddress.HostToNetworkOrder((short)b);
- _time_hi_and_version = (ushort)System.Net.IPAddress.HostToNetworkOrder((short)c);
+ _time_mid = (ushort)System.Net.IPAddress.HostToNetworkOrder((Int16)b);
+ _time_hi_and_version = (ushort)System.Net.IPAddress.HostToNetworkOrder((Int16)c);
_clock_seq_hi_and_reserved = d;
_clock_seq_low = e;
f.CopyTo(_node, 0);
@@ -186,8 +186,8 @@ public Uuid(uint a, ushort b, ushort c, byte d, byte e, byte[] f) : this()
public Uuid(uint a, ushort b, ushort c, byte d, byte e, byte f, byte g, byte h, byte i, byte j, byte k) : this()
{
_time_low = (uint)System.Net.IPAddress.HostToNetworkOrder((int)a);
- _time_mid = (ushort)System.Net.IPAddress.HostToNetworkOrder((short)b);
- _time_hi_and_version = (ushort)System.Net.IPAddress.HostToNetworkOrder((short)c);
+ _time_mid = (ushort)System.Net.IPAddress.HostToNetworkOrder((Int16)b);
+ _time_hi_and_version = (ushort)System.Net.IPAddress.HostToNetworkOrder((Int16)c);
_clock_seq_hi_and_reserved = d;
_clock_seq_low = e;
_node[0] = f;
@@ -233,6 +233,7 @@ public static bool TryParse(string input, out Uuid result)
}
catch (Exception)
{
+ // Quietly suppress exception on Parse.
}
return vs;
@@ -297,11 +298,11 @@ public bool Equals(Uuid other)
///
/// Returns a value that indicates whether this instance is equal to a specified object.
///
- /// The object to compare with this instance.
+ /// The object to compare with this instance.
/// true if o is a Uuid that has the same value as this instance; otherwise,false.
- public override bool Equals(object o)
+ public override bool Equals(object obj)
{
- if (o is Uuid other)
+ if (obj is Uuid other)
{
return Equals(other);
}
@@ -483,10 +484,10 @@ private string ToStringBraces()
/// true if a and b are equal; otherwise, false.
public static bool operator ==(Uuid a, Uuid b)
{
- if (a == null && b == null)
+ if (a is null && b is null)
return true;
- if (a == null || b == null)
+ if (a is null || b is null)
return false;
return a.Equals(b);
@@ -502,5 +503,25 @@ private string ToStringBraces()
{
return !(a == b);
}
+
+ public static bool operator <(Uuid a, Uuid b)
+ {
+ return a.CompareTo(b) < 0;
+ }
+
+ public static bool operator >(Uuid a, Uuid b)
+ {
+ return a.CompareTo(b) > 0;
+ }
+
+ public static bool operator <=(Uuid a, Uuid b)
+ {
+ return a.CompareTo(b) <= 0;
+ }
+
+ public static bool operator >=(Uuid a, Uuid b)
+ {
+ return a.CompareTo(b) >= 0;
+ }
}
}
diff --git a/XUnitTestProjectUUID/UnitTestUUIDv7.cs b/XUnitTestProjectUUID/UnitTestUUIDv7.cs
index b100bd0..1448112 100644
--- a/XUnitTestProjectUUID/UnitTestUUIDv7.cs
+++ b/XUnitTestProjectUUID/UnitTestUUIDv7.cs
@@ -1,6 +1,7 @@
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
+using System.Linq;
using System.Threading.Tasks;
using Xunit;
@@ -13,7 +14,7 @@ public void TestGetRandomA()
{
byte[] randA = TensionDev.UUID.UUIDv7.GetRandomA();
- Assert.True(randA.Length == 2);
+ Assert.Equal(2, randA.Length);
}
[Fact]
@@ -25,12 +26,85 @@ public void TestRandomGetRandomA()
Assert.NotEqual(randA1, randA2);
}
+ [Fact]
+ public void TestGetFixedBitLengthDedicatedCounterA()
+ {
+ byte[] counterA = TensionDev.UUID.UUIDv7.GetFixedBitLengthDedicatedCounterA();
+
+ Assert.Equal(2, counterA.Length);
+ }
+
+ [Fact]
+ public void TestUniqueGetFixedBitLengthDedicatedCounterA()
+ {
+ ConcurrentBag countersA = new ConcurrentBag();
+
+ Parallel.For(0, 0x1000,
+ counter =>
+ {
+ countersA.Add(TensionDev.UUID.UUIDv7.GetFixedBitLengthDedicatedCounterA());
+ });
+
+ IEnumerable distinctCounters = countersA.Distinct();
+
+ Assert.Equal(distinctCounters.Count(), countersA.Count);
+ Assert.Equal(0x1000, distinctCounters.Count());
+ Assert.Equal(0x1000, countersA.Count);
+ }
+
+ [Fact]
+ public void TestOverflowGetCounterA()
+ {
+ ConcurrentBag countersA = new ConcurrentBag();
+
+ Parallel.For(0, 0x4000,
+ counter =>
+ {
+ countersA.Add(TensionDev.UUID.UUIDv7.GetFixedBitLengthDedicatedCounterA());
+ });
+
+ IEnumerable distinctCounters = countersA.Select(m => BitConverter.ToInt16(m)).Distinct();
+
+ Assert.Equal(0x1000, distinctCounters.Count());
+ Assert.Equal(0x4000, countersA.Count);
+ }
+
+ [Fact]
+ public void TestGetIncreasedClockPrecisionA()
+ {
+ DateTime dateTime = DateTime.Now;
+ byte[] counterA = TensionDev.UUID.UUIDv7.GetIncreasedClockPrecisionA(dateTime);
+
+ Assert.Equal(2, counterA.Length);
+ }
+
+ [Fact]
+ public void TestOverflowGetIncreasedClockPrecisionA()
+ {
+ ConcurrentBag countersA = new ConcurrentBag();
+
+ DateTime start = DateTime.Now;
+ DateTime end = start.AddMilliseconds(1);
+
+ Parallel.For(start.Ticks, end.Ticks ,
+ ticks =>
+ {
+ DateTime dateTime = new DateTime(ticks, DateTimeKind.Local);
+ countersA.Add(TensionDev.UUID.UUIDv7.GetIncreasedClockPrecisionA(dateTime));
+ });
+
+ IEnumerable distinctCounters = countersA.Select(m => BitConverter.ToInt16(m)).Distinct();
+
+ Assert.Equal(0x1000, distinctCounters.Count());
+ Assert.Equal(10000, countersA.Count);
+ }
+
[Fact]
public void TestGetRandomB()
{
byte[] randB = TensionDev.UUID.UUIDv7.GetRandomB();
- Assert.True(randB.Length == 8);
+ Assert.Equal(8, randB.Length);
}
[Fact]
diff --git a/XUnitTestProjectUUID/XUnitTestProjectUUID.csproj b/XUnitTestProjectUUID/XUnitTestProjectUUID.csproj
index dbcab31..27c8e0c 100644
--- a/XUnitTestProjectUUID/XUnitTestProjectUUID.csproj
+++ b/XUnitTestProjectUUID/XUnitTestProjectUUID.csproj
@@ -1,19 +1,19 @@
- net6.0
+ net8.0
false
-
-
-
+
+
+
all
runtime; build; native; contentfiles; analyzers; buildtransitive
-
+
all
runtime; build; native; contentfiles; analyzers; buildtransitive