@@ -325,49 +325,48 @@ internal static bool TryValidateParseStyleInteger(NumberStyles style, [NotNullWh
325325 return true ;
326326 }
327327
328- internal static bool TryParseBigInteger ( string ? value , NumberStyles style , NumberFormatInfo info , out int sign , out uint [ ] ? bits )
328+ internal static bool TryParseBigInteger ( string ? value , NumberStyles style , NumberFormatInfo info , out BigInteger result )
329329 {
330330 if ( value == null )
331331 {
332- sign = 0 ;
333- bits = null ;
332+ result = default ;
334333 return false ;
335334 }
336335
337- return TryParseBigInteger ( value . AsSpan ( ) , style , info , out sign , out bits ) ;
336+ return TryParseBigInteger ( value . AsSpan ( ) , style , info , out result ) ;
338337 }
339338
340- internal static bool TryParseBigInteger ( ReadOnlySpan < char > value , NumberStyles style , NumberFormatInfo info , out int sign , out uint [ ] ? bits )
339+ internal static bool TryParseBigInteger ( ReadOnlySpan < char > value , NumberStyles style , NumberFormatInfo info , out BigInteger result )
341340 {
342- sign = 0 ;
343- bits = null ;
344-
345341 ArgumentException ? e ;
346342 if ( ! TryValidateParseStyleInteger ( style , out e ) )
347343 throw e ; // TryParse still throws ArgumentException on invalid NumberStyles
348344
349345 BigNumberBuffer bignumber = BigNumberBuffer . Create ( ) ;
350346 if ( ! FormatProvider . TryStringToBigInteger ( value , style , info , bignumber . digits , out bignumber . precision , out bignumber . scale , out bignumber . sign ) )
347+ {
348+ result = default ;
351349 return false ;
350+ }
352351
353352 if ( ( style & NumberStyles . AllowHexSpecifier ) != 0 )
354353 {
355- if ( ! HexNumberToBigInteger ( ref bignumber , out sign , out bits ) )
354+ if ( ! HexNumberToBigInteger ( ref bignumber , out result ) )
356355 {
357356 return false ;
358357 }
359358 }
360359 else
361360 {
362- if ( ! NumberToBigInteger ( ref bignumber , out sign , out bits ) )
361+ if ( ! NumberToBigInteger ( ref bignumber , out result ) )
363362 {
364363 return false ;
365364 }
366365 }
367366 return true ;
368367 }
369368
370- internal static ( int sign , uint [ ] ? bits ) ParseBigInteger ( string value , NumberStyles style , NumberFormatInfo info )
369+ internal static BigInteger ParseBigInteger ( string value , NumberStyles style , NumberFormatInfo info )
371370 {
372371 if ( value == null )
373372 {
@@ -377,41 +376,41 @@ internal static (int sign, uint[]? bits) ParseBigInteger(string value, NumberSty
377376 return ParseBigInteger ( value . AsSpan ( ) , style , info ) ;
378377 }
379378
380- internal static ( int sign , uint [ ] ? bits ) ParseBigInteger ( ReadOnlySpan < char > value , NumberStyles style , NumberFormatInfo info )
379+ internal static BigInteger ParseBigInteger ( ReadOnlySpan < char > value , NumberStyles style , NumberFormatInfo info )
381380 {
382381 ArgumentException ? e ;
383382 if ( ! TryValidateParseStyleInteger ( style , out e ) )
384383 throw e ;
385384
386- if ( ! TryParseBigInteger ( value , style , info , out int sign , out uint [ ] ? bits ) )
385+ if ( ! TryParseBigInteger ( value , style , info , out BigInteger result ) )
387386 {
388387 throw new FormatException ( SR . Overflow_ParseBigInteger ) ;
389388 }
390- return ( sign , bits ) ;
389+ return result ;
391390 }
392391
393- private static bool HexNumberToBigInteger ( ref BigNumberBuffer number , out int sign , out uint [ ] ? bits )
392+ private static bool HexNumberToBigInteger ( ref BigNumberBuffer number , out BigInteger result )
394393 {
395- sign = 0 ;
396- bits = null ;
397-
398394 if ( number . digits == null || number . digits . Length == 0 )
395+ {
396+ result = default ;
399397 return false ;
398+ }
400399
401400 const int DigitsPerBlock = 8 ;
402401
403402 int totalDigitCount = number . digits . Length - 1 ; // Ignore trailing '\0'
404403 int blockCount , partialDigitCount ;
405404
406- if ( totalDigitCount % DigitsPerBlock == 0 )
405+ if ( ( uint ) totalDigitCount % DigitsPerBlock == 0 )
407406 {
408407 blockCount = totalDigitCount / DigitsPerBlock ;
409408 partialDigitCount = 0 ;
410409 }
411410 else
412411 {
413- blockCount = ( totalDigitCount / DigitsPerBlock ) + 1 ;
414- partialDigitCount = DigitsPerBlock - ( totalDigitCount % DigitsPerBlock ) ;
412+ blockCount = Math . DivRem ( totalDigitCount , DigitsPerBlock , out int mod ) + 1 ;
413+ partialDigitCount = DigitsPerBlock - mod ;
415414 }
416415
417416 bool isNegative = HexConverter . FromChar ( number . digits [ 0 ] ) >= 8 ;
@@ -427,22 +426,45 @@ private static bool HexNumberToBigInteger(ref BigNumberBuffer number, out int si
427426
428427 try
429428 {
430- foreach ( ReadOnlyMemory < char > digitsChunk in number . digits . GetChunks ( ) )
431- ProcessChunk ( digitsChunk . Span , bitsBuffer ) ;
429+ foreach ( ReadOnlyMemory < char > digitsChunkMem in number . digits . GetChunks ( ) )
430+ {
431+ ReadOnlySpan < char > chunkDigits = digitsChunkMem . Span ;
432+ for ( int i = 0 ; i < chunkDigits . Length ; i ++ )
433+ {
434+ char digitChar = chunkDigits [ i ] ;
435+ if ( digitChar == '\0 ' )
436+ break ;
437+
438+ int hexValue = HexConverter . FromChar ( digitChar ) ;
439+ Debug . Assert ( hexValue != 0xFF ) ;
440+
441+ partialValue = ( partialValue << 4 ) | ( uint ) hexValue ;
442+ partialDigitCount ++ ;
443+
444+ if ( partialDigitCount == DigitsPerBlock )
445+ {
446+ bitsBuffer [ bitsBufferPos ] = ( int ) partialValue ;
447+ bitsBufferPos -- ;
448+ partialValue = 0 ;
449+ partialDigitCount = 0 ;
450+ }
451+ }
452+ }
432453
433454 Debug . Assert ( partialDigitCount == 0 && bitsBufferPos == - 1 ) ;
434455
435456 // BigInteger requires leading zero blocks to be truncated.
436- int blockCountNoLeadingZeros = blockCount ;
437- while ( blockCountNoLeadingZeros > 0 && bitsBuffer [ blockCountNoLeadingZeros - 1 ] == 0 )
438- blockCountNoLeadingZeros -- ;
457+ bitsBuffer = bitsBuffer . TrimEnd ( 0 ) ;
439458
440- if ( blockCountNoLeadingZeros == 0 )
459+ int sign ;
460+ uint [ ] ? bits ;
461+
462+ if ( bitsBuffer . IsEmpty )
441463 {
442464 sign = 0 ;
443465 bits = null ;
444466 }
445- else if ( blockCountNoLeadingZeros == 1 )
467+ else if ( bitsBuffer . Length == 1 )
446468 {
447469 sign = bitsBuffer [ 0 ] ;
448470 bits = null ;
@@ -456,50 +478,24 @@ private static bool HexNumberToBigInteger(ref BigNumberBuffer number, out int si
456478 else
457479 {
458480 sign = isNegative ? - 1 : 1 ;
459- bits = MemoryMarshal . Cast < int , uint > ( bitsBuffer ) . Slice ( 0 , blockCountNoLeadingZeros ) . ToArray ( ) ;
481+ bits = MemoryMarshal . Cast < int , uint > ( bitsBuffer ) . ToArray ( ) ;
460482
461483 if ( isNegative )
462484 NumericsHelpers . DangerousMakeTwosComplement ( bits ) ;
463485 }
464486
487+ result = new BigInteger ( sign , bits ) ;
465488 return true ;
466489 }
467490 finally
468491 {
469492 if ( arrayFromPool != null )
470493 ArrayPool < int > . Shared . Return ( arrayFromPool ) ;
471494 }
472-
473- void ProcessChunk ( ReadOnlySpan < char > chunkDigits , Span < int > _bitsBuffer )
474- {
475- for ( int i = 0 ; i < chunkDigits . Length ; i ++ )
476- {
477- char digitChar = chunkDigits [ i ] ;
478- if ( digitChar == '\0 ' )
479- return ;
480-
481- int hexValue = HexConverter . FromChar ( digitChar ) ;
482- Debug . Assert ( hexValue != 0xFF ) ;
483-
484- partialValue = ( partialValue << 4 ) | ( uint ) hexValue ;
485- partialDigitCount ++ ;
486-
487- if ( partialDigitCount == DigitsPerBlock )
488- {
489- _bitsBuffer [ bitsBufferPos ] = ( int ) partialValue ;
490- bitsBufferPos -- ;
491- partialValue = 0 ;
492- partialDigitCount = 0 ;
493- }
494- }
495- }
496495 }
497496
498- private static bool NumberToBigInteger ( ref BigNumberBuffer number , out int sign , out uint [ ] ? bits )
497+ private static bool NumberToBigInteger ( ref BigNumberBuffer number , out BigInteger result )
499498 {
500- sign = 0 ;
501- bits = null ;
502-
503499 Span < int > stackBuffer = stackalloc int [ BigInteger . StackallocUInt32Limit ] ;
504500 Span < int > currentBuffer = stackBuffer ;
505501 int currentBufferSize = 0 ;
@@ -517,9 +513,11 @@ private static bool NumberToBigInteger(ref BigNumberBuffer number, out int sign,
517513 {
518514 foreach ( ReadOnlyMemory < char > digitsChunk in number . digits . GetChunks ( ) )
519515 {
520- bool isValid = ProcessChunk ( digitsChunk . Span , ref currentBuffer ) ;
521- if ( ! isValid )
516+ if ( ! ProcessChunk ( digitsChunk . Span , ref currentBuffer ) )
517+ {
518+ result = default ;
522519 return false ;
520+ }
523521 }
524522
525523 if ( partialDigitCount > 0 )
@@ -536,12 +534,15 @@ private static bool NumberToBigInteger(ref BigNumberBuffer number, out int sign,
536534 if ( trailingZeroCount > 0 )
537535 MultiplyAdd ( ref currentBuffer , s_uint32PowersOfTen [ trailingZeroCount ] , 0 ) ;
538536
537+ int sign ;
538+ uint [ ] ? bits ;
539+
539540 if ( currentBufferSize == 0 )
540541 {
541542 sign = 0 ;
542543 bits = null ;
543544 }
544- else if ( currentBufferSize == 1 && currentBuffer [ 0 ] <= int . MaxValue )
545+ else if ( currentBufferSize == 1 && ( uint ) currentBuffer [ 0 ] <= int . MaxValue )
545546 {
546547 sign = number . sign ? - currentBuffer [ 0 ] : currentBuffer [ 0 ] ;
547548 bits = null ;
@@ -552,6 +553,7 @@ private static bool NumberToBigInteger(ref BigNumberBuffer number, out int sign,
552553 bits = MemoryMarshal . Cast < int , uint > ( currentBuffer ) . Slice ( 0 , currentBufferSize ) . ToArray ( ) ;
553554 }
554555
556+ result = new BigInteger ( sign , bits ) ;
555557 return true ;
556558 }
557559 finally
@@ -560,7 +562,7 @@ private static bool NumberToBigInteger(ref BigNumberBuffer number, out int sign,
560562 ArrayPool < int > . Shared . Return ( arrayFromPool ) ;
561563 }
562564
563- bool ProcessChunk ( ReadOnlySpan < char > chunkDigits , ref Span < int > _currentBuffer )
565+ bool ProcessChunk ( ReadOnlySpan < char > chunkDigits , ref Span < int > currentBuffer )
564566 {
565567 int remainingIntDigitCount = Math . Max ( numberScale - totalDigitCount , 0 ) ;
566568 ReadOnlySpan < char > intDigitsSpan = chunkDigits . Slice ( 0 , Math . Min ( remainingIntDigitCount , chunkDigits . Length ) ) ;
@@ -578,7 +580,7 @@ bool ProcessChunk(ReadOnlySpan<char> chunkDigits, ref Span<int> _currentBuffer)
578580 // Update the buffer when enough partial digits have been accumulated.
579581 if ( partialDigitCount == MaxPartialDigits )
580582 {
581- MultiplyAdd ( ref _currentBuffer , TenPowMaxPartial , partialValue ) ;
583+ MultiplyAdd ( ref currentBuffer , TenPowMaxPartial , partialValue ) ;
582584 partialValue = 0 ;
583585 partialDigitCount = 0 ;
584586 }
@@ -598,9 +600,9 @@ bool ProcessChunk(ReadOnlySpan<char> chunkDigits, ref Span<int> _currentBuffer)
598600 return true ;
599601 }
600602
601- void MultiplyAdd ( ref Span < int > _currentBuffer , uint multiplier , uint addValue )
603+ void MultiplyAdd ( ref Span < int > currentBuffer , uint multiplier , uint addValue )
602604 {
603- Span < int > curBits = _currentBuffer . Slice ( 0 , currentBufferSize ) ;
605+ Span < int > curBits = currentBuffer . Slice ( 0 , currentBufferSize ) ;
604606 uint carry = addValue ;
605607
606608 for ( int i = 0 ; i < curBits . Length ; i ++ )
@@ -613,19 +615,19 @@ void MultiplyAdd(ref Span<int> _currentBuffer, uint multiplier, uint addValue)
613615 if ( carry == 0 )
614616 return ;
615617
616- if ( currentBufferSize == _currentBuffer . Length )
618+ if ( currentBufferSize == currentBuffer . Length )
617619 {
618620 int [ ] ? arrayToReturn = arrayFromPool ;
619621
620622 arrayFromPool = ArrayPool < int > . Shared . Rent ( checked ( currentBufferSize * 2 ) ) ;
621- _currentBuffer . CopyTo ( arrayFromPool ) ;
622- _currentBuffer = arrayFromPool ;
623+ currentBuffer . CopyTo ( arrayFromPool ) ;
624+ currentBuffer = arrayFromPool ;
623625
624626 if ( arrayToReturn != null )
625627 ArrayPool < int > . Shared . Return ( arrayToReturn ) ;
626628 }
627629
628- _currentBuffer [ currentBufferSize ] = ( int ) carry ;
630+ currentBuffer [ currentBufferSize ] = ( int ) carry ;
629631 currentBufferSize ++ ;
630632 }
631633 }
0 commit comments