@@ -601,14 +601,89 @@ RADIX_TABLE_REVERSE_SIZE :: 80
601601 Stores a bignum as a ASCII string in a given radix (2..64)
602602 The buffer must be appropriately sized. This routine doesn't check.
603603*/
604+
604605_itoa_raw_full :: proc (a: ^Int, radix: i8 , buffer: []u8 , zero_terminate := false , allocator := context .allocator) -> (written: int , err: Error) {
605606 assert_if_nil (a)
606607 context .allocator = allocator
607608
608- temp, denominator := &Int{}, &Int{}
609+ // Calculate largest radix^n that fits within _DIGIT_BITS
610+ divisor := ITOA_DIVISOR
611+ digit_count := ITOA_COUNT
612+ _radix := DIGIT (radix)
613+
614+ if radix != 10 {
615+ i := _WORD (1 )
616+ digit_count = -1
617+ for i < _WORD (1 << _DIGIT_BITS) {
618+ divisor = DIGIT (i)
619+ i *= _WORD (radix)
620+ digit_count += 1
621+ }
622+ }
609623
610- internal_copy (temp, a) or_return
611- internal_set (denominator, radix) or_return
624+ temp := &Int{}
625+ internal_copy (temp, a) or_return
626+ defer internal_destroy (temp)
627+
628+ available := len (buffer)
629+ if zero_terminate {
630+ available -= 1
631+ buffer[available] = 0
632+ }
633+
634+ if a.sign == .Negative {
635+ temp.sign = .Zero_or_Positive
636+ }
637+
638+ remainder: DIGIT
639+ for {
640+ if remainder, err = internal_divmod (temp, temp, divisor); err != nil {
641+ return len (buffer) - available, err
642+ }
643+
644+ count := digit_count
645+ for available > 0 && count > 0 {
646+ available -= 1
647+ buffer[available] = RADIX_TABLE[remainder % _radix]
648+ remainder /= _radix
649+ count -= 1
650+ }
651+
652+ if temp.used == 0 {
653+ break
654+ }
655+ }
656+
657+ // Remove leading zero if we ended up with one.
658+ if buffer[available] == ' 0' {
659+ available += 1
660+ }
661+
662+ if a.sign == .Negative {
663+ available -= 1
664+ buffer[available] = ' -'
665+ }
666+
667+ /*
668+ If we overestimated the size, we need to move the buffer left.
669+ */
670+ written = len (buffer) - available
671+ if written < len (buffer) {
672+ diff := len (buffer) - written
673+ mem.copy (&buffer[0 ], &buffer[diff], written)
674+ }
675+ return written, nil
676+ }
677+
678+ // Old internal digit extraction procedure.
679+ // We're keeping this around as ground truth for the tests.
680+ _itoa_raw_old :: proc (a: ^Int, radix: i8 , buffer: []u8 , zero_terminate := false , allocator := context .allocator) -> (written: int , err: Error) {
681+ assert_if_nil (a)
682+ context .allocator = allocator
683+
684+ temp := &Int{}
685+ internal_copy (temp, a) or_return
686+ defer internal_destroy (temp)
612687
613688 available := len (buffer)
614689 if zero_terminate {
@@ -623,7 +698,6 @@ _itoa_raw_full :: proc(a: ^Int, radix: i8, buffer: []u8, zero_terminate := false
623698 remainder: DIGIT
624699 for {
625700 if remainder, err = #force_inline internal_divmod (temp, temp, DIGIT (radix)); err != nil {
626- internal_destroy (temp, denominator)
627701 return len (buffer) - available, err
628702 }
629703 available -= 1
@@ -638,8 +712,6 @@ _itoa_raw_full :: proc(a: ^Int, radix: i8, buffer: []u8, zero_terminate := false
638712 buffer[available] = ' -'
639713 }
640714
641- internal_destroy (temp, denominator)
642-
643715 /*
644716 If we overestimated the size, we need to move the buffer left.
645717 */
0 commit comments