Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Format/Parse binary from/to BigInteger #85392

Merged
Changes from 1 commit
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
3c127ea
Initial draft commit: add FormatBigIntegerToBin().
lateapexearlyspeed Apr 26, 2023
64a0ead
Fix comment: use '?:' to assign ValueStringBuilder variable to make i…
lateapexearlyspeed Apr 28, 2023
4216498
Refine FormatBigIntegerToBin(); and consider chars overflow scenario.
lateapexearlyspeed Apr 29, 2023
1bcf7f8
Update Format code for final binary format definition.
lateapexearlyspeed May 15, 2023
63923da
Refine FormatBigIntegerToBin().
lateapexearlyspeed May 23, 2023
19c701d
consider case where output is span
lateapexearlyspeed May 25, 2023
56e701f
Turn to use try..finally to return array pool.
lateapexearlyspeed May 27, 2023
817c58c
Initial add method BinNumberToBigInteger().
lateapexearlyspeed May 27, 2023
24d88c7
Update FormatProvider.Number.cs to support AllowBinarySpecifier.
lateapexearlyspeed May 30, 2023
5a90e15
Use BinNumberToBigInteger().
lateapexearlyspeed May 30, 2023
3987f71
Add tests of Format.
lateapexearlyspeed May 30, 2023
8b58eb7
Add tests of Parse().
lateapexearlyspeed Jun 1, 2023
6cea91a
Improve Format(): use ValueStringBuilder just as wrapper for destinat…
lateapexearlyspeed Jun 1, 2023
3007b48
Fix comment: use ch == '0' || ch == '1'
lateapexearlyspeed Jun 2, 2023
cd0a03d
Fix comment: refactor ParseNumber() to extract common abstract operat…
lateapexearlyspeed Aug 25, 2023
f22d2e9
Fix comment: refine naming; make BinNumberToBigInteger() general patt…
lateapexearlyspeed Sep 1, 2023
17434aa
Fix comment: use internal 'kcbitUint'.
lateapexearlyspeed Sep 15, 2023
bdfddf5
Fix comment: rename 'Bin' method names to 'Binary' ones; remove unnec…
lateapexearlyspeed Oct 5, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -1002,6 +1002,71 @@ internal static char ParseFormatSpecifier(ReadOnlySpan<char> format, out int dig
}
}

private static string? FormatBigIntegerToBin(BigInteger value, int digits)
{
// Get the bytes that make up the BigInteger.
byte[]? arrayToReturnToPool = null;
Span<byte> bits = stackalloc byte[64]; // arbitrary threshold
if (!value.TryWriteOrCountBytes(bits, out int bytesWrittenOrNeeded))
{
bits = arrayToReturnToPool = ArrayPool<byte>.Shared.Rent(bytesWrittenOrNeeded);
bool success = value.TryWriteBytes(bits, out bytesWrittenOrNeeded);
Debug.Assert(success);
stephentoub marked this conversation as resolved.
Show resolved Hide resolved
}
bits = bits.Slice(0, bytesWrittenOrNeeded);

Debug.Assert(!bits.IsEmpty);

byte highByte = bits[bits.Length - 1];
int charCount = highByte == 0 ? 1 : 8 - byte.LeadingZeroCount(highByte);
charCount += (bits.Length - 1) * 8;
if (digits > charCount)
{
charCount = digits;
}

// each byte is typically eight chars
var sb = new ValueStringBuilder(stackalloc char[Math.Min(charCount, 512)]);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maybe

var sb = (charCount <= 512)
   ? new ValueStringBuilder(stackalloc char[charCount])
   : new ValueStringBuilder(charCount);
}

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed, didn't know this pattern can mark sb as 'unsafe to return' for stackalloc before, thanks !


if (charCount > 512)
{
sb = new ValueStringBuilder(charCount);
}

if (digits > charCount)
{
sb.Append(value._sign >= 0 ? '0' : '1', digits - charCount);
}

if (highByte == 0)
{
sb.Append('0');
}
else
{
AppendByte(ref sb, highByte, 7 - byte.LeadingZeroCount(highByte));
}

for (int i = bits.Length - 2; i >= 0; i--)
{
AppendByte(ref sb, bits[i]);
}

if (arrayToReturnToPool is not null)
{
ArrayPool<byte>.Shared.Return(arrayToReturnToPool);
}
return sb.ToString();

static void AppendByte(ref ValueStringBuilder sb, byte b, int startHighBit = 7)
{
for (int i = startHighBit; i >= 0; i--)
{
sb.Append((char)('0' + ((b >> i) & 0x1)));
}
}
}

internal static string FormatBigInteger(BigInteger value, string? format, NumberFormatInfo info)
{
return FormatBigInteger(targetSpan: false, value, format, format, info, default, out _, out _)!;
Expand Down