diff --git a/core/math/big/example.odin b/core/math/big/example.odin index e8793ba23..ae900d0c9 100644 --- a/core/math/big/example.odin +++ b/core/math/big/example.odin @@ -79,14 +79,22 @@ int_to_byte :: proc(v: ^Int) { print("v: ", v); fmt.println(); + t := &Int{}; + defer destroy(t); + if size, err = int_to_bytes_size(v); err != nil { fmt.printf("int_to_bytes_size returned: %v\n", err); return; } b1 := make([]u8, size, context.temp_allocator); err = int_to_bytes_big(v, b1); + int_from_bytes_big(t, b1); fmt.printf("big: %v | err: %v\n", b1, err); + int_from_bytes_big(t, b1); + if internal_cmp_mag(t, v) != 0 { + print("\tError parsing t: ", t); + } if size, err = int_to_bytes_size(v); err != nil { fmt.printf("int_to_bytes_size returned: %v\n", err); @@ -96,6 +104,12 @@ int_to_byte :: proc(v: ^Int) { err = int_to_bytes_big_python(v, b2); fmt.printf("big python: %v | err: %v\n", b2, err); + if err == nil { + int_from_bytes_big_python(t, b2); + if internal_cmp_mag(t, v) != 0 { + print("\tError parsing t: ", t); + } + } if size, err = int_to_bytes_size(v, true); err != nil { fmt.printf("int_to_bytes_size returned: %v\n", err); @@ -105,10 +119,10 @@ int_to_byte :: proc(v: ^Int) { err = int_to_bytes_big(v, b3, true); fmt.printf("big signed: %v | err: %v\n", b3, err); - t := &Int{}; int_from_bytes_big(t, b3, true); - defer destroy(t); - print("t: ", t); + if internal_cmp(t, v) != 0 { + print("\tError parsing t: ", t); + } if size, err = int_to_bytes_size(v, true); err != nil { fmt.printf("int_to_bytes_size returned: %v\n", err); @@ -117,6 +131,11 @@ int_to_byte :: proc(v: ^Int) { b4 := make([]u8, size, context.temp_allocator); err = int_to_bytes_big_python(v, b4, true); fmt.printf("big signed python: %v | err: %v\n", b4, err); + + int_from_bytes_big_python(t, b4, true); + if internal_cmp(t, v) != 0 { + print("\tError parsing t: ", t); + } } int_to_byte_little :: proc(v: ^Int) { @@ -125,6 +144,9 @@ int_to_byte_little :: proc(v: ^Int) { print("v: ", v); fmt.println(); + t := &Int{}; + defer destroy(t); + if size, err = int_to_bytes_size(v); err != nil { fmt.printf("int_to_bytes_size returned: %v\n", err); return; @@ -133,6 +155,10 @@ int_to_byte_little :: proc(v: ^Int) { err = int_to_bytes_little(v, b1); fmt.printf("little: %v | err: %v\n", b1, err); + int_from_bytes_little(t, b1); + if internal_cmp_mag(t, v) != 0 { + print("\tError parsing t: ", t); + } if size, err = int_to_bytes_size(v); err != nil { fmt.printf("int_to_bytes_size returned: %v\n", err); @@ -142,6 +168,12 @@ int_to_byte_little :: proc(v: ^Int) { err = int_to_bytes_little_python(v, b2); fmt.printf("little python: %v | err: %v\n", b2, err); + if err == nil { + int_from_bytes_little_python(t, b2); + if internal_cmp_mag(t, v) != 0 { + print("\tError parsing t: ", t); + } + } if size, err = int_to_bytes_size(v, true); err != nil { fmt.printf("int_to_bytes_size returned: %v\n", err); @@ -151,10 +183,10 @@ int_to_byte_little :: proc(v: ^Int) { err = int_to_bytes_little(v, b3, true); fmt.printf("little signed: %v | err: %v\n", b3, err); - // t := &Int{}; - // int_from_bytes_little(t, b3, true); - // defer destroy(t); - // print("t: ", t); + int_from_bytes_little(t, b3, true); + if internal_cmp(t, v) != 0 { + print("\tError parsing t: ", t); + } if size, err = int_to_bytes_size(v, true); err != nil { fmt.printf("int_to_bytes_size returned: %v\n", err); @@ -163,6 +195,11 @@ int_to_byte_little :: proc(v: ^Int) { b4 := make([]u8, size, context.temp_allocator); err = int_to_bytes_little_python(v, b4, true); fmt.printf("little signed python: %v | err: %v\n", b4, err); + + int_from_bytes_little_python(t, b4, true); + if internal_cmp(t, v) != 0 { + print("\tError parsing t: ", t); + } } demo :: proc() { diff --git a/core/math/big/helpers.odin b/core/math/big/helpers.odin index cdd1e3bcb..81a95a215 100644 --- a/core/math/big/helpers.odin +++ b/core/math/big/helpers.odin @@ -12,6 +12,8 @@ package math_big import "core:intrinsics" import rnd "core:math/rand" +// import "core:fmt" + /* TODO: Int.flags and Constants like ONE, NAN, etc, are not yet properly handled everywhere. */ @@ -608,16 +610,17 @@ int_from_bytes_big :: proc(a: ^Int, buf: []u8, signed := false, allocator := con if l == 0 { return .Invalid_Argument; } sign: Sign; - size_in_bits := l * 8; + size_in_bits := l * 8; if signed { /* First byte denotes the sign. */ size_in_bits -= 8; } - size_in_digits := size_in_bits / _DIGIT_BITS; + size_in_digits := (size_in_bits + _DIGIT_BITS - 1) / _DIGIT_BITS; size_in_digits += 0 if size_in_bits % 8 == 0 else 1; - if err = internal_grow(a, size_in_digits); err != nil { return err; } + if err = internal_zero(a, false, allocator); err != nil { return err; } + if err = internal_grow(a, size_in_digits, false, allocator); err != nil { return err; } if signed { sign = .Zero_or_Positive if buf[0] == 0 else .Negative; @@ -629,9 +632,141 @@ int_from_bytes_big :: proc(a: ^Int, buf: []u8, signed := false, allocator := con a.digit[0] |= DIGIT(v); } a.sign = sign; + a.used = size_in_digits; return internal_clamp(a); } +/* + Read `Int` from a Big Endian Python binary representation. + Sign is detected from the first byte if `signed` is true. +*/ +int_from_bytes_big_python :: proc(a: ^Int, buf: []u8, signed := false, allocator := context.allocator) -> (err: Error) { + assert_if_nil(a); + buf := buf; + l := len(buf); + if l == 0 { return .Invalid_Argument; } + + sign: Sign; + size_in_bits := l * 8; + if signed { + /* + First byte denotes the sign. + */ + size_in_bits -= 8; + } + size_in_digits := (size_in_bits + _DIGIT_BITS - 1) / _DIGIT_BITS; + size_in_digits += 0 if size_in_bits % 8 == 0 else 1; + if err = internal_zero(a, false, allocator); err != nil { return err; } + if err = internal_grow(a, size_in_digits, false, allocator); err != nil { return err; } + + if signed { + sign = .Zero_or_Positive if buf[0] == 0 else .Negative; + buf = buf[1:]; + } + + for v in buf { + if err = internal_shl(a, a, 8); err != nil { return err; } + if signed && sign == .Negative { + a.digit[0] |= DIGIT(255 - v); + } else { + a.digit[0] |= DIGIT(v); + } + } + a.sign = sign; + a.used = size_in_digits; + if err = internal_clamp(a); err != nil { return err; } + + if signed && sign == .Negative { + return internal_sub(a, a, 1); + } + return nil; +} + +/* + Read `Int` from a Little Endian binary representation. + Sign is detected from the last byte if `signed` is true. +*/ +int_from_bytes_little :: proc(a: ^Int, buf: []u8, signed := false, allocator := context.allocator) -> (err: Error) { + assert_if_nil(a); + buf := buf; + l := len(buf); + if l == 0 { return .Invalid_Argument; } + + sign: Sign; + size_in_bits := l * 8; + if signed { + /* + First byte denotes the sign. + */ + size_in_bits -= 8; + } + size_in_digits := (size_in_bits + _DIGIT_BITS - 1) / _DIGIT_BITS; + size_in_digits += 0 if size_in_bits % 8 == 0 else 1; + if err = internal_zero(a, false, allocator); err != nil { return err; } + if err = internal_grow(a, size_in_digits, false, allocator); err != nil { return err; } + + if signed { + sign = .Zero_or_Positive if buf[l-1] == 0 else .Negative; + buf = buf[:l-1]; + l -= 1; + } + + for _, i in buf { + if err = internal_shl(a, a, 8); err != nil { return err; } + a.digit[0] |= DIGIT(buf[l-i-1]); + } + a.sign = sign; + a.used = size_in_digits; + return internal_clamp(a); +} + +/* + Read `Int` from a Little Endian Python binary representation. + Sign is detected from the first byte if `signed` is true. +*/ +int_from_bytes_little_python :: proc(a: ^Int, buf: []u8, signed := false, allocator := context.allocator) -> (err: Error) { + assert_if_nil(a); + buf := buf; + l := len(buf); + if l == 0 { return .Invalid_Argument; } + + sign: Sign; + size_in_bits := l * 8; + if signed { + /* + First byte denotes the sign. + */ + size_in_bits -= 8; + } + size_in_digits := (size_in_bits + _DIGIT_BITS - 1) / _DIGIT_BITS; + size_in_digits += 0 if size_in_bits % 8 == 0 else 1; + if err = internal_zero(a, false, allocator); err != nil { return err; } + if err = internal_grow(a, size_in_digits, false, allocator); err != nil { return err; } + + if signed { + sign = .Zero_or_Positive if buf[l-1] == 0 else .Negative; + buf = buf[:l-1]; + l -= 1; + } + + for _, i in buf { + if err = internal_shl(a, a, 8); err != nil { return err; } + if signed && sign == .Negative { + a.digit[0] |= DIGIT(255 - buf[l-i-1]); + } else { + a.digit[0] |= DIGIT(buf[l-i-1]); + } + } + a.sign = sign; + a.used = size_in_digits; + if err = internal_clamp(a); err != nil { return err; } + + if signed && sign == .Negative { + return internal_sub(a, a, 1); + } + return nil; +} + /* Initialize constants. */