mirror of
https://github.com/odin-lang/Odin.git
synced 2025-12-30 09:54:45 +00:00
big: Improve int_to_bytes_*.
This commit is contained in:
@@ -73,67 +73,115 @@ print :: proc(name: string, a: ^Int, base := i8(10), print_name := true, newline
|
||||
}
|
||||
}
|
||||
|
||||
int_to_byte :: proc(v: ^Int) {
|
||||
err: Error;
|
||||
size: int;
|
||||
print("v: ", v);
|
||||
fmt.println();
|
||||
|
||||
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);
|
||||
fmt.printf("big: %v | err: %v\n", b1, err);
|
||||
|
||||
|
||||
if size, err = int_to_bytes_size(v); err != nil {
|
||||
fmt.printf("int_to_bytes_size returned: %v\n", err);
|
||||
return;
|
||||
}
|
||||
b2 := make([]u8, size, context.temp_allocator);
|
||||
err = int_to_bytes_big_python(v, b2);
|
||||
fmt.printf("big python: %v | err: %v\n", b2, err);
|
||||
|
||||
|
||||
if size, err = int_to_bytes_size(v, true); err != nil {
|
||||
fmt.printf("int_to_bytes_size returned: %v\n", err);
|
||||
return;
|
||||
}
|
||||
b3 := make([]u8, size, context.temp_allocator);
|
||||
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 size, err = int_to_bytes_size(v, true); err != nil {
|
||||
fmt.printf("int_to_bytes_size returned: %v\n", err);
|
||||
return;
|
||||
}
|
||||
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_to_byte_little :: proc(v: ^Int) {
|
||||
err: Error;
|
||||
size: int;
|
||||
print("v: ", v);
|
||||
fmt.println();
|
||||
|
||||
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_little(v, b1);
|
||||
fmt.printf("little: %v | err: %v\n", b1, err);
|
||||
|
||||
|
||||
if size, err = int_to_bytes_size(v); err != nil {
|
||||
fmt.printf("int_to_bytes_size returned: %v\n", err);
|
||||
return;
|
||||
}
|
||||
b2 := make([]u8, size, context.temp_allocator);
|
||||
err = int_to_bytes_little_python(v, b2);
|
||||
fmt.printf("little python: %v | err: %v\n", b2, err);
|
||||
|
||||
|
||||
if size, err = int_to_bytes_size(v, true); err != nil {
|
||||
fmt.printf("int_to_bytes_size returned: %v\n", err);
|
||||
return;
|
||||
}
|
||||
b3 := make([]u8, size, context.temp_allocator);
|
||||
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);
|
||||
|
||||
if size, err = int_to_bytes_size(v, true); err != nil {
|
||||
fmt.printf("int_to_bytes_size returned: %v\n", err);
|
||||
return;
|
||||
}
|
||||
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);
|
||||
}
|
||||
|
||||
demo :: proc() {
|
||||
a, b, c, d, e, f := &Int{}, &Int{}, &Int{}, &Int{}, &Int{}, &Int{};
|
||||
defer destroy(a, b, c, d, e, f);
|
||||
|
||||
err: Error;
|
||||
set(a, 64336);
|
||||
fmt.println("--- --- --- ---");
|
||||
int_to_byte(a);
|
||||
fmt.println("--- --- --- ---");
|
||||
int_to_byte_little(a);
|
||||
fmt.println("--- --- --- ---");
|
||||
|
||||
foo := "2291194942392555914538479778530519876003906024854260006581638127590953";
|
||||
if err = atoi(a, foo, 10); err != nil { return; }
|
||||
// print("a: ", a, 10, true, true, true);
|
||||
|
||||
byte_length, _ := int_to_bytes_size(a);
|
||||
|
||||
fmt.printf("byte_length(a): %v\n", byte_length);
|
||||
|
||||
buf := make([]u8, byte_length);
|
||||
defer delete(buf);
|
||||
|
||||
err = int_to_bytes_big(a, buf);
|
||||
|
||||
python_big := []u8{
|
||||
84, 252, 50, 97, 27, 81, 11, 101, 58, 96, 138, 175, 65, 202, 109,
|
||||
142, 106, 146, 117, 32, 200, 113, 36, 214, 188, 157, 242, 158, 41,
|
||||
};
|
||||
|
||||
if mem.compare(python_big, buf) == 0 {
|
||||
fmt.printf("int_to_bytes_big: pass\n");
|
||||
} else {
|
||||
fmt.printf("int_to_bytes_big: fail | %v\n", buf);
|
||||
}
|
||||
python_little := []u8{
|
||||
41, 158, 242, 157, 188, 214, 36, 113, 200, 32, 117, 146, 106, 142, 109,
|
||||
202, 65, 175, 138, 96, 58, 101, 11, 81, 27, 97, 50, 252, 84,
|
||||
};
|
||||
|
||||
err = int_to_bytes_little(a, buf);
|
||||
if mem.compare(python_little, buf) == 0 {
|
||||
fmt.printf("int_to_bytes_little: pass\n");
|
||||
} else {
|
||||
fmt.printf("int_to_bytes_little: fail | %v\n", buf);
|
||||
}
|
||||
|
||||
_ = neg(b, a);
|
||||
|
||||
python_little_neg := []u8{
|
||||
215, 97, 13, 98, 67, 41, 219, 142, 55, 223, 138, 109, 149, 113, 146,
|
||||
53, 190, 80, 117, 159, 197, 154, 244, 174, 228, 158, 205, 3, 171,
|
||||
};
|
||||
|
||||
byte_length, _ = int_to_bytes_size_python(b, true);
|
||||
|
||||
fmt.printf("byte_length(a): %v\n", byte_length);
|
||||
|
||||
buf2 := make([]u8, byte_length);
|
||||
defer delete(buf2);
|
||||
|
||||
err = int_to_bytes_little_python(b, buf, true);
|
||||
if mem.compare(python_little_neg, buf) == 0 {
|
||||
fmt.printf("int_to_bytes_little: pass\n");
|
||||
} else {
|
||||
fmt.printf("int_to_bytes_little: %v | %v\n", err, buf);
|
||||
}
|
||||
set(b, -64336);
|
||||
fmt.println("--- --- --- ---");
|
||||
int_to_byte(b);
|
||||
fmt.println("--- --- --- ---");
|
||||
int_to_byte_little(b);
|
||||
fmt.println("--- --- --- ---");
|
||||
}
|
||||
|
||||
main :: proc() {
|
||||
|
||||
@@ -480,22 +480,6 @@ int_to_bytes_size :: proc(a: ^Int, signed := false, allocator := context.allocat
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
Size binary representation, Python `._to_bytes(num_bytes, "endianness", signed=Bool)` compatible.
|
||||
*/
|
||||
int_to_bytes_size_python :: proc(a: ^Int, signed := false, allocator := context.allocator) -> (size_in_bytes: int, err: Error) {
|
||||
assert_if_nil(a);
|
||||
size_in_bytes, err = int_to_bytes_size(a, signed, allocator);
|
||||
|
||||
/*
|
||||
Python uses a complement representation of negative numbers and doesn't add a prefix byte.
|
||||
*/
|
||||
if signed {
|
||||
size_in_bytes -= 1;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
Return Little Endian binary representation of `a`, either signed or unsigned.
|
||||
If `a` is negative and we ask for the default unsigned representation, we return abs(a).
|
||||
@@ -505,13 +489,13 @@ int_to_bytes_little :: proc(a: ^Int, buf: []u8, signed := false, allocator := co
|
||||
size_in_bytes: int;
|
||||
|
||||
if size_in_bytes, err = int_to_bytes_size(a, signed, allocator); err != nil { return err; }
|
||||
if size_in_bytes > len(buf) { return .Buffer_Overflow; }
|
||||
l := len(buf);
|
||||
if size_in_bytes > l { return .Buffer_Overflow; }
|
||||
|
||||
size_in_bits := internal_count_bits(a);
|
||||
i := 0;
|
||||
if signed {
|
||||
i += 1;
|
||||
buf[0] = 1 if a.sign == .Negative else 0;
|
||||
buf[l - 1] = 1 if a.sign == .Negative else 0;
|
||||
}
|
||||
for offset := 0; offset < size_in_bits; offset += 8 {
|
||||
bits, _ := internal_int_bitfield_extract(a, offset, 8);
|
||||
@@ -553,24 +537,31 @@ int_to_bytes_little_python :: proc(a: ^Int, buf: []u8, signed := false, allocato
|
||||
assert_if_nil(a);
|
||||
size_in_bytes: int;
|
||||
|
||||
if a.sign == .Zero_or_Positive {
|
||||
return int_to_bytes_little(a, buf, signed, allocator);
|
||||
}
|
||||
if a.sign == .Negative && !signed { return .Invalid_Argument; }
|
||||
if !signed && a.sign == .Negative { return .Invalid_Argument; }
|
||||
|
||||
l := len(buf);
|
||||
if size_in_bytes, err = int_to_bytes_size_python(a, signed, allocator); err != nil { return err; }
|
||||
if size_in_bytes, err = int_to_bytes_size(a, signed, allocator); err != nil { return err; }
|
||||
if size_in_bytes > l { return .Buffer_Overflow; }
|
||||
|
||||
t := &Int{};
|
||||
defer destroy(t);
|
||||
if err = complement(t, a, allocator); err != nil { return err; }
|
||||
if a.sign == .Negative {
|
||||
t := &Int{};
|
||||
defer destroy(t);
|
||||
if err = internal_complement(t, a, allocator); err != nil { return err; }
|
||||
|
||||
size_in_bits := internal_count_bits(t);
|
||||
i := 0;
|
||||
for offset := 0; offset < size_in_bits; offset += 8 {
|
||||
bits, _ := internal_int_bitfield_extract(t, offset, 8);
|
||||
buf[i] = 255 - u8(bits & 255); i += 1;
|
||||
size_in_bits := internal_count_bits(t);
|
||||
i := 0;
|
||||
for offset := 0; offset < size_in_bits; offset += 8 {
|
||||
bits, _ := internal_int_bitfield_extract(t, offset, 8);
|
||||
buf[i] = 255 - u8(bits & 255); i += 1;
|
||||
}
|
||||
buf[l-1] = 255;
|
||||
} else {
|
||||
size_in_bits := internal_count_bits(a);
|
||||
i := 0;
|
||||
for offset := 0; offset < size_in_bits; offset += 8 {
|
||||
bits, _ := internal_int_bitfield_extract(a, offset, 8);
|
||||
buf[i] = u8(bits & 255); i += 1;
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
@@ -583,29 +574,64 @@ int_to_bytes_big_python :: proc(a: ^Int, buf: []u8, signed := false, allocator :
|
||||
assert_if_nil(a);
|
||||
size_in_bytes: int;
|
||||
|
||||
if a.sign == .Zero_or_Positive {
|
||||
return int_to_bytes_big(a, buf, signed, allocator);
|
||||
}
|
||||
if a.sign == .Negative && !signed { return .Invalid_Argument; }
|
||||
if !signed && a.sign == .Negative { return .Invalid_Argument; }
|
||||
if a.sign == .Zero_or_Positive { return int_to_bytes_big(a, buf, signed, allocator); }
|
||||
|
||||
l := len(buf);
|
||||
if size_in_bytes, err = int_to_bytes_size_python(a, signed, allocator); err != nil { return err; }
|
||||
if size_in_bytes, err = int_to_bytes_size(a, signed, allocator); err != nil { return err; }
|
||||
if size_in_bytes > l { return .Buffer_Overflow; }
|
||||
|
||||
t := &Int{};
|
||||
defer destroy(t);
|
||||
if err = complement(t, a, allocator); err != nil { return err; }
|
||||
|
||||
if err = internal_complement(t, a, allocator); err != nil { return err; }
|
||||
|
||||
size_in_bits := internal_count_bits(t);
|
||||
i := l - 1;
|
||||
|
||||
for offset := 0; offset < size_in_bits; offset += 8 {
|
||||
bits, _ := internal_int_bitfield_extract(a, offset, 8);
|
||||
bits, _ := internal_int_bitfield_extract(t, offset, 8);
|
||||
buf[i] = 255 - u8(bits & 255); i -= 1;
|
||||
}
|
||||
buf[0] = 255;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
Read `Int` from a Big Endian binary representation.
|
||||
Sign is detected from the first byte if `signed` is true.
|
||||
*/
|
||||
int_from_bytes_big :: 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;
|
||||
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 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; }
|
||||
a.digit[0] |= DIGIT(v);
|
||||
}
|
||||
a.sign = sign;
|
||||
return internal_clamp(a);
|
||||
}
|
||||
|
||||
/*
|
||||
Initialize constants.
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user