mirror of
https://github.com/Ed94/Odin.git
synced 2026-08-04 22:58:46 +00:00
big: Add ASCII file import/export.
This commit is contained in:
@@ -166,6 +166,10 @@ Error :: enum int {
|
|||||||
Division_by_Zero = 8,
|
Division_by_Zero = 8,
|
||||||
Math_Domain_Error = 9,
|
Math_Domain_Error = 9,
|
||||||
|
|
||||||
|
Cannot_Open_File = 50,
|
||||||
|
Cannot_Read_File = 51,
|
||||||
|
Cannot_Write_File = 52,
|
||||||
|
|
||||||
Unimplemented = 127,
|
Unimplemented = 127,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -86,7 +86,7 @@ print :: proc(name: string, a: ^Int, base := i8(10), print_name := true, newline
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// printf :: fmt.printf;
|
printf :: fmt.printf;
|
||||||
|
|
||||||
demo :: proc() {
|
demo :: proc() {
|
||||||
a, b, c, d, e, f, res := &Int{}, &Int{}, &Int{}, &Int{}, &Int{}, &Int{}, &Int{};
|
a, b, c, d, e, f, res := &Int{}, &Int{}, &Int{}, &Int{}, &Int{}, &Int{}, &Int{};
|
||||||
@@ -107,6 +107,18 @@ demo :: proc() {
|
|||||||
print("a(10): ", a, 10, true, true, true);
|
print("a(10): ", a, 10, true, true, true);
|
||||||
fmt.printf("err: %v\n", err);
|
fmt.printf("err: %v\n", err);
|
||||||
fmt.printf("RANDOM_PRIME_ITERATIONS_USED: %v\n", RANDOM_PRIME_ITERATIONS_USED);
|
fmt.printf("RANDOM_PRIME_ITERATIONS_USED: %v\n", RANDOM_PRIME_ITERATIONS_USED);
|
||||||
|
|
||||||
|
// err = internal_int_write_to_ascii_file(a, "a.txt");
|
||||||
|
// if err != nil {
|
||||||
|
// fmt.printf("internal_int_write_to_ascii_file returned %v\n", err);
|
||||||
|
// }
|
||||||
|
|
||||||
|
// err = internal_int_read_from_ascii_file(b, "a.txt");
|
||||||
|
// if err != nil {
|
||||||
|
// fmt.printf("internal_int_read_from_ascii_file returned %v\n", err);
|
||||||
|
// }
|
||||||
|
|
||||||
|
// print("b: ", b);
|
||||||
}
|
}
|
||||||
|
|
||||||
main :: proc() {
|
main :: proc() {
|
||||||
|
|||||||
+67
-12
@@ -16,20 +16,18 @@ package math_big
|
|||||||
|
|
||||||
import "core:intrinsics"
|
import "core:intrinsics"
|
||||||
import "core:mem"
|
import "core:mem"
|
||||||
|
import "core:os"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
This version of `itoa` allocates one behalf of the caller. The caller must free the string.
|
This version of `itoa` allocates on behalf of the caller. The caller must free the string.
|
||||||
|
The radix defaults to 10.
|
||||||
*/
|
*/
|
||||||
int_itoa_string :: proc(a: ^Int, radix := i8(-1), zero_terminate := false, allocator := context.allocator) -> (res: string, err: Error) {
|
int_itoa_string :: proc(a: ^Int, radix := i8(10), zero_terminate := false, allocator := context.allocator) -> (res: string, err: Error) {
|
||||||
assert_if_nil(a);
|
assert_if_nil(a);
|
||||||
context.allocator = allocator;
|
context.allocator = allocator;
|
||||||
|
|
||||||
a := a; radix := radix;
|
a := a; radix := radix;
|
||||||
clear_if_uninitialized(a) or_return;
|
clear_if_uninitialized(a) or_return;
|
||||||
/*
|
|
||||||
Radix defaults to 10.
|
|
||||||
*/
|
|
||||||
radix = radix if radix > 0 else 10;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
TODO: If we want to write a prefix for some of the radixes, we can oversize the buffer.
|
TODO: If we want to write a prefix for some of the radixes, we can oversize the buffer.
|
||||||
@@ -57,18 +55,15 @@ int_itoa_string :: proc(a: ^Int, radix := i8(-1), zero_terminate := false, alloc
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
This version of `itoa` allocates one behalf of the caller. The caller must free the string.
|
This version of `itoa` allocates on behalf of the caller. The caller must free the string.
|
||||||
|
The radix defaults to 10.
|
||||||
*/
|
*/
|
||||||
int_itoa_cstring :: proc(a: ^Int, radix := i8(-1), allocator := context.allocator) -> (res: cstring, err: Error) {
|
int_itoa_cstring :: proc(a: ^Int, radix := i8(10), allocator := context.allocator) -> (res: cstring, err: Error) {
|
||||||
assert_if_nil(a);
|
assert_if_nil(a);
|
||||||
context.allocator = allocator;
|
context.allocator = allocator;
|
||||||
|
|
||||||
a := a; radix := radix;
|
a := a; radix := radix;
|
||||||
clear_if_uninitialized(a) or_return;
|
clear_if_uninitialized(a) or_return;
|
||||||
/*
|
|
||||||
Radix defaults to 10.
|
|
||||||
*/
|
|
||||||
radix = radix if radix > 0 else 10;
|
|
||||||
|
|
||||||
s: string;
|
s: string;
|
||||||
s, err = int_itoa_string(a, radix, true);
|
s, err = int_itoa_string(a, radix, true);
|
||||||
@@ -377,6 +372,66 @@ radix_size :: proc(a: ^Int, radix: i8, zero_terminate := false, allocator := con
|
|||||||
return size, nil;
|
return size, nil;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
We might add functions to read and write byte-encoded Ints from/to files, using `int_to_bytes_*` functions.
|
||||||
|
|
||||||
|
LibTomMath allows exporting/importing to/from a file in ASCII, but it doesn't support a much more compact representation in binary, even though it has several pack functions int_to_bytes_* (which I expanded upon and wrote Python interoperable versions of as well), and (un)pack, which is GMP compatible.
|
||||||
|
Someone could implement their own read/write binary int procedures, of course.
|
||||||
|
|
||||||
|
Could be worthwhile to add a canonical binary file representation with an optional small header that says it's an Odin big.Int, big.Rat or Big.Float, byte count for each component that follows, flag for big/little endian and a flag that says a checksum exists at the end of the file.
|
||||||
|
For big.Rat and big.Float the header couldn't be optional, because we'd have no way to distinguish where the components end.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
Read an Int from an ASCII file.
|
||||||
|
*/
|
||||||
|
internal_int_read_from_ascii_file :: proc(a: ^Int, filename: string, radix := i8(10), allocator := context.allocator) -> (err: Error) {
|
||||||
|
context.allocator = allocator;
|
||||||
|
|
||||||
|
/*
|
||||||
|
We can either read the entire file at once, or read a bunch at a time and keep multiplying by the radix.
|
||||||
|
For now, we'll read the entire file. Eventually we'll replace this with a copy that duplicates the logic
|
||||||
|
of `atoi` so we don't need to read the entire file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
res, ok := os.read_entire_file(filename, allocator);
|
||||||
|
defer delete(res, allocator);
|
||||||
|
|
||||||
|
if !ok {
|
||||||
|
return .Cannot_Read_File;
|
||||||
|
}
|
||||||
|
|
||||||
|
as := string(res);
|
||||||
|
return atoi(a, as, radix);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Write an Int to an ASCII file.
|
||||||
|
*/
|
||||||
|
internal_int_write_to_ascii_file :: proc(a: ^Int, filename: string, radix := i8(10), allocator := context.allocator) -> (err: Error) {
|
||||||
|
context.allocator = allocator;
|
||||||
|
|
||||||
|
/*
|
||||||
|
For now we'll convert the Int using itoa and writing the result in one go.
|
||||||
|
If we want to preserve memory we could duplicate the itoa logic and write backwards.
|
||||||
|
*/
|
||||||
|
|
||||||
|
as := itoa(a, radix) or_return;
|
||||||
|
defer delete(as);
|
||||||
|
|
||||||
|
l := len(as);
|
||||||
|
assert(l > 0);
|
||||||
|
|
||||||
|
data := transmute([]u8)mem.Raw_Slice{
|
||||||
|
data = raw_data(as),
|
||||||
|
len = l,
|
||||||
|
};
|
||||||
|
|
||||||
|
ok := os.write_entire_file(name=filename, data=data, truncate=true);
|
||||||
|
return nil if ok else .Cannot_Write_File;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Overestimate the size needed for the bigint to string conversion by a very small amount.
|
Overestimate the size needed for the bigint to string conversion by a very small amount.
|
||||||
The error is about 10^-8; it will overestimate the result by at most 11 elements for
|
The error is about 10^-8; it will overestimate the result by at most 11 elements for
|
||||||
|
|||||||
Reference in New Issue
Block a user