You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
84 lines
3.2 KiB
84 lines
3.2 KiB
using System;
|
|
using System.Text;
|
|
|
|
namespace Infrastructure.Extensions
|
|
{
|
|
public static class GuidExtensions
|
|
{
|
|
private const uint radix = 62;
|
|
private const ulong carry = 297528130221121800; // 2^64 / 62
|
|
private const ulong carryRemainder = 16; // 2^64 % 62
|
|
private const string symbols = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
|
|
private const string outputTemplate = "0000000000000000000000"; // 16 bytes takes up 22 base62 symbols
|
|
|
|
private static void DivRem(ulong num, out ulong quot, out uint rem)
|
|
{
|
|
quot = num / radix;
|
|
rem = (uint)(num - (radix * quot));
|
|
}
|
|
|
|
private static void DivRem(ulong numUpper64, ulong numLower64, out ulong quotUpper, out ulong quotLower, out uint rem)
|
|
{
|
|
DivRem(numUpper64, out quotUpper, out uint remUpper);
|
|
DivRem(numLower64, out quotLower, out uint remLower);
|
|
|
|
// take the upper remainder, and incorporate it into the other lower quotient/lower remainder/output remainder
|
|
remLower += (uint)(remUpper * carryRemainder); // max value = 61 + 61*16 = 1037
|
|
DivRem(remLower, out ulong remLowerQuot, out rem);
|
|
|
|
// at this point the max values are:
|
|
// quotientLower: 2^64-17 / 62, which is 297528130221121799 (any more than 2^64-17 and remainderLower will be under 61)
|
|
// remainderUpper * carry: 61 * 297528130221121800 which is 18149215943488429800
|
|
// remainderLowerQuotient = 1037 / 62 = 16
|
|
quotLower += remUpper * carry; // max value is now 18446744073709551599
|
|
quotLower += remLowerQuot; // max value is now 18446744073709551615. So no overflow.
|
|
}
|
|
|
|
public static string ToBase62(this Guid input)
|
|
{
|
|
return input.ToByteArray().ToBase62();
|
|
}
|
|
|
|
public static string ToBase62(this byte[] bytes, bool zeroPadding = false)
|
|
{
|
|
if (bytes is null)
|
|
{
|
|
throw new ArgumentNullException(nameof(bytes));
|
|
}
|
|
if (bytes.Length != 16)
|
|
{
|
|
throw new ArgumentOutOfRangeException(nameof(bytes));
|
|
}
|
|
|
|
if (!BitConverter.IsLittleEndian)
|
|
{
|
|
#pragma warning disable CA1303 // 请不要将文本作为本地化参数传递
|
|
throw new Exception("Untested on big endian architecture");
|
|
#pragma warning restore CA1303 // 请不要将文本作为本地化参数传递
|
|
}
|
|
|
|
ulong lower, upper;
|
|
|
|
lower = BitConverter.ToUInt64(bytes, 0);
|
|
upper = BitConverter.ToUInt64(bytes, 8);
|
|
|
|
var sb = new StringBuilder(outputTemplate);
|
|
int pos = outputTemplate.Length;
|
|
uint remainder;
|
|
while (upper != 0)
|
|
{
|
|
DivRem(upper, lower, out upper, out lower, out remainder);
|
|
sb[--pos] = symbols[(int)remainder];
|
|
}
|
|
|
|
do
|
|
{
|
|
DivRem(lower, out lower, out remainder);
|
|
sb[--pos] = symbols[(int)remainder];
|
|
} while (lower != 0);
|
|
|
|
if (zeroPadding) pos = 0;
|
|
return sb.ToString(pos, outputTemplate.Length - pos);
|
|
}
|
|
}
|
|
} |