/// <summary> /// Creates and returns random bytes based on internal <see cref="IUlidRng"/>. /// </summary> /// <param name="dateTime"> /// DateTime for which the random bytes need to be generated; this value is used to determine wether a sequence /// needs to be incremented (same timestamp with millisecond resolution) or reset to a new random value. /// </param> /// <returns>Random bytes.</returns> /// <exception cref="InvalidOperationException"> /// Thrown when the specified <paramref name="dateTime"/> is before the last time this method was called. /// </exception> public override byte[] GetRandomBytes(DateTimeOffset dateTime) { lock (_genlock) { // Get unix time for given datetime var timestamp = Ulid.ToUnixTimeMilliseconds(dateTime); if (timestamp <= _lastgen) // Same or earlier timestamp as last time we generated random values? { // Increment our random value by one. var i = RANDLEN; while (--i >= 0 && ++_lastvalue[i] == 0) { ; } // If i made it all the way to -1 we have an overflow and we throw if (i < 0) { throw new OverflowException(); } } else // New(er) timestamp, so generate a new random value and store the new(er) timestamp { _lastvalue = _rng.GetRandomBytes(dateTime); // Use internal RNG to get bytes from _lastvalue[0] = (byte)(_lastvalue[0] & 0x7F); // Mask out bit 0 of the random part _lastgen = timestamp; // Store last timestamp } return(_lastvalue); } }
/// <summary> /// Creates and returns a new <see cref="Ulid"/> based on the specified time and using the specified RNG. /// </summary> /// <param name="time"> /// The <see cref="DateTimeOffset"/> to use for the time-part of the <see cref="Ulid"/>. /// </param> /// <param name="rng">The <see cref="IUlidRng"/> to use for random number generation.</param> /// <returns>Returns a new <see cref="Ulid"/>.</returns> /// <exception cref="ArgumentNullException">Thrown when <paramref name="rng"/> is <see langword="null"/>.</exception> public static Ulid NewUlid(DateTimeOffset time, IUlidRng rng) { if (rng == null) { throw new ArgumentNullException(nameof(rng)); } return(new Ulid(time, rng.GetRandomBytes(time))); }
public static Guid NewGuid() { var timePart = DateTime.Now; var randomPart = DEFAULTRNG.GetRandomBytes(10); var d = DateTimeOffsetToByteArray(timePart); byte[] bytes = new byte[] { d[3], d[2], d[1], d[0], d[5], d[4], d[7], d[6], randomPart[0], randomPart[1], randomPart[2], randomPart[3], randomPart[4], randomPart[5], randomPart[6], randomPart[7] }; return(new Guid(bytes)); //return new byte[] { _d, _c, _b, _a, _f, _e, _h, _g, _i, _j, _k, _l, _m, _n, _o, _p }; }
/// <summary> /// Creates and returns random bytes based on internal <see cref="IUlidRng"/>. /// </summary> /// <param name="dateTime"> /// DateTime for which the random bytes need to be generated; this value is used to determine wether a sequence /// needs to be incremented (same timestamp with millisecond resolution) or reset to a new random value. /// </param> /// <returns>Random bytes.</returns> /// <exception cref="InvalidOperationException"> /// Thrown when the specified <paramref name="dateTime"/> is before the last time this method was called. /// </exception> public override byte[] GetRandomBytes(DateTimeOffset dateTime) { lock (_genlock) { // Get unix time for given datetime var timestamp = Ulid.ToUnixTimeMilliseconds(dateTime); if (timestamp < _lastgen) { throw new InvalidOperationException("Clock moved backwards; this is not supported."); } if (timestamp == _lastgen) // Same timestamp as last time we generated random values? { // Increment our random value by one. var i = RANDLEN; while (--i >= 0 && ++_lastvalue[i] == 0) { ; } // If i made it all the way to -1 we have an overflow and we throw if (i < 0) { throw new OverflowException(); } } else // New(er) timestamp, so generate a new random value and store the new(er) timestamp { _lastvalue = _rng.GetRandomBytes(dateTime); // Use internal RNG to get bytes from for (var i = 0; i < _mask.Length && _mask[i] < 255; i++) // Mask out desired number of MSB's { _lastvalue[i] = (byte)(_lastvalue[i] & _mask[i]); } _lastgen = timestamp; // Store last timestamp } return(_lastvalue); } }
/// <summary> /// Creates and returns a new <see cref="Ulid"/> based on the specified time and using the specified RNG. /// </summary> /// <param name="time"> /// The <see cref="DateTimeOffset"/> to use for the time-part of the <see cref="Ulid"/>. /// </param> /// <param name="rng">The <see cref="IUlidRng"/> to use for random number generation.</param> /// <returns>Returns a new <see cref="Ulid"/>.</returns> public static Ulid NewUlid(DateTimeOffset time, IUlidRng rng) { return(new Ulid(time, rng.GetRandomBytes(10))); }