using System; using System.Security.Cryptography; namespace Quadarax.Foundation.Core.Value.Generators { public class TinyHash : IIdGenerator { #region *** Constants *** public const string DefaultCharset = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; public const int DefaultLength = 5; #endregion #region *** Private fields *** private readonly int _length; private readonly string _charset; #endregion #region *** Constructors *** public TinyHash(string charset, int length) { if (string.IsNullOrEmpty(charset)) throw new ArgumentNullException(nameof(charset)); if (length < 1) throw new ArgumentOutOfRangeException(nameof(length)); _charset = charset; _length = length; } public TinyHash(int length) : this(DefaultCharset, length) { } public TinyHash() : this(DefaultCharset, DefaultLength) { } #endregion #region *** Public Operations *** public string NewId() { var outputChars = new char[_length]; using var rnd = RandomNumberGenerator.Create(); var diff = _charset.Length; var upperBound = uint.MaxValue / diff * diff; var randomBuffer = new byte[sizeof(int)]; for (var i = 0; i < outputChars.Length; i++) { // Generate a fair, random number between minIndex and maxIndex uint randomUInt; do { rnd.GetBytes(randomBuffer); randomUInt = BitConverter.ToUInt32(randomBuffer, 0); } while (randomUInt >= upperBound); var charIndex = (int)(randomUInt % diff); // Set output character based on random index outputChars[i] = _charset[charIndex]; } return new string(outputChars); } #endregion } }