浏览代码

big: Add `int_from_bytes_*`.

Jeroen van Rijn 4 年之前
父节点
当前提交
eb22a49b02
共有 2 个文件被更改,包括 182 次插入10 次删除
  1. 44 7
      core/math/big/example.odin
  2. 138 3
      core/math/big/helpers.odin

+ 44 - 7
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() {

+ 138 - 3
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.
 */