bigint: itoa now writes backwards directly, no need to reverse after.

This commit is contained in:
Jeroen van Rijn
2021-07-18 15:42:19 +02:00
parent 04a83eb9f7
commit d7ae611f76
2 changed files with 40 additions and 27 deletions

View File

@@ -58,12 +58,18 @@ demo :: proc() {
fmt.printf("b: %s, err: %v\n\n", bs, err);
delete(bs);
c, err = init();
c, err = init(-4);
defer destroy(c);
cs, err = itoa(c);
fmt.printf("b: %s, err: %v\n\n", cs, err);
fmt.printf("c: %s, err: %v\n\n", cs, err);
delete(cs);
cstr: cstring;
defer delete(cstr);
cstr, err = itoa_cstring(a);
fmt.printf("cstring: %v, err: %v\n\n", cstr, err);
fmt.println("=== Add ===");
err = sub(c, a, b);

View File

@@ -103,13 +103,19 @@ itoa_cstring :: proc(a: ^Int, radix := i8(-1), allocator := context.allocator) -
Use `radix_size` or `radix_size_estimate` to determine a buffer size big enough.
`written` includes the sign if negative, and the zero terminator if asked for.
If you want a 2s complement negative number, adjust it before calling.
You can pass the output of `radix_size` to `size` if you've previously called it to size
the output buffer. If you haven't, this routine will call it. This way it knows if the buffer
is the appropriate size, and it can avoid writing backwards and then reversing.
is the appropriate size, and we can write directly in place without a reverse step at the end.
=== === === IMPORTANT === === ===
If you determined the buffer size using `radix_size_estimate`, or have a buffer
that you reuse that you know is large enough, don't pass this size unless you know what you are doing,
because we will always write backwards starting at last byte of the buffer.
Keep in mind that if you set `size` yourself and it's smaller than the buffer,
it'll result in buffer overflows, as we use it to avoid reversing at the end
and having to perform a buffer overflow check each character.
*/
itoa_raw :: proc(a: ^Int, radix: i8, buffer: []u8, size := int(-1), zero_terminate := false) -> (written: int, err: Error) {
assert_initialized(a); size := size;
@@ -145,17 +151,20 @@ itoa_raw :: proc(a: ^Int, radix: i8, buffer: []u8, size := int(-1), zero_termina
return 0, .Buffer_Overflow;
}
if is_neg(a) {
buffer[written] = '-';
written += 1;
if zero_terminate {
available -= 1;
buffer[available] = 0;
written += 1;
}
buffer[written] = RADIX_TABLE[a.digit[0]];
written += 1;
available -= 1;
buffer[available] = RADIX_TABLE[a.digit[0]];
written += 1;
if zero_terminate {
buffer[written] = 0;
written += 1;
if is_neg(a) {
available -= 1;
buffer[available] = '-';
written += 1;
}
return written, .OK;
@@ -165,6 +174,15 @@ itoa_raw :: proc(a: ^Int, radix: i8, buffer: []u8, size := int(-1), zero_termina
Fast path for when `Int` fits within a `_WORD`.
*/
if a.used == 1 || a.used == 2 {
if zero_terminate {
if available == 0 {
return written, .Buffer_Overflow;
}
available -= 1;
buffer[available] = 0;
written += 1;
}
val := _WORD(a.digit[1]) << _DIGIT_BITS + _WORD(a.digit[0]);
for val > 0 {
if available == 0 {
@@ -172,8 +190,8 @@ itoa_raw :: proc(a: ^Int, radix: i8, buffer: []u8, size := int(-1), zero_termina
}
q := val / _WORD(radix);
buffer[written] = RADIX_TABLE[val - (q * _WORD(radix))];
available -= 1;
buffer[available] = RADIX_TABLE[val - (q * _WORD(radix))];
written += 1;
val = q;
@@ -182,19 +200,8 @@ itoa_raw :: proc(a: ^Int, radix: i8, buffer: []u8, size := int(-1), zero_termina
if available == 0 {
return written, .Buffer_Overflow;
}
buffer[written] = '-';
available -= 1;
written += 1;
}
/*
Reverse output.
*/
slice.reverse(buffer[:written]);
if zero_terminate {
if available == 0 {
return written, .Buffer_Overflow;
}
buffer[written] = 0;
buffer[available] = '-';
written += 1;
}
return written, .OK;