Explorar o código

big: More ZII refactoring.

Jeroen van Rijn %!s(int64=4) %!d(string=hai) anos
pai
achega
2e372b33a3

+ 3 - 7
core/math/big/api.odin

@@ -141,15 +141,11 @@ cmp_mag :: compare_magnitude;
 
 destroy :: proc {
 	/*
-		Deallocates the backing memory of an `Int` and resets it.
+		Clears one or more `Int`s and dellocates their backing memory.
 
-		int_destroy :: proc(a: ^Int, allocator_zeroes := false, allocator := context.allocator)
+		int_destroy :: proc(integers: ..^Int)
 	*/
 	int_destroy,
 };
 
-init :: proc{
-	int_init_sized,
-	int_init_from_integer,
-	int_init_copy,
-};
+

+ 2 - 1
core/math/big/bigint.odin

@@ -49,7 +49,6 @@ Sign :: enum u8 {
 
 Int :: struct {
 	used:      int,
-	allocated: int,
 	digit:     [dynamic]DIGIT,
 	sign:      Sign,
 };
@@ -71,6 +70,8 @@ Error :: enum i8 {
 	Max_Iterations_Reached = -4,
 	Buffer_Overflow        = -5,
 	Integer_Overflow       = -6,
+	Nil_Pointer_Passed     = -7,
+	Int_Not_Initialized    = -8,
 
 	Unimplemented          = -127,
 };

+ 6 - 1
core/math/big/compare.odin

@@ -12,9 +12,14 @@ package big
 */
 
 import "core:intrinsics"
+import "core:mem"
 
 int_is_initialized :: proc(a: ^Int) -> bool {
-	return a != rawptr(uintptr(0)) && a.allocated >= _MIN_DIGIT_COUNT;
+	if a == nil {
+		return false;
+	}
+	raw := transmute(mem.Raw_Dynamic_Array)a.digit;
+	return raw.cap >= _MIN_DIGIT_COUNT;
 }
 
 int_is_zero :: proc(a: ^Int) -> bool {

+ 4 - 7
core/math/big/example.odin

@@ -53,16 +53,13 @@ print :: proc(name: string, a: ^Int, base := i8(16)) {
 }
 
 demo :: proc() {
-	a, b, c := &Int{}, &Int{}, &Int{};
 	err: Error;
-
-	defer destroy(a);
-	defer destroy(b);
-	defer destroy(c);
+	a, b, c := &Int{}, &Int{}, &Int{};
+	defer destroy(a, b, c);
 
 	err = set(a, 512);
-	err = init(b, a);
-	err = init(c, -4);
+	err = set(b, a);
+	err = set(c, -4);
 
 	print("a", a, 2);
 	print("b", b, 2);

+ 130 - 159
core/math/big/helpers.odin

@@ -11,86 +11,34 @@ package big
 
 import "core:mem"
 import "core:intrinsics"
-//import "core:fmt"
 /*
-	Deallocates the backing memory of an `Int`.
+	Deallocates the backing memory of one or more `Int`s.
 */
-int_destroy :: proc(a: ^Int, allocator_zeroes := false, allocator := context.allocator) {
-	if !is_initialized(a) { return; }
+int_destroy :: proc(integers: ..^Int) {
+	integers := integers;
 
-	if !allocator_zeroes {
+	for a in &integers {
 		mem.zero_slice(a.digit[:]);
+		free(&a.digit[0]);
+		a = &Int{};
 	}
-	free(&a.digit[0]);
-	a.used      = 0;
-	a.allocated = 0;
-}
-
-/*
-	Creates and returns a new `Int`.
-	Size is the last parameter so it doesn't conflict with `int_init_from_integer`,
-	and we can say `init(512)` to init & set to 512.
-*/
-int_init_sized :: proc(a: ^Int, allocator_zeroes := true, allocator := context.allocator, size := _DEFAULT_DIGIT_COUNT) -> (err: Error) {
-	/*
-		Allocating a new variable.
-	*/
-
-	a.digit     = mem.make_dynamic_array_len_cap([dynamic]DIGIT, size, size, allocator);
-	a.allocated = 0;
-	a.used      = 0;
-	a.sign      = .Zero_or_Positive;
-
-	if len(a.digit) != size {
-		return .Out_of_Memory;
-	}
-	a.allocated = size;
-
-	if !allocator_zeroes {
-		_zero_unused(a);
-	}
-	return .OK;
-}
-
-/*
-	Initialize from a signed or unsigned platform integer.
-	Inits a new `Int` and then calls the appropriate `set` routine.
-*/
-int_init_from_integer :: proc(a: ^Int, src: $T, minimize := false, allocator_zeroes := true, allocator := context.allocator) -> (err: Error)
-	where intrinsics.type_is_integer(T) {
-
-	n := _DEFAULT_DIGIT_COUNT;
-	if minimize {
-		n = _MIN_DIGIT_COUNT;
-	}
-
-	return set(a, src, minimize);
-}
-
-/*
-	Initialize an `Int` as a copy from another `Int`.
-*/
-int_init_copy :: proc(dest, src: ^Int, minimize := false, allocator_zeroes := true, allocator := context.allocator) -> (err: Error) {
-	if !is_initialized(src) {
-		return .Invalid_Input;
-	}
-
-	if err == .OK {
-		err = copy(dest, src);
-	}
-	return;
 }
 
 /*
 	Helpers to set an `Int` to a specific value.
 */
-int_set_from_integer :: proc(dest: ^Int, src: $T, minimize := false, allocator_zeroes := true, allocator := context.allocator) -> (err: Error)
+int_set_from_integer :: proc(dest: ^Int, src: $T, minimize := false, allocator := context.allocator) -> (err: Error)
 	where intrinsics.type_is_integer(T) {
 	src := src;
-	if !is_initialized(dest) {
-		grow(dest, _DEFAULT_DIGIT_COUNT);
+	/*
+		Check that dest is usable.
+	*/
+	if dest == nil {
+		return .Nil_Pointer_Passed;
 	}
 
+	if err = _grow_if_uninitialized(dest, minimize); err != .OK { return err; }
+
 	dest.used = 0;
 	dest.sign = .Zero_or_Positive if src >= 0 else .Negative;
 	src = abs(src);
@@ -100,44 +48,43 @@ int_set_from_integer :: proc(dest: ^Int, src: $T, minimize := false, allocator_z
 		dest.used += 1;
 		src >>= _DIGIT_BITS;
 	}
-	if minimize {
-		shrink(dest);
-	}
 	_zero_unused(dest);
 	return .OK;
 }
 
-set :: proc{int_set_from_integer};
+set :: proc { int_set_from_integer, int_copy };
 
 /*
 	Copy one `Int` to another.
 */
-copy :: proc(dest, src: ^Int, allocator := context.allocator) -> (err: Error) {
+int_copy :: proc(dest, src: ^Int, allocator := context.allocator) -> (err: Error) {
 	/*
-		If dest == src, do nothing
+		Check that src and dest are usable.
 	*/
-	if (dest == src) {
-		return .OK;
+	if dest == nil || src == nil {
+		return .Nil_Pointer_Passed;
+	} else if !is_initialized(src) {
+		return .Int_Not_Initialized;
 	}
 
 	/*
-		Check `src` is initialized.
+		If dest == src, do nothing
 	*/
-	if !is_initialized(src) {
-		return .Invalid_Input;
+	if (dest == src) {
+		return .OK;
 	}
 
 	/*
 		Grow `dest` to fit `src`.
+		If `dest` is not yet initialized, it will be using `allocator`.
 	*/
-	if err = grow(dest, src.used); err != .OK {
+	if err = grow(dest, src.used, false, allocator); err != .OK {
 		return err;
 	}
 
 	/*
 		Copy everything over and zero high digits.
 	*/
-	assert(dest.allocated >= src.used);
 	for v, i in src.digit[:src.used+1] {
 		dest.digit[i] = v;
 	}
@@ -146,30 +93,33 @@ copy :: proc(dest, src: ^Int, allocator := context.allocator) -> (err: Error) {
 	_zero_unused(dest);
 	return .OK;
 }
+copy :: proc { int_copy, };
 
 /*
 	Set `dest` to |`src`|.
 */
-abs_bigint :: proc(dest, src: ^Int) -> (err: Error) {
+int_abs :: proc(dest, src: ^Int, allocator := context.allocator) -> (err: Error) {
 	/*
-		If `dest == src`, just fix `dest`'s sign.
+		Check that src and dest are usable.
 	*/
-	if (dest == src) {
-		dest.sign = .Zero_or_Positive;
-		return .OK;
+	if dest == nil || src == nil {
+		return .Nil_Pointer_Passed;
+	} else if !is_initialized(src) {
+		return .Int_Not_Initialized;
 	}
 
 	/*
-		Check they're both initialized.
+		If `dest == src`, just fix `dest`'s sign.
 	*/
-	if !(is_initialized(dest) && is_initialized(src)) {
-		return .Invalid_Input;
+	if (dest == src) {
+		dest.sign = .Zero_or_Positive;
+		return .OK;
 	}
 
 	/*
 		Copy `src` to `dest`
 	*/
-	if err = copy(dest, src); err != .OK {
+	if err = copy(dest, src, allocator); err != .OK {
 		return err;
 	}
 
@@ -180,15 +130,24 @@ abs_bigint :: proc(dest, src: ^Int) -> (err: Error) {
 	return .OK;
 }
 
-abs_integer :: proc(n: $T) -> T where intrinsics.type_is_integer(T) {
+platform_abs :: proc(n: $T) -> T where intrinsics.type_is_integer(T) {
 	return n if n >= 0 else -n;
 }
-abs :: proc{abs_bigint, abs_integer};
+abs :: proc{int_abs, platform_abs};
 
 /*
 	Set `dest` to `-src`.
 */
-neg :: proc(dest, src: ^Int) -> (err: Error) {
+neg :: proc(dest, src: ^Int, allocator := context.allocator) -> (err: Error) {
+	/*
+		Check that src and dest are usable.
+	*/
+	if dest == nil || src == nil {
+		return .Nil_Pointer_Passed;
+	} else if !is_initialized(src) {
+		return .Int_Not_Initialized;
+	}
+
 	/*
 		If `dest == src`, just fix `dest`'s sign.
 	*/
@@ -198,17 +157,10 @@ neg :: proc(dest, src: ^Int) -> (err: Error) {
 		return .OK;
 	}
 
-	/*
-		Check they're both initialized.
-	*/
-	if !(is_initialized(dest) && is_initialized(src)) {
-		return .Invalid_Input;
-	}
-
 	/*
 		Copy `src` to `dest`
 	*/
-	if err = copy(dest, src); err != .OK {
+	if err = copy(dest, src, allocator); err != .OK {
 		return err;
 	}
 
@@ -223,6 +175,15 @@ neg :: proc(dest, src: ^Int) -> (err: Error) {
 	Helpers to extract values from the `Int`.
 */
 extract_bit :: proc(a: ^Int, bit_offset: int) -> (bit: DIGIT, err: Error) {
+	/*
+		Check that `a` is usable.
+	*/
+	if a == nil {
+		return 0, .Nil_Pointer_Passed;
+	} else if !is_initialized(a) {
+		return 0, .Int_Not_Initialized;
+	}
+
 	limb := bit_offset / _DIGIT_BITS;
 	if limb < 0 || limb >= a.used {
 		return 0, .Invalid_Input;
@@ -237,6 +198,15 @@ extract_bit :: proc(a: ^Int, bit_offset: int) -> (bit: DIGIT, err: Error) {
 	TODO: Optimize.
 */
 extract_bits :: proc(a: ^Int, offset, count: int) -> (res: _WORD, err: Error) {
+	/*
+		Check that `a` is usable.
+	*/
+	if a == nil {
+		return 0, .Nil_Pointer_Passed;
+	} else if !is_initialized(a) {
+		return 0, .Int_Not_Initialized;
+	}
+
 	if count > _WORD_BITS || count < 1 {
 		return 0, .Invalid_Input;
 	}
@@ -259,6 +229,10 @@ extract_bits :: proc(a: ^Int, offset, count: int) -> (res: _WORD, err: Error) {
 	Resize backing store.
 */
 shrink :: proc(a: ^Int) -> (err: Error) {
+	if a == nil {
+		return .Nil_Pointer_Passed;
+	}
+
 	needed := max(_MIN_DIGIT_COUNT, a.used);
 
 	if a.used != needed {
@@ -267,102 +241,91 @@ shrink :: proc(a: ^Int) -> (err: Error) {
 	return .OK;
 }
 
-grow :: proc(a: ^Int, n: int, allow_shrink := false) -> (err: Error) {
-	/*
-		By default, calling `grow` with `n` <= a.allocated won't resize.
-		With `allow_shrink` set to `true`, will call resize and shrink the `Int` as a result.
-	*/
+int_grow :: proc(a: ^Int, digits: int, allow_shrink := false, allocator := context.allocator) -> (err: Error) {
+	if a == nil {
+		return .Nil_Pointer_Passed;
+	}
+	raw := transmute(mem.Raw_Dynamic_Array)a.digit;
 
 	/*
 		We need at least _MIN_DIGIT_COUNT or a.used digits, whichever is bigger.
+		The caller is asking for `digits`. Let's be accomodating.
 	*/
-	needed := max(_MIN_DIGIT_COUNT, a.used);
-	/*
-		The caller is asking for `n`. Let's be accomodating.
-	*/
-	needed  = max(needed, n);
-	/*
-		If `allow_shrink` == `false`, we need to needed >= `a.allocated`.
-	*/
+	needed := max(_MIN_DIGIT_COUNT, a.used, digits);
 	if !allow_shrink {
-		needed = max(needed, a.allocated);
+		needed = max(needed, raw.cap);
 	}
 
-	if a.allocated != needed {
+	/*
+		If not yet iniialized, initialize the `digit` backing with the allocator we were passed.
+		Otherwise, `[dynamic]DIGIT` already knows what allocator was used for it, so reuse will do the right thing.
+	*/
+	if raw.cap == 0 {
+		a.digit = mem.make_dynamic_array_len_cap([dynamic]DIGIT, needed, needed, allocator);
+	} else if raw.cap != needed {
 		resize(&a.digit, needed);
-		if len(a.digit) != needed {
-			return .Out_of_Memory;
-		}
 	}
-
-	// a.used      = min(size, a.used);
-	a.allocated = needed;
+	/*
+		Let's see if the allocation/resize worked as expected.
+	*/
+	if len(a.digit) != needed {
+		return .Out_of_Memory;
+	}
 	return .OK;
 }
+grow :: proc { int_grow, };
 
 /*
 	Clear `Int` and resize it to the default size.
 */
-clear :: proc(a: ^Int) -> (err: Error) {
-	assert_initialized(a);
-
-	mem.zero_slice(a.digit[:]);
-	a.sign = .Zero_or_Positive;
-	a.used = 0;
-	grow(a, _DEFAULT_DIGIT_COUNT);
-
-	return .OK;	
-}
-
-/*
-	Set the `Int` to 0 and optionally shrink it to the minimum backing size.
-*/
-zero :: proc(a: ^Int, minimize := false) -> (err: Error) {
-	assert_initialized(a);
+int_clear :: proc(a: ^Int, minimize := false, allocator := context.allocator) -> (err: Error) {
+	if a == nil {
+		return .Nil_Pointer_Passed;
+	}
 
+	raw := transmute(mem.Raw_Dynamic_Array)a.digit;
+	if raw.cap != 0 {
+		mem.zero_slice(a.digit[:]);
+	}
 	a.sign = .Zero_or_Positive;
 	a.used = 0;
-	mem.zero_slice(a.digit[a.used:]);
-	if minimize {
-		return shrink(a);
-	}
 
-	return .OK;
+	return grow(a, a.used, minimize, allocator);
 }
+clear :: proc { int_clear, };
+zero  :: clear;
 
 /*
 	Set the `Int` to 1 and optionally shrink it to the minimum backing size.
 */
-one :: proc(a: ^Int, minimize := false) -> (err: Error) {
-	assert_initialized(a);
+int_one :: proc(a: ^Int, minimize := false, allocator := context.allocator) -> (err: Error) {
+	if err = clear(a, minimize, allocator); err != .OK {
+		return err;
+	}
 
-	a.sign     = .Zero_or_Positive;
 	a.used     = 1;
 	a.digit[0] = 1;
-	mem.zero_slice(a.digit[a.used:]);
-	if minimize {
-		return shrink(a);
-	}
-
+	a.sign     = .Zero_or_Positive;
 	return .OK;
 }
+one :: proc { int_one, };
 
 /*
 	Set the `Int` to -1 and optionally shrink it to the minimum backing size.
 */
-minus_one :: proc(a: ^Int, minimize := false) -> (err: Error) {
-	assert_initialized(a);
+int_minus_one :: proc(a: ^Int, minimize := false, allocator := context.allocator) -> (err: Error) {
+	if err = clear(a, minimize, allocator); err != .OK {
+		return err;
+	}
 
-	a.sign     = .Negative;
 	a.used     = 1;
 	a.digit[0] = 1;
-	mem.zero_slice(a.digit[a.used:]);
-	if minimize {
-		return shrink(a);
-	}
-
+	a.sign     = .Negative;
 	return .OK;
 }
+minus_one :: proc { int_minus_one, };
+
+
 
 power_of_two :: proc(a: ^Int, power: int) -> (err: Error) {
 	assert_initialized(a);
@@ -422,11 +385,18 @@ assert_initialized :: proc(a: ^Int, loc := #caller_location) {
 
 _zero_unused :: proc(a: ^Int) {
 	assert_initialized(a);
-	if a.used < a.allocated {
+	if a.used < len(a.digit) {
 		mem.zero_slice(a.digit[a.used:]);
 	}
 }
 
+_grow_if_uninitialized :: proc(dest: ^Int, minimize := false) -> (err: Error) {
+	if !is_initialized(dest) {
+		return grow(dest, _MIN_DIGIT_COUNT if minimize else _DEFAULT_DIGIT_COUNT);
+	}
+	return .OK;
+}
+
 clamp :: proc(a: ^Int) {
 	assert_initialized(a);
 	/*
@@ -444,4 +414,5 @@ clamp :: proc(a: ^Int) {
 	if is_zero(a) {
 		a.sign = .Zero_or_Positive;
 	}
-}
+}
+

+ 1 - 2
core/math/big/radix.odin

@@ -76,7 +76,7 @@ itoa_string :: proc(a: ^Int, radix := i8(-1), zero_terminate := false, allocator
 				   v := _WORD(a.digit[1]) << _DIGIT_BITS + _WORD(a.digit[0]);
 				   return fmt.tprintf("%v%v", sign, v);
 		   } else {
-				   return fmt.tprintf("[%2d/%2d] %v%v", a.used, a.allocated, sign, a.digit[:a.used]);
+				   return fmt.tprintf("[%2d] %v%v", a.used, sign, a.digit[:a.used]);
 		   }
 	}
 	return strings.clone(fallback(a), allocator), .Unimplemented;
@@ -248,7 +248,6 @@ radix_size :: proc(a: ^Int, radix: i8, zero_terminate := false) -> (size: int, e
  	*/
 	t := &Int{
 		used      = a.used,
-		allocated = a.allocated,
 		sign      = .Zero_or_Positive,
 		digit     = a.digit,
 	};