mirror of
https://github.com/Ed94/Odin.git
synced 2026-08-05 07:08:48 +00:00
Remove unneeded semicolons from the core library
This commit is contained in:
+16
-16
@@ -31,7 +31,7 @@ add :: proc {
|
||||
int_add_digit :: proc(dest, a: ^Int, digit: DIGIT, allocator := context.allocator) -> (err: Error)
|
||||
*/
|
||||
int_add_digit,
|
||||
};
|
||||
}
|
||||
|
||||
/*
|
||||
err = sub(dest, a, b);
|
||||
@@ -45,7 +45,7 @@ sub :: proc {
|
||||
int_sub_digit :: proc(dest, a: ^Int, digit: DIGIT) -> (err: Error)
|
||||
*/
|
||||
int_sub_digit,
|
||||
};
|
||||
}
|
||||
|
||||
/*
|
||||
=== === === === === === === === === === === === === === === === === === === === === === === ===
|
||||
@@ -59,44 +59,44 @@ is_initialized :: proc {
|
||||
int_is_initialized :: proc(a: ^Int) -> bool
|
||||
*/
|
||||
int_is_initialized,
|
||||
};
|
||||
}
|
||||
|
||||
is_zero :: proc {
|
||||
/*
|
||||
int_is_zero :: proc(a: ^Int) -> bool
|
||||
*/
|
||||
int_is_zero,
|
||||
};
|
||||
}
|
||||
|
||||
is_positive :: proc {
|
||||
/*
|
||||
int_is_positive :: proc(a: ^Int) -> bool
|
||||
*/
|
||||
int_is_positive,
|
||||
};
|
||||
is_pos :: is_positive;
|
||||
}
|
||||
is_pos :: is_positive
|
||||
|
||||
is_negative :: proc {
|
||||
/*
|
||||
int_is_negative :: proc(a: ^Int) -> bool
|
||||
*/
|
||||
int_is_negative,
|
||||
};
|
||||
is_neg :: is_negative;
|
||||
}
|
||||
is_neg :: is_negative
|
||||
|
||||
is_even :: proc {
|
||||
/*
|
||||
int_is_even :: proc(a: ^Int) -> bool
|
||||
*/
|
||||
int_is_even,
|
||||
};
|
||||
}
|
||||
|
||||
is_odd :: proc {
|
||||
/*
|
||||
int_is_odd :: proc(a: ^Int) -> bool
|
||||
*/
|
||||
int_is_odd,
|
||||
};
|
||||
}
|
||||
|
||||
is_power_of_two :: proc {
|
||||
/*
|
||||
@@ -107,7 +107,7 @@ is_power_of_two :: proc {
|
||||
int_is_power_of_two :: proc(a: ^Int) -> (res: bool)
|
||||
*/
|
||||
int_is_power_of_two,
|
||||
};
|
||||
}
|
||||
|
||||
compare :: proc {
|
||||
/*
|
||||
@@ -122,16 +122,16 @@ compare :: proc {
|
||||
int_compare_digit :: proc(a: ^Int, u: DIGIT) -> Comparison_Flag
|
||||
*/
|
||||
int_compare_digit,
|
||||
};
|
||||
cmp :: compare;
|
||||
}
|
||||
cmp :: compare
|
||||
|
||||
compare_magnitude :: proc {
|
||||
/*
|
||||
Compare the magnitude of two `Int`s, unsigned.
|
||||
*/
|
||||
int_compare_magnitude,
|
||||
};
|
||||
cmp_mag :: compare_magnitude;
|
||||
}
|
||||
cmp_mag :: compare_magnitude
|
||||
|
||||
/*
|
||||
=== === === === === === === === === === === === === === === === === === === === === === === ===
|
||||
@@ -147,6 +147,6 @@ destroy :: proc {
|
||||
int_destroy :: proc(integers: ..^Int)
|
||||
*/
|
||||
int_destroy,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
|
||||
+45
-45
@@ -33,15 +33,15 @@ import "core:intrinsics"
|
||||
To allow tests to run we add `-define:MATH_BIG_EXE=false` to hardcode the cutoffs for now.
|
||||
*/
|
||||
when #config(MATH_BIG_EXE, true) {
|
||||
MUL_KARATSUBA_CUTOFF := initialize_constants();
|
||||
SQR_KARATSUBA_CUTOFF := _DEFAULT_SQR_KARATSUBA_CUTOFF;
|
||||
MUL_TOOM_CUTOFF := _DEFAULT_MUL_TOOM_CUTOFF;
|
||||
SQR_TOOM_CUTOFF := _DEFAULT_SQR_TOOM_CUTOFF;
|
||||
MUL_KARATSUBA_CUTOFF := initialize_constants()
|
||||
SQR_KARATSUBA_CUTOFF := _DEFAULT_SQR_KARATSUBA_CUTOFF
|
||||
MUL_TOOM_CUTOFF := _DEFAULT_MUL_TOOM_CUTOFF
|
||||
SQR_TOOM_CUTOFF := _DEFAULT_SQR_TOOM_CUTOFF
|
||||
} else {
|
||||
MUL_KARATSUBA_CUTOFF := _DEFAULT_MUL_KARATSUBA_CUTOFF;
|
||||
SQR_KARATSUBA_CUTOFF := _DEFAULT_SQR_KARATSUBA_CUTOFF;
|
||||
MUL_TOOM_CUTOFF := _DEFAULT_MUL_TOOM_CUTOFF;
|
||||
SQR_TOOM_CUTOFF := _DEFAULT_SQR_TOOM_CUTOFF;
|
||||
MUL_KARATSUBA_CUTOFF := _DEFAULT_MUL_KARATSUBA_CUTOFF
|
||||
SQR_KARATSUBA_CUTOFF := _DEFAULT_SQR_KARATSUBA_CUTOFF
|
||||
MUL_TOOM_CUTOFF := _DEFAULT_MUL_TOOM_CUTOFF
|
||||
SQR_TOOM_CUTOFF := _DEFAULT_SQR_TOOM_CUTOFF
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -57,24 +57,24 @@ when #config(MATH_BIG_EXE, true) {
|
||||
debugged where necessary.
|
||||
*/
|
||||
|
||||
_DEFAULT_MUL_KARATSUBA_CUTOFF :: #config(MUL_KARATSUBA_CUTOFF, 80);
|
||||
_DEFAULT_SQR_KARATSUBA_CUTOFF :: #config(SQR_KARATSUBA_CUTOFF, 120);
|
||||
_DEFAULT_MUL_TOOM_CUTOFF :: #config(MUL_TOOM_CUTOFF, 350);
|
||||
_DEFAULT_SQR_TOOM_CUTOFF :: #config(SQR_TOOM_CUTOFF, 400);
|
||||
_DEFAULT_MUL_KARATSUBA_CUTOFF :: #config(MUL_KARATSUBA_CUTOFF, 80)
|
||||
_DEFAULT_SQR_KARATSUBA_CUTOFF :: #config(SQR_KARATSUBA_CUTOFF, 120)
|
||||
_DEFAULT_MUL_TOOM_CUTOFF :: #config(MUL_TOOM_CUTOFF, 350)
|
||||
_DEFAULT_SQR_TOOM_CUTOFF :: #config(SQR_TOOM_CUTOFF, 400)
|
||||
|
||||
|
||||
MAX_ITERATIONS_ROOT_N := 500;
|
||||
MAX_ITERATIONS_ROOT_N := 500
|
||||
|
||||
/*
|
||||
Largest `N` for which we'll compute `N!`
|
||||
*/
|
||||
FACTORIAL_MAX_N := 1_000_000;
|
||||
FACTORIAL_MAX_N := 1_000_000
|
||||
|
||||
/*
|
||||
Cutoff to switch to int_factorial_binary_split, and its max recursion level.
|
||||
*/
|
||||
FACTORIAL_BINARY_SPLIT_CUTOFF := 6100;
|
||||
FACTORIAL_BINARY_SPLIT_MAX_RECURSIONS := 100;
|
||||
FACTORIAL_BINARY_SPLIT_CUTOFF := 6100
|
||||
FACTORIAL_BINARY_SPLIT_MAX_RECURSIONS := 100
|
||||
|
||||
|
||||
/*
|
||||
@@ -85,15 +85,15 @@ FACTORIAL_BINARY_SPLIT_MAX_RECURSIONS := 100;
|
||||
|
||||
2) Optimizations thanks to precomputed masks wouldn't work.
|
||||
*/
|
||||
MATH_BIG_FORCE_64_BIT :: #config(MATH_BIG_FORCE_64_BIT, false);
|
||||
MATH_BIG_FORCE_32_BIT :: #config(MATH_BIG_FORCE_32_BIT, false);
|
||||
MATH_BIG_FORCE_64_BIT :: #config(MATH_BIG_FORCE_64_BIT, false)
|
||||
MATH_BIG_FORCE_32_BIT :: #config(MATH_BIG_FORCE_32_BIT, false)
|
||||
when (MATH_BIG_FORCE_32_BIT && MATH_BIG_FORCE_64_BIT) { #panic("Cannot force 32-bit and 64-bit big backend simultaneously."); };
|
||||
|
||||
_LOW_MEMORY :: #config(BIGINT_SMALL_MEMORY, false);
|
||||
_LOW_MEMORY :: #config(BIGINT_SMALL_MEMORY, false)
|
||||
when _LOW_MEMORY {
|
||||
_DEFAULT_DIGIT_COUNT :: 8;
|
||||
_DEFAULT_DIGIT_COUNT :: 8
|
||||
} else {
|
||||
_DEFAULT_DIGIT_COUNT :: 32;
|
||||
_DEFAULT_DIGIT_COUNT :: 32
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -103,22 +103,22 @@ when _LOW_MEMORY {
|
||||
Sign :: enum u8 {
|
||||
Zero_or_Positive = 0,
|
||||
Negative = 1,
|
||||
};
|
||||
}
|
||||
|
||||
Int :: struct {
|
||||
used: int,
|
||||
digit: [dynamic]DIGIT,
|
||||
sign: Sign,
|
||||
flags: Flags,
|
||||
};
|
||||
}
|
||||
|
||||
Flag :: enum u8 {
|
||||
NaN,
|
||||
Inf,
|
||||
Immutable,
|
||||
};
|
||||
}
|
||||
|
||||
Flags :: bit_set[Flag; u8];
|
||||
Flags :: bit_set[Flag; u8]
|
||||
|
||||
/*
|
||||
Errors are a strict superset of runtime.Allocation_Error.
|
||||
@@ -138,7 +138,7 @@ Error :: enum int {
|
||||
Math_Domain_Error = 9,
|
||||
|
||||
Unimplemented = 127,
|
||||
};
|
||||
}
|
||||
|
||||
Error_String :: #partial [Error]string{
|
||||
.Out_Of_Memory = "Out of memory",
|
||||
@@ -154,14 +154,14 @@ Error_String :: #partial [Error]string{
|
||||
.Math_Domain_Error = "Math domain error",
|
||||
|
||||
.Unimplemented = "Unimplemented",
|
||||
};
|
||||
}
|
||||
|
||||
Primality_Flag :: enum u8 {
|
||||
Blum_Blum_Shub = 0, /* BBS style prime */
|
||||
Safe = 1, /* Safe prime (p-1)/2 == prime */
|
||||
Second_MSB_On = 3, /* force 2nd MSB to 1 */
|
||||
};
|
||||
Primality_Flags :: bit_set[Primality_Flag; u8];
|
||||
}
|
||||
Primality_Flags :: bit_set[Primality_Flag; u8]
|
||||
|
||||
/*
|
||||
How do we store the Ints?
|
||||
@@ -171,7 +171,7 @@ Primality_Flags :: bit_set[Primality_Flag; u8];
|
||||
- Must be large enough such that `init_integer` can store `u128` in the `Int` without growing.
|
||||
*/
|
||||
|
||||
_MIN_DIGIT_COUNT :: max(3, ((size_of(u128) + _DIGIT_BITS) - 1) / _DIGIT_BITS);
|
||||
_MIN_DIGIT_COUNT :: max(3, ((size_of(u128) + _DIGIT_BITS) - 1) / _DIGIT_BITS)
|
||||
#assert(_DEFAULT_DIGIT_COUNT >= _MIN_DIGIT_COUNT);
|
||||
|
||||
/*
|
||||
@@ -180,36 +180,36 @@ _MIN_DIGIT_COUNT :: max(3, ((size_of(u128) + _DIGIT_BITS) - 1) / _DIGIT_BITS);
|
||||
- Must be small enough such that `_radix_size` for base 2 does not overflow.
|
||||
`_radix_size` needs two additional bytes for zero termination and sign.
|
||||
*/
|
||||
_MAX_BIT_COUNT :: (max(int) - 2);
|
||||
_MAX_DIGIT_COUNT :: _MAX_BIT_COUNT / _DIGIT_BITS;
|
||||
_MAX_BIT_COUNT :: (max(int) - 2)
|
||||
_MAX_DIGIT_COUNT :: _MAX_BIT_COUNT / _DIGIT_BITS
|
||||
|
||||
when MATH_BIG_FORCE_64_BIT || (!MATH_BIG_FORCE_32_BIT && size_of(rawptr) == 8) {
|
||||
/*
|
||||
We can use u128 as an intermediary.
|
||||
*/
|
||||
DIGIT :: distinct u64;
|
||||
_WORD :: distinct u128;
|
||||
DIGIT :: distinct u64
|
||||
_WORD :: distinct u128
|
||||
} else {
|
||||
DIGIT :: distinct u32;
|
||||
_WORD :: distinct u64;
|
||||
DIGIT :: distinct u32
|
||||
_WORD :: distinct u64
|
||||
}
|
||||
#assert(size_of(_WORD) == 2 * size_of(DIGIT));
|
||||
|
||||
_DIGIT_TYPE_BITS :: 8 * size_of(DIGIT);
|
||||
_WORD_TYPE_BITS :: 8 * size_of(_WORD);
|
||||
_DIGIT_TYPE_BITS :: 8 * size_of(DIGIT)
|
||||
_WORD_TYPE_BITS :: 8 * size_of(_WORD)
|
||||
|
||||
_DIGIT_BITS :: _DIGIT_TYPE_BITS - 4;
|
||||
_WORD_BITS :: 2 * _DIGIT_BITS;
|
||||
_DIGIT_BITS :: _DIGIT_TYPE_BITS - 4
|
||||
_WORD_BITS :: 2 * _DIGIT_BITS
|
||||
|
||||
_MASK :: (DIGIT(1) << DIGIT(_DIGIT_BITS)) - DIGIT(1);
|
||||
_DIGIT_MAX :: _MASK;
|
||||
_MAX_COMBA :: 1 << (_WORD_TYPE_BITS - (2 * _DIGIT_BITS)) ;
|
||||
_WARRAY :: 1 << ((_WORD_TYPE_BITS - (2 * _DIGIT_BITS)) + 1);
|
||||
_MASK :: (DIGIT(1) << DIGIT(_DIGIT_BITS)) - DIGIT(1)
|
||||
_DIGIT_MAX :: _MASK
|
||||
_MAX_COMBA :: 1 << (_WORD_TYPE_BITS - (2 * _DIGIT_BITS))
|
||||
_WARRAY :: 1 << ((_WORD_TYPE_BITS - (2 * _DIGIT_BITS)) + 1)
|
||||
|
||||
Order :: enum i8 {
|
||||
LSB_First = -1,
|
||||
MSB_First = 1,
|
||||
};
|
||||
}
|
||||
|
||||
Endianness :: enum i8 {
|
||||
Little = -1,
|
||||
|
||||
+90
-90
@@ -47,186 +47,186 @@ MAX_ITERATIONS_ROOT_N,
|
||||
FACTORIAL_MAX_N,
|
||||
FACTORIAL_BINARY_SPLIT_CUTOFF,
|
||||
FACTORIAL_BINARY_SPLIT_MAX_RECURSIONS,
|
||||
);
|
||||
)
|
||||
|
||||
}
|
||||
|
||||
print :: proc(name: string, a: ^Int, base := i8(10), print_name := true, newline := true, print_extra_info := false) {
|
||||
assert_if_nil(a);
|
||||
assert_if_nil(a)
|
||||
|
||||
as, err := itoa(a, base);
|
||||
defer delete(as);
|
||||
as, err := itoa(a, base)
|
||||
defer delete(as)
|
||||
|
||||
cb := internal_count_bits(a);
|
||||
cb := internal_count_bits(a)
|
||||
if print_name {
|
||||
fmt.printf("%v", name);
|
||||
fmt.printf("%v", name)
|
||||
}
|
||||
if err != nil {
|
||||
fmt.printf("%v (error: %v | %v)", name, err, a);
|
||||
fmt.printf("%v (error: %v | %v)", name, err, a)
|
||||
}
|
||||
fmt.printf("%v", as);
|
||||
fmt.printf("%v", as)
|
||||
if print_extra_info {
|
||||
fmt.printf(" (base: %v, bits: %v (digits: %v), flags: %v)", base, cb, a.used, a.flags);
|
||||
fmt.printf(" (base: %v, bits: %v (digits: %v), flags: %v)", base, cb, a.used, a.flags)
|
||||
}
|
||||
if newline {
|
||||
fmt.println();
|
||||
fmt.println()
|
||||
}
|
||||
}
|
||||
|
||||
int_to_byte :: proc(v: ^Int) {
|
||||
err: Error;
|
||||
size: int;
|
||||
print("v: ", v);
|
||||
fmt.println();
|
||||
err: Error
|
||||
size: int
|
||||
print("v: ", v)
|
||||
fmt.println()
|
||||
|
||||
t := &Int{};
|
||||
defer destroy(t);
|
||||
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;
|
||||
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);
|
||||
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);
|
||||
int_from_bytes_big(t, b1)
|
||||
if internal_cmp_mag(t, v) != 0 {
|
||||
print("\tError parsing t: ", t);
|
||||
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);
|
||||
return;
|
||||
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);
|
||||
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 err == nil {
|
||||
int_from_bytes_big_python(t, b2);
|
||||
int_from_bytes_big_python(t, b2)
|
||||
if internal_cmp_mag(t, v) != 0 {
|
||||
print("\tError parsing t: ", t);
|
||||
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);
|
||||
return;
|
||||
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);
|
||||
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)
|
||||
|
||||
int_from_bytes_big(t, b3, true);
|
||||
int_from_bytes_big(t, b3, true)
|
||||
if internal_cmp(t, v) != 0 {
|
||||
print("\tError parsing t: ", t);
|
||||
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);
|
||||
return;
|
||||
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);
|
||||
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);
|
||||
int_from_bytes_big_python(t, b4, true)
|
||||
if internal_cmp(t, v) != 0 {
|
||||
print("\tError parsing t: ", t);
|
||||
print("\tError parsing t: ", t)
|
||||
}
|
||||
}
|
||||
|
||||
int_to_byte_little :: proc(v: ^Int) {
|
||||
err: Error;
|
||||
size: int;
|
||||
print("v: ", v);
|
||||
fmt.println();
|
||||
err: Error
|
||||
size: int
|
||||
print("v: ", v)
|
||||
fmt.println()
|
||||
|
||||
t := &Int{};
|
||||
defer destroy(t);
|
||||
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;
|
||||
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);
|
||||
b1 := make([]u8, size, context.temp_allocator)
|
||||
err = int_to_bytes_little(v, b1)
|
||||
fmt.printf("little: %v | err: %v\n", b1, err)
|
||||
|
||||
int_from_bytes_little(t, b1);
|
||||
int_from_bytes_little(t, b1)
|
||||
if internal_cmp_mag(t, v) != 0 {
|
||||
print("\tError parsing t: ", t);
|
||||
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);
|
||||
return;
|
||||
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);
|
||||
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 err == nil {
|
||||
int_from_bytes_little_python(t, b2);
|
||||
int_from_bytes_little_python(t, b2)
|
||||
if internal_cmp_mag(t, v) != 0 {
|
||||
print("\tError parsing t: ", t);
|
||||
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);
|
||||
return;
|
||||
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);
|
||||
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)
|
||||
|
||||
int_from_bytes_little(t, b3, true);
|
||||
int_from_bytes_little(t, b3, true)
|
||||
if internal_cmp(t, v) != 0 {
|
||||
print("\tError parsing t: ", t);
|
||||
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);
|
||||
return;
|
||||
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);
|
||||
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);
|
||||
int_from_bytes_little_python(t, b4, true)
|
||||
if internal_cmp(t, v) != 0 {
|
||||
print("\tError parsing t: ", t);
|
||||
print("\tError parsing t: ", t)
|
||||
}
|
||||
}
|
||||
|
||||
demo :: proc() {
|
||||
a, b, c, d, e, f := &Int{}, &Int{}, &Int{}, &Int{}, &Int{}, &Int{};
|
||||
defer destroy(a, b, c, d, e, f);
|
||||
a, b, c, d, e, f := &Int{}, &Int{}, &Int{}, &Int{}, &Int{}, &Int{}
|
||||
defer destroy(a, b, c, d, e, f)
|
||||
}
|
||||
|
||||
main :: proc() {
|
||||
ta := mem.Tracking_Allocator{};
|
||||
mem.tracking_allocator_init(&ta, context.allocator);
|
||||
context.allocator = mem.tracking_allocator(&ta);
|
||||
ta := mem.Tracking_Allocator{}
|
||||
mem.tracking_allocator_init(&ta, context.allocator)
|
||||
context.allocator = mem.tracking_allocator(&ta)
|
||||
|
||||
demo();
|
||||
demo()
|
||||
|
||||
print_configation();
|
||||
print_configation()
|
||||
|
||||
print_timings();
|
||||
print_timings()
|
||||
|
||||
if len(ta.allocation_map) > 0 {
|
||||
for _, v in ta.allocation_map {
|
||||
fmt.printf("Leaked %v bytes @ %v\n", v.size, v.location);
|
||||
fmt.printf("Leaked %v bytes @ %v\n", v.size, v.location)
|
||||
}
|
||||
}
|
||||
if len(ta.bad_free_array) > 0 {
|
||||
fmt.println("Bad frees:");
|
||||
fmt.println("Bad frees:")
|
||||
for v in ta.bad_free_array {
|
||||
fmt.println(v);
|
||||
fmt.println(v)
|
||||
}
|
||||
}
|
||||
}
|
||||
+251
-251
@@ -22,10 +22,10 @@ import rnd "core:math/rand"
|
||||
Deallocates the backing memory of one or more `Int`s.
|
||||
*/
|
||||
int_destroy :: proc(integers: ..^Int) {
|
||||
integers := integers;
|
||||
integers := integers
|
||||
|
||||
for a in &integers {
|
||||
assert_if_nil(a);
|
||||
assert_if_nil(a)
|
||||
}
|
||||
#force_inline internal_int_destroy(..integers);
|
||||
}
|
||||
@@ -35,19 +35,19 @@ int_destroy :: proc(integers: ..^Int) {
|
||||
*/
|
||||
int_set_from_integer :: proc(dest: ^Int, src: $T, minimize := false, allocator := context.allocator) -> (err: Error)
|
||||
where intrinsics.type_is_integer(T) {
|
||||
context.allocator = allocator;
|
||||
src := src;
|
||||
context.allocator = allocator
|
||||
src := src
|
||||
|
||||
/*
|
||||
Check that `src` is usable and `dest` isn't immutable.
|
||||
*/
|
||||
assert_if_nil(dest);
|
||||
assert_if_nil(dest)
|
||||
#force_inline internal_error_if_immutable(dest) or_return;
|
||||
|
||||
return #force_inline internal_int_set_from_integer(dest, src, minimize);
|
||||
return #force_inline internal_int_set_from_integer(dest, src, minimize)
|
||||
}
|
||||
|
||||
set :: proc { int_set_from_integer, int_copy, int_atoi, };
|
||||
set :: proc { int_set_from_integer, int_copy, int_atoi, }
|
||||
|
||||
/*
|
||||
Copy one `Int` to another.
|
||||
@@ -61,15 +61,15 @@ int_copy :: proc(dest, src: ^Int, minimize := false, allocator := context.alloca
|
||||
/*
|
||||
Check that `src` is usable and `dest` isn't immutable.
|
||||
*/
|
||||
assert_if_nil(dest, src);
|
||||
context.allocator = allocator;
|
||||
assert_if_nil(dest, src)
|
||||
context.allocator = allocator
|
||||
|
||||
#force_inline internal_clear_if_uninitialized(src) or_return;
|
||||
#force_inline internal_error_if_immutable(dest) or_return;
|
||||
|
||||
return #force_inline internal_int_copy(dest, src, minimize);
|
||||
return #force_inline internal_int_copy(dest, src, minimize)
|
||||
}
|
||||
copy :: proc { int_copy, };
|
||||
copy :: proc { int_copy, }
|
||||
|
||||
/*
|
||||
In normal code, you can also write `a, b = b, a`.
|
||||
@@ -77,10 +77,10 @@ copy :: proc { int_copy, };
|
||||
This helper swaps completely.
|
||||
*/
|
||||
int_swap :: proc(a, b: ^Int) {
|
||||
assert_if_nil(a, b);
|
||||
assert_if_nil(a, b)
|
||||
#force_inline internal_swap(a, b);
|
||||
}
|
||||
swap :: proc { int_swap, };
|
||||
swap :: proc { int_swap, }
|
||||
|
||||
/*
|
||||
Set `dest` to |`src`|.
|
||||
@@ -89,19 +89,19 @@ int_abs :: proc(dest, src: ^Int, allocator := context.allocator) -> (err: Error)
|
||||
/*
|
||||
Check that `src` is usable and `dest` isn't immutable.
|
||||
*/
|
||||
assert_if_nil(dest, src);
|
||||
context.allocator = allocator;
|
||||
assert_if_nil(dest, src)
|
||||
context.allocator = allocator
|
||||
|
||||
#force_inline internal_clear_if_uninitialized(src) or_return;
|
||||
#force_inline internal_error_if_immutable(dest) or_return;
|
||||
|
||||
return #force_inline internal_int_abs(dest, src);
|
||||
return #force_inline internal_int_abs(dest, src)
|
||||
}
|
||||
|
||||
platform_abs :: proc(n: $T) -> T where intrinsics.type_is_integer(T) {
|
||||
return n if n >= 0 else -n;
|
||||
return n if n >= 0 else -n
|
||||
}
|
||||
abs :: proc{ int_abs, platform_abs, };
|
||||
abs :: proc{ int_abs, platform_abs, }
|
||||
|
||||
/*
|
||||
Set `dest` to `-src`.
|
||||
@@ -110,32 +110,32 @@ int_neg :: proc(dest, src: ^Int, allocator := context.allocator) -> (err: Error)
|
||||
/*
|
||||
Check that `src` is usable and `dest` isn't immutable.
|
||||
*/
|
||||
assert_if_nil(dest, src);
|
||||
context.allocator = allocator;
|
||||
assert_if_nil(dest, src)
|
||||
context.allocator = allocator
|
||||
|
||||
#force_inline internal_clear_if_uninitialized(src) or_return;
|
||||
#force_inline internal_error_if_immutable(dest) or_return;
|
||||
|
||||
return #force_inline internal_int_neg(dest, src);
|
||||
return #force_inline internal_int_neg(dest, src)
|
||||
}
|
||||
neg :: proc { int_neg, };
|
||||
neg :: proc { int_neg, }
|
||||
|
||||
/*
|
||||
Helpers to extract values from the `Int`.
|
||||
*/
|
||||
int_bitfield_extract_single :: proc(a: ^Int, offset: int, allocator := context.allocator) -> (bit: _WORD, err: Error) {
|
||||
return #force_inline int_bitfield_extract(a, offset, 1, allocator);
|
||||
return #force_inline int_bitfield_extract(a, offset, 1, allocator)
|
||||
}
|
||||
|
||||
int_bitfield_extract :: proc(a: ^Int, offset, count: int, allocator := context.allocator) -> (res: _WORD, err: Error) {
|
||||
/*
|
||||
Check that `a` is usable.
|
||||
*/
|
||||
assert_if_nil(a);
|
||||
context.allocator = allocator;
|
||||
assert_if_nil(a)
|
||||
context.allocator = allocator
|
||||
|
||||
#force_inline internal_clear_if_uninitialized(a) or_return;
|
||||
return #force_inline internal_int_bitfield_extract(a, offset, count);
|
||||
return #force_inline internal_int_bitfield_extract(a, offset, count)
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -145,21 +145,21 @@ shrink :: proc(a: ^Int, allocator := context.allocator) -> (err: Error) {
|
||||
/*
|
||||
Check that `a` is usable.
|
||||
*/
|
||||
assert_if_nil(a);
|
||||
context.allocator = allocator;
|
||||
assert_if_nil(a)
|
||||
context.allocator = allocator
|
||||
|
||||
#force_inline internal_clear_if_uninitialized(a) or_return;
|
||||
return #force_inline internal_shrink(a);
|
||||
return #force_inline internal_shrink(a)
|
||||
}
|
||||
|
||||
int_grow :: proc(a: ^Int, digits: int, allow_shrink := false, allocator := context.allocator) -> (err: Error) {
|
||||
/*
|
||||
Check that `a` is usable.
|
||||
*/
|
||||
assert_if_nil(a);
|
||||
return #force_inline internal_int_grow(a, digits, allow_shrink, allocator);
|
||||
assert_if_nil(a)
|
||||
return #force_inline internal_int_grow(a, digits, allow_shrink, allocator)
|
||||
}
|
||||
grow :: proc { int_grow, };
|
||||
grow :: proc { int_grow, }
|
||||
|
||||
/*
|
||||
Clear `Int` and resize it to the default size.
|
||||
@@ -168,11 +168,11 @@ int_clear :: proc(a: ^Int, minimize := false, allocator := context.allocator) ->
|
||||
/*
|
||||
Check that `a` is usable.
|
||||
*/
|
||||
assert_if_nil(a);
|
||||
return #force_inline internal_int_clear(a, minimize, allocator);
|
||||
assert_if_nil(a)
|
||||
return #force_inline internal_int_clear(a, minimize, allocator)
|
||||
}
|
||||
clear :: proc { int_clear, };
|
||||
zero :: clear;
|
||||
clear :: proc { int_clear, }
|
||||
zero :: clear
|
||||
|
||||
/*
|
||||
Set the `Int` to 1 and optionally shrink it to the minimum backing size.
|
||||
@@ -181,10 +181,10 @@ int_one :: proc(a: ^Int, minimize := false, allocator := context.allocator) -> (
|
||||
/*
|
||||
Check that `a` is usable.
|
||||
*/
|
||||
assert_if_nil(a);
|
||||
return #force_inline internal_one(a, minimize, allocator);
|
||||
assert_if_nil(a)
|
||||
return #force_inline internal_one(a, minimize, allocator)
|
||||
}
|
||||
one :: proc { int_one, };
|
||||
one :: proc { int_one, }
|
||||
|
||||
/*
|
||||
Set the `Int` to -1 and optionally shrink it to the minimum backing size.
|
||||
@@ -193,10 +193,10 @@ int_minus_one :: proc(a: ^Int, minimize := false, allocator := context.allocator
|
||||
/*
|
||||
Check that `a` is usable.
|
||||
*/
|
||||
assert_if_nil(a);
|
||||
return #force_inline internal_minus_one(a, minimize, allocator);
|
||||
assert_if_nil(a)
|
||||
return #force_inline internal_minus_one(a, minimize, allocator)
|
||||
}
|
||||
minus_one :: proc { int_minus_one, };
|
||||
minus_one :: proc { int_minus_one, }
|
||||
|
||||
/*
|
||||
Set the `Int` to Inf and optionally shrink it to the minimum backing size.
|
||||
@@ -205,10 +205,10 @@ int_inf :: proc(a: ^Int, minimize := false, allocator := context.allocator) -> (
|
||||
/*
|
||||
Check that `a` is usable.
|
||||
*/
|
||||
assert_if_nil(a);
|
||||
return #force_inline internal_inf(a, minimize, allocator);
|
||||
assert_if_nil(a)
|
||||
return #force_inline internal_inf(a, minimize, allocator)
|
||||
}
|
||||
inf :: proc { int_inf, };
|
||||
inf :: proc { int_inf, }
|
||||
|
||||
/*
|
||||
Set the `Int` to -Inf and optionally shrink it to the minimum backing size.
|
||||
@@ -217,10 +217,10 @@ int_minus_inf :: proc(a: ^Int, minimize := false, allocator := context.allocator
|
||||
/*
|
||||
Check that `a` is usable.
|
||||
*/
|
||||
assert_if_nil(a);
|
||||
return #force_inline internal_minus_inf(a, minimize, allocator);
|
||||
assert_if_nil(a)
|
||||
return #force_inline internal_minus_inf(a, minimize, allocator)
|
||||
}
|
||||
minus_inf :: proc { int_inf, };
|
||||
minus_inf :: proc { int_inf, }
|
||||
|
||||
/*
|
||||
Set the `Int` to NaN and optionally shrink it to the minimum backing size.
|
||||
@@ -229,72 +229,72 @@ int_nan :: proc(a: ^Int, minimize := false, allocator := context.allocator) -> (
|
||||
/*
|
||||
Check that `a` is usable.
|
||||
*/
|
||||
assert_if_nil(a);
|
||||
return #force_inline internal_nan(a, minimize, allocator);
|
||||
assert_if_nil(a)
|
||||
return #force_inline internal_nan(a, minimize, allocator)
|
||||
}
|
||||
nan :: proc { int_nan, };
|
||||
nan :: proc { int_nan, }
|
||||
|
||||
power_of_two :: proc(a: ^Int, power: int, allocator := context.allocator) -> (err: Error) {
|
||||
/*
|
||||
Check that `a` is usable.
|
||||
*/
|
||||
assert_if_nil(a);
|
||||
return #force_inline internal_int_power_of_two(a, power, allocator);
|
||||
assert_if_nil(a)
|
||||
return #force_inline internal_int_power_of_two(a, power, allocator)
|
||||
}
|
||||
|
||||
int_get_u128 :: proc(a: ^Int, allocator := context.allocator) -> (res: u128, err: Error) {
|
||||
/*
|
||||
Check that `a` is usable.
|
||||
*/
|
||||
assert_if_nil(a);
|
||||
return int_get(a, u128, allocator);
|
||||
assert_if_nil(a)
|
||||
return int_get(a, u128, allocator)
|
||||
}
|
||||
get_u128 :: proc { int_get_u128, };
|
||||
get_u128 :: proc { int_get_u128, }
|
||||
|
||||
int_get_i128 :: proc(a: ^Int, allocator := context.allocator) -> (res: i128, err: Error) {
|
||||
/*
|
||||
Check that `a` is usable.
|
||||
*/
|
||||
assert_if_nil(a);
|
||||
return int_get(a, i128, allocator);
|
||||
assert_if_nil(a)
|
||||
return int_get(a, i128, allocator)
|
||||
}
|
||||
get_i128 :: proc { int_get_i128, };
|
||||
get_i128 :: proc { int_get_i128, }
|
||||
|
||||
int_get_u64 :: proc(a: ^Int, allocator := context.allocator) -> (res: u64, err: Error) {
|
||||
/*
|
||||
Check that `a` is usable.
|
||||
*/
|
||||
assert_if_nil(a);
|
||||
return int_get(a, u64, allocator);
|
||||
assert_if_nil(a)
|
||||
return int_get(a, u64, allocator)
|
||||
}
|
||||
get_u64 :: proc { int_get_u64, };
|
||||
get_u64 :: proc { int_get_u64, }
|
||||
|
||||
int_get_i64 :: proc(a: ^Int, allocator := context.allocator) -> (res: i64, err: Error) {
|
||||
/*
|
||||
Check that `a` is usable.
|
||||
*/
|
||||
assert_if_nil(a);
|
||||
return int_get(a, i64, allocator);
|
||||
assert_if_nil(a)
|
||||
return int_get(a, i64, allocator)
|
||||
}
|
||||
get_i64 :: proc { int_get_i64, };
|
||||
get_i64 :: proc { int_get_i64, }
|
||||
|
||||
int_get_u32 :: proc(a: ^Int, allocator := context.allocator) -> (res: u32, err: Error) {
|
||||
/*
|
||||
Check that `a` is usable.
|
||||
*/
|
||||
assert_if_nil(a);
|
||||
return int_get(a, u32, allocator);
|
||||
assert_if_nil(a)
|
||||
return int_get(a, u32, allocator)
|
||||
}
|
||||
get_u32 :: proc { int_get_u32, };
|
||||
get_u32 :: proc { int_get_u32, }
|
||||
|
||||
int_get_i32 :: proc(a: ^Int, allocator := context.allocator) -> (res: i32, err: Error) {
|
||||
/*
|
||||
Check that `a` is usable.
|
||||
*/
|
||||
assert_if_nil(a);
|
||||
return int_get(a, i32, allocator);
|
||||
assert_if_nil(a)
|
||||
return int_get(a, i32, allocator)
|
||||
}
|
||||
get_i32 :: proc { int_get_i32, };
|
||||
get_i32 :: proc { int_get_i32, }
|
||||
|
||||
/*
|
||||
TODO: Think about using `count_bits` to check if the value could be returned completely,
|
||||
@@ -304,19 +304,19 @@ int_get :: proc(a: ^Int, $T: typeid, allocator := context.allocator) -> (res: T,
|
||||
/*
|
||||
Check that `a` is usable.
|
||||
*/
|
||||
assert_if_nil(a);
|
||||
assert_if_nil(a)
|
||||
#force_inline internal_clear_if_uninitialized(a, allocator) or_return;
|
||||
return #force_inline internal_int_get(a, T);
|
||||
return #force_inline internal_int_get(a, T)
|
||||
}
|
||||
get :: proc { int_get, };
|
||||
get :: proc { int_get, }
|
||||
|
||||
int_get_float :: proc(a: ^Int, allocator := context.allocator) -> (res: f64, err: Error) {
|
||||
/*
|
||||
Check that `a` is usable.
|
||||
*/
|
||||
assert_if_nil(a);
|
||||
assert_if_nil(a)
|
||||
#force_inline internal_clear_if_uninitialized(a, allocator) or_return;
|
||||
return #force_inline internal_int_get_float(a);
|
||||
return #force_inline internal_int_get_float(a)
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -326,9 +326,9 @@ count_bits :: proc(a: ^Int, allocator := context.allocator) -> (count: int, err:
|
||||
/*
|
||||
Check that `a` is usable.
|
||||
*/
|
||||
assert_if_nil(a);
|
||||
assert_if_nil(a)
|
||||
#force_inline internal_clear_if_uninitialized(a, allocator) or_return;
|
||||
return #force_inline internal_count_bits(a), nil;
|
||||
return #force_inline internal_count_bits(a), nil
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -339,109 +339,109 @@ int_count_lsb :: proc(a: ^Int, allocator := context.allocator) -> (count: int, e
|
||||
/*
|
||||
Check that `a` is usable.
|
||||
*/
|
||||
assert_if_nil(a);
|
||||
assert_if_nil(a)
|
||||
#force_inline internal_clear_if_uninitialized(a, allocator) or_return;
|
||||
return #force_inline internal_int_count_lsb(a);
|
||||
return #force_inline internal_int_count_lsb(a)
|
||||
}
|
||||
|
||||
platform_count_lsb :: #force_inline proc(a: $T) -> (count: int)
|
||||
where intrinsics.type_is_integer(T) && intrinsics.type_is_unsigned(T) {
|
||||
return int(intrinsics.count_trailing_zeros(a)) if a > 0 else 0;
|
||||
return int(intrinsics.count_trailing_zeros(a)) if a > 0 else 0
|
||||
}
|
||||
|
||||
count_lsb :: proc { int_count_lsb, platform_count_lsb, };
|
||||
count_lsb :: proc { int_count_lsb, platform_count_lsb, }
|
||||
|
||||
int_random_digit :: proc(r: ^rnd.Rand = nil) -> (res: DIGIT) {
|
||||
when _DIGIT_BITS == 60 { // DIGIT = u64
|
||||
return DIGIT(rnd.uint64(r)) & _MASK;
|
||||
return DIGIT(rnd.uint64(r)) & _MASK
|
||||
} else when _DIGIT_BITS == 28 { // DIGIT = u32
|
||||
return DIGIT(rnd.uint32(r)) & _MASK;
|
||||
return DIGIT(rnd.uint32(r)) & _MASK
|
||||
} else {
|
||||
panic("Unsupported DIGIT size.");
|
||||
panic("Unsupported DIGIT size.")
|
||||
}
|
||||
|
||||
return 0; // We shouldn't get here.
|
||||
return 0 // We shouldn't get here.
|
||||
}
|
||||
|
||||
int_rand :: proc(dest: ^Int, bits: int, r: ^rnd.Rand = nil, allocator := context.allocator) -> (err: Error) {
|
||||
/*
|
||||
Check that `a` is usable.
|
||||
*/
|
||||
assert_if_nil(dest);
|
||||
return #force_inline internal_int_rand(dest, bits, r, allocator);
|
||||
assert_if_nil(dest)
|
||||
return #force_inline internal_int_rand(dest, bits, r, allocator)
|
||||
|
||||
}
|
||||
rand :: proc { int_rand, };
|
||||
rand :: proc { int_rand, }
|
||||
|
||||
/*
|
||||
Internal helpers.
|
||||
*/
|
||||
assert_initialized :: proc(a: ^Int, loc := #caller_location) {
|
||||
assert_if_nil(a);
|
||||
assert(is_initialized(a), "`Int` was not properly initialized.", loc);
|
||||
assert_if_nil(a)
|
||||
assert(is_initialized(a), "`Int` was not properly initialized.", loc)
|
||||
}
|
||||
|
||||
zero_unused :: proc(dest: ^Int, old_used := -1) {
|
||||
assert_if_nil(dest);
|
||||
assert_if_nil(dest)
|
||||
if ! #force_inline is_initialized(dest) { return; }
|
||||
|
||||
#force_inline internal_zero_unused(dest, old_used);
|
||||
}
|
||||
|
||||
clear_if_uninitialized_single :: proc(arg: ^Int, allocator := context.allocator) -> (err: Error) {
|
||||
assert_if_nil(arg);
|
||||
return #force_inline internal_clear_if_uninitialized_single(arg, allocator);
|
||||
assert_if_nil(arg)
|
||||
return #force_inline internal_clear_if_uninitialized_single(arg, allocator)
|
||||
}
|
||||
|
||||
clear_if_uninitialized_multi :: proc(args: ..^Int, allocator := context.allocator) -> (err: Error) {
|
||||
args := args;
|
||||
assert_if_nil(..args);
|
||||
args := args
|
||||
assert_if_nil(..args)
|
||||
|
||||
for i in &args {
|
||||
#force_inline internal_clear_if_uninitialized_single(i, allocator) or_return;
|
||||
}
|
||||
return err;
|
||||
return err
|
||||
}
|
||||
clear_if_uninitialized :: proc {clear_if_uninitialized_single, clear_if_uninitialized_multi, };
|
||||
clear_if_uninitialized :: proc {clear_if_uninitialized_single, clear_if_uninitialized_multi, }
|
||||
|
||||
error_if_immutable_single :: proc(arg: ^Int) -> (err: Error) {
|
||||
if arg != nil && .Immutable in arg.flags { return .Assignment_To_Immutable; }
|
||||
return nil;
|
||||
return nil
|
||||
}
|
||||
|
||||
error_if_immutable_multi :: proc(args: ..^Int) -> (err: Error) {
|
||||
for i in args {
|
||||
if i != nil && .Immutable in i.flags { return .Assignment_To_Immutable; }
|
||||
}
|
||||
return nil;
|
||||
return nil
|
||||
}
|
||||
error_if_immutable :: proc {error_if_immutable_single, error_if_immutable_multi, };
|
||||
error_if_immutable :: proc {error_if_immutable_single, error_if_immutable_multi, }
|
||||
|
||||
/*
|
||||
Allocates several `Int`s at once.
|
||||
*/
|
||||
int_init_multi :: proc(integers: ..^Int, allocator := context.allocator) -> (err: Error) {
|
||||
assert_if_nil(..integers);
|
||||
assert_if_nil(..integers)
|
||||
|
||||
integers := integers;
|
||||
integers := integers
|
||||
for a in &integers {
|
||||
#force_inline internal_clear(a, true, allocator) or_return;
|
||||
}
|
||||
return nil;
|
||||
return nil
|
||||
}
|
||||
|
||||
init_multi :: proc { int_init_multi, };
|
||||
init_multi :: proc { int_init_multi, }
|
||||
|
||||
copy_digits :: proc(dest, src: ^Int, digits: int, offset := int(0), allocator := context.allocator) -> (err: Error) {
|
||||
context.allocator = allocator;
|
||||
context.allocator = allocator
|
||||
|
||||
/*
|
||||
Check that `src` is usable and `dest` isn't immutable.
|
||||
*/
|
||||
assert_if_nil(dest, src);
|
||||
assert_if_nil(dest, src)
|
||||
#force_inline internal_clear_if_uninitialized(src) or_return;
|
||||
|
||||
return #force_inline internal_copy_digits(dest, src, digits, offset);
|
||||
return #force_inline internal_copy_digits(dest, src, digits, offset)
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -451,17 +451,17 @@ copy_digits :: proc(dest, src: ^Int, digits: int, offset := int(0), allocator :=
|
||||
Typically very fast. Also fixes the sign if there are no more leading digits.
|
||||
*/
|
||||
clamp :: proc(a: ^Int, allocator := context.allocator) -> (err: Error) {
|
||||
assert_if_nil(a);
|
||||
assert_if_nil(a)
|
||||
#force_inline internal_clear_if_uninitialized(a, allocator) or_return;
|
||||
|
||||
for a.used > 0 && a.digit[a.used - 1] == 0 {
|
||||
a.used -= 1;
|
||||
a.used -= 1
|
||||
}
|
||||
|
||||
if z, _ := is_zero(a); z {
|
||||
a.sign = .Zero_or_Positive;
|
||||
a.sign = .Zero_or_Positive
|
||||
}
|
||||
return nil;
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
@@ -469,15 +469,15 @@ clamp :: proc(a: ^Int, allocator := context.allocator) -> (err: Error) {
|
||||
Size binary representation
|
||||
*/
|
||||
int_to_bytes_size :: proc(a: ^Int, signed := false, allocator := context.allocator) -> (size_in_bytes: int, err: Error) {
|
||||
assert_if_nil(a);
|
||||
assert_if_nil(a)
|
||||
#force_inline internal_clear_if_uninitialized(a, allocator) or_return;
|
||||
|
||||
size_in_bits := internal_count_bits(a);
|
||||
size_in_bits := internal_count_bits(a)
|
||||
|
||||
size_in_bytes = (size_in_bits / 8);
|
||||
size_in_bytes += 0 if size_in_bits % 8 == 0 else 1;
|
||||
size_in_bytes += 1 if signed else 0;
|
||||
return;
|
||||
size_in_bytes = (size_in_bits / 8)
|
||||
size_in_bytes += 0 if size_in_bits % 8 == 0 else 1
|
||||
size_in_bytes += 1 if signed else 0
|
||||
return
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -485,22 +485,22 @@ int_to_bytes_size :: proc(a: ^Int, signed := false, allocator := context.allocat
|
||||
If `a` is negative and we ask for the default unsigned representation, we return abs(a).
|
||||
*/
|
||||
int_to_bytes_little :: proc(a: ^Int, buf: []u8, signed := false, allocator := context.allocator) -> (err: Error) {
|
||||
assert_if_nil(a);
|
||||
assert_if_nil(a)
|
||||
|
||||
size_in_bytes := int_to_bytes_size(a, signed, allocator) or_return;
|
||||
l := len(buf);
|
||||
size_in_bytes := int_to_bytes_size(a, signed, allocator) or_return
|
||||
l := len(buf)
|
||||
if size_in_bytes > l { return .Buffer_Overflow; }
|
||||
|
||||
size_in_bits := internal_count_bits(a);
|
||||
i := 0;
|
||||
size_in_bits := internal_count_bits(a)
|
||||
i := 0
|
||||
if signed {
|
||||
buf[l - 1] = 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);
|
||||
buf[i] = u8(bits & 255); i += 1;
|
||||
bits, _ := internal_int_bitfield_extract(a, offset, 8)
|
||||
buf[i] = u8(bits & 255); i += 1
|
||||
}
|
||||
return;
|
||||
return
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -508,23 +508,23 @@ int_to_bytes_little :: proc(a: ^Int, buf: []u8, signed := false, allocator := co
|
||||
If `a` is negative and we ask for the default unsigned representation, we return abs(a).
|
||||
*/
|
||||
int_to_bytes_big :: proc(a: ^Int, buf: []u8, signed := false, allocator := context.allocator) -> (err: Error) {
|
||||
assert_if_nil(a);
|
||||
assert_if_nil(a)
|
||||
|
||||
size_in_bytes := int_to_bytes_size(a, signed, allocator) or_return;
|
||||
l := len(buf);
|
||||
size_in_bytes := int_to_bytes_size(a, signed, allocator) or_return
|
||||
l := len(buf)
|
||||
if size_in_bytes > l { return .Buffer_Overflow; }
|
||||
|
||||
size_in_bits := internal_count_bits(a);
|
||||
i := l - 1;
|
||||
size_in_bits := internal_count_bits(a)
|
||||
i := l - 1
|
||||
|
||||
if signed {
|
||||
buf[0] = 1 if a.sign == .Negative else 0;
|
||||
buf[0] = 1 if a.sign == .Negative else 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;
|
||||
bits, _ := internal_int_bitfield_extract(a, offset, 8)
|
||||
buf[i] = u8(bits & 255); i -= 1
|
||||
}
|
||||
return;
|
||||
return
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -532,35 +532,35 @@ int_to_bytes_big :: proc(a: ^Int, buf: []u8, signed := false, allocator := conte
|
||||
If `a` is negative when asking for an unsigned number, we return an error like Python does.
|
||||
*/
|
||||
int_to_bytes_little_python :: proc(a: ^Int, buf: []u8, signed := false, allocator := context.allocator) -> (err: Error) {
|
||||
assert_if_nil(a);
|
||||
assert_if_nil(a)
|
||||
|
||||
if !signed && a.sign == .Negative { return .Invalid_Argument; }
|
||||
|
||||
l := len(buf);
|
||||
size_in_bytes := int_to_bytes_size(a, signed, allocator) or_return;
|
||||
l := len(buf)
|
||||
size_in_bytes := int_to_bytes_size(a, signed, allocator) or_return
|
||||
if size_in_bytes > l { return .Buffer_Overflow; }
|
||||
|
||||
if a.sign == .Negative {
|
||||
t := &Int{};
|
||||
defer destroy(t);
|
||||
internal_complement(t, a, allocator) or_return;
|
||||
t := &Int{}
|
||||
defer destroy(t)
|
||||
internal_complement(t, a, allocator) or_return
|
||||
|
||||
size_in_bits := internal_count_bits(t);
|
||||
i := 0;
|
||||
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;
|
||||
bits, _ := internal_int_bitfield_extract(t, offset, 8)
|
||||
buf[i] = 255 - u8(bits & 255); i += 1
|
||||
}
|
||||
buf[l-1] = 255;
|
||||
buf[l-1] = 255
|
||||
} else {
|
||||
size_in_bits := internal_count_bits(a);
|
||||
i := 0;
|
||||
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;
|
||||
bits, _ := internal_int_bitfield_extract(a, offset, 8)
|
||||
buf[i] = u8(bits & 255); i += 1
|
||||
}
|
||||
}
|
||||
return;
|
||||
return
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -568,29 +568,29 @@ int_to_bytes_little_python :: proc(a: ^Int, buf: []u8, signed := false, allocato
|
||||
If `a` is negative when asking for an unsigned number, we return an error like Python does.
|
||||
*/
|
||||
int_to_bytes_big_python :: proc(a: ^Int, buf: []u8, signed := false, allocator := context.allocator) -> (err: Error) {
|
||||
assert_if_nil(a);
|
||||
assert_if_nil(a)
|
||||
|
||||
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);
|
||||
size_in_bytes := int_to_bytes_size(a, signed, allocator) or_return;
|
||||
l := len(buf)
|
||||
size_in_bytes := int_to_bytes_size(a, signed, allocator) or_return
|
||||
if size_in_bytes > l { return .Buffer_Overflow; }
|
||||
|
||||
t := &Int{};
|
||||
defer destroy(t);
|
||||
t := &Int{}
|
||||
defer destroy(t)
|
||||
|
||||
internal_complement(t, a, allocator) or_return;
|
||||
internal_complement(t, a, allocator) or_return
|
||||
|
||||
size_in_bits := internal_count_bits(t);
|
||||
i := l - 1;
|
||||
size_in_bits := internal_count_bits(t)
|
||||
i := l - 1
|
||||
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;
|
||||
bits, _ := internal_int_bitfield_extract(t, offset, 8)
|
||||
buf[i] = 255 - u8(bits & 255); i -= 1
|
||||
}
|
||||
buf[0] = 255;
|
||||
buf[0] = 255
|
||||
|
||||
return;
|
||||
return
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -598,36 +598,36 @@ int_to_bytes_big_python :: proc(a: ^Int, buf: []u8, signed := false, allocator :
|
||||
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);
|
||||
assert_if_nil(a)
|
||||
buf := buf
|
||||
l := len(buf)
|
||||
if l == 0 { return .Invalid_Argument; }
|
||||
|
||||
sign: Sign;
|
||||
size_in_bits := l * 8;
|
||||
sign: Sign
|
||||
size_in_bits := l * 8
|
||||
if signed {
|
||||
/*
|
||||
First byte denotes the sign.
|
||||
*/
|
||||
size_in_bits -= 8;
|
||||
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;
|
||||
internal_zero(a, false, allocator) or_return;
|
||||
internal_grow(a, size_in_digits, false, allocator) or_return;
|
||||
size_in_digits := (size_in_bits + _DIGIT_BITS - 1) / _DIGIT_BITS
|
||||
size_in_digits += 0 if size_in_bits % 8 == 0 else 1
|
||||
internal_zero(a, false, allocator) or_return
|
||||
internal_grow(a, size_in_digits, false, allocator) or_return
|
||||
|
||||
if signed {
|
||||
sign = .Zero_or_Positive if buf[0] == 0 else .Negative;
|
||||
buf = buf[1:];
|
||||
sign = .Zero_or_Positive if buf[0] == 0 else .Negative
|
||||
buf = buf[1:]
|
||||
}
|
||||
|
||||
for v in buf {
|
||||
internal_shl(a, a, 8) or_return;
|
||||
a.digit[0] |= DIGIT(v);
|
||||
internal_shl(a, a, 8) or_return
|
||||
a.digit[0] |= DIGIT(v)
|
||||
}
|
||||
a.sign = sign;
|
||||
a.used = size_in_digits;
|
||||
return internal_clamp(a);
|
||||
a.sign = sign
|
||||
a.used = size_in_digits
|
||||
return internal_clamp(a)
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -635,45 +635,45 @@ int_from_bytes_big :: proc(a: ^Int, buf: []u8, signed := false, allocator := con
|
||||
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);
|
||||
assert_if_nil(a)
|
||||
buf := buf
|
||||
l := len(buf)
|
||||
if l == 0 { return .Invalid_Argument; }
|
||||
|
||||
sign: Sign;
|
||||
size_in_bits := l * 8;
|
||||
sign: Sign
|
||||
size_in_bits := l * 8
|
||||
if signed {
|
||||
/*
|
||||
First byte denotes the sign.
|
||||
*/
|
||||
size_in_bits -= 8;
|
||||
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;
|
||||
internal_zero(a, false, allocator) or_return;
|
||||
internal_grow(a, size_in_digits, false, allocator) or_return;
|
||||
size_in_digits := (size_in_bits + _DIGIT_BITS - 1) / _DIGIT_BITS
|
||||
size_in_digits += 0 if size_in_bits % 8 == 0 else 1
|
||||
internal_zero(a, false, allocator) or_return
|
||||
internal_grow(a, size_in_digits, false, allocator) or_return
|
||||
|
||||
if signed {
|
||||
sign = .Zero_or_Positive if buf[0] == 0 else .Negative;
|
||||
buf = buf[1:];
|
||||
sign = .Zero_or_Positive if buf[0] == 0 else .Negative
|
||||
buf = buf[1:]
|
||||
}
|
||||
|
||||
for v in buf {
|
||||
internal_shl(a, a, 8) or_return;
|
||||
internal_shl(a, a, 8) or_return
|
||||
if signed && sign == .Negative {
|
||||
a.digit[0] |= DIGIT(255 - v);
|
||||
a.digit[0] |= DIGIT(255 - v)
|
||||
} else {
|
||||
a.digit[0] |= DIGIT(v);
|
||||
a.digit[0] |= DIGIT(v)
|
||||
}
|
||||
}
|
||||
a.sign = sign;
|
||||
a.used = size_in_digits;
|
||||
internal_clamp(a) or_return;
|
||||
a.sign = sign
|
||||
a.used = size_in_digits
|
||||
internal_clamp(a) or_return
|
||||
|
||||
if signed && sign == .Negative {
|
||||
return internal_sub(a, a, 1);
|
||||
return internal_sub(a, a, 1)
|
||||
}
|
||||
return nil;
|
||||
return nil
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -681,37 +681,37 @@ int_from_bytes_big_python :: proc(a: ^Int, buf: []u8, signed := false, allocator
|
||||
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);
|
||||
assert_if_nil(a)
|
||||
buf := buf
|
||||
l := len(buf)
|
||||
if l == 0 { return .Invalid_Argument; }
|
||||
|
||||
sign: Sign;
|
||||
size_in_bits := l * 8;
|
||||
sign: Sign
|
||||
size_in_bits := l * 8
|
||||
if signed {
|
||||
/*
|
||||
First byte denotes the sign.
|
||||
*/
|
||||
size_in_bits -= 8;
|
||||
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;
|
||||
internal_zero(a, false, allocator) or_return;
|
||||
internal_grow(a, size_in_digits, false, allocator) or_return;
|
||||
size_in_digits := (size_in_bits + _DIGIT_BITS - 1) / _DIGIT_BITS
|
||||
size_in_digits += 0 if size_in_bits % 8 == 0 else 1
|
||||
internal_zero(a, false, allocator) or_return
|
||||
internal_grow(a, size_in_digits, false, allocator) or_return
|
||||
|
||||
if signed {
|
||||
sign = .Zero_or_Positive if buf[l-1] == 0 else .Negative;
|
||||
buf = buf[:l-1];
|
||||
l -= 1;
|
||||
sign = .Zero_or_Positive if buf[l-1] == 0 else .Negative
|
||||
buf = buf[:l-1]
|
||||
l -= 1
|
||||
}
|
||||
|
||||
for _, i in buf {
|
||||
internal_shl(a, a, 8) or_return;
|
||||
a.digit[0] |= DIGIT(buf[l-i-1]);
|
||||
internal_shl(a, a, 8) or_return
|
||||
a.digit[0] |= DIGIT(buf[l-i-1])
|
||||
}
|
||||
a.sign = sign;
|
||||
a.used = size_in_digits;
|
||||
return internal_clamp(a);
|
||||
a.sign = sign
|
||||
a.used = size_in_digits
|
||||
return internal_clamp(a)
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -719,67 +719,67 @@ int_from_bytes_little :: proc(a: ^Int, buf: []u8, signed := false, allocator :=
|
||||
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);
|
||||
assert_if_nil(a)
|
||||
buf := buf
|
||||
l := len(buf)
|
||||
if l == 0 { return .Invalid_Argument; }
|
||||
|
||||
sign: Sign;
|
||||
size_in_bits := l * 8;
|
||||
sign: Sign
|
||||
size_in_bits := l * 8
|
||||
if signed {
|
||||
/*
|
||||
First byte denotes the sign.
|
||||
*/
|
||||
size_in_bits -= 8;
|
||||
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;
|
||||
internal_zero(a, false, allocator) or_return;
|
||||
internal_grow(a, size_in_digits, false, allocator) or_return;
|
||||
size_in_digits := (size_in_bits + _DIGIT_BITS - 1) / _DIGIT_BITS
|
||||
size_in_digits += 0 if size_in_bits % 8 == 0 else 1
|
||||
internal_zero(a, false, allocator) or_return
|
||||
internal_grow(a, size_in_digits, false, allocator) or_return
|
||||
|
||||
if signed {
|
||||
sign = .Zero_or_Positive if buf[l-1] == 0 else .Negative;
|
||||
buf = buf[:l-1];
|
||||
l -= 1;
|
||||
sign = .Zero_or_Positive if buf[l-1] == 0 else .Negative
|
||||
buf = buf[:l-1]
|
||||
l -= 1
|
||||
}
|
||||
|
||||
for _, i in buf {
|
||||
internal_shl(a, a, 8) or_return;
|
||||
internal_shl(a, a, 8) or_return
|
||||
if signed && sign == .Negative {
|
||||
a.digit[0] |= DIGIT(255 - buf[l-i-1]);
|
||||
a.digit[0] |= DIGIT(255 - buf[l-i-1])
|
||||
} else {
|
||||
a.digit[0] |= DIGIT(buf[l-i-1]);
|
||||
a.digit[0] |= DIGIT(buf[l-i-1])
|
||||
}
|
||||
}
|
||||
a.sign = sign;
|
||||
a.used = size_in_digits;
|
||||
internal_clamp(a) or_return;
|
||||
a.sign = sign
|
||||
a.used = size_in_digits
|
||||
internal_clamp(a) or_return
|
||||
|
||||
if signed && sign == .Negative {
|
||||
return internal_sub(a, a, 1);
|
||||
return internal_sub(a, a, 1)
|
||||
}
|
||||
return nil;
|
||||
return nil
|
||||
}
|
||||
|
||||
/*
|
||||
Initialize constants.
|
||||
*/
|
||||
INT_ONE, INT_ZERO, INT_MINUS_ONE, INT_INF, INT_MINUS_INF, INT_NAN := &Int{}, &Int{}, &Int{}, &Int{}, &Int{}, &Int{};
|
||||
INT_ONE, INT_ZERO, INT_MINUS_ONE, INT_INF, INT_MINUS_INF, INT_NAN := &Int{}, &Int{}, &Int{}, &Int{}, &Int{}, &Int{}
|
||||
|
||||
initialize_constants :: proc() -> (res: int) {
|
||||
internal_set( INT_ZERO, 0); INT_ZERO.flags = {.Immutable};
|
||||
internal_set( INT_ONE, 1); INT_ONE.flags = {.Immutable};
|
||||
internal_set(INT_MINUS_ONE, -1); INT_MINUS_ONE.flags = {.Immutable};
|
||||
internal_set( INT_ZERO, 0); INT_ZERO.flags = {.Immutable}
|
||||
internal_set( INT_ONE, 1); INT_ONE.flags = {.Immutable}
|
||||
internal_set(INT_MINUS_ONE, -1); INT_MINUS_ONE.flags = {.Immutable}
|
||||
|
||||
/*
|
||||
We set these special values to -1 or 1 so they don't get mistake for zero accidentally.
|
||||
This allows for shortcut tests of is_zero as .used == 0.
|
||||
*/
|
||||
internal_set( INT_NAN, 1); INT_NAN.flags = {.Immutable, .NaN};
|
||||
internal_set( INT_INF, 1); INT_INF.flags = {.Immutable, .Inf};
|
||||
internal_set( INT_INF, -1); INT_MINUS_INF.flags = {.Immutable, .Inf};
|
||||
internal_set( INT_NAN, 1); INT_NAN.flags = {.Immutable, .NaN}
|
||||
internal_set( INT_INF, 1); INT_INF.flags = {.Immutable, .Inf}
|
||||
internal_set( INT_INF, -1); INT_MINUS_INF.flags = {.Immutable, .Inf}
|
||||
|
||||
return _DEFAULT_MUL_KARATSUBA_CUTOFF;
|
||||
return _DEFAULT_MUL_KARATSUBA_CUTOFF
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -787,14 +787,14 @@ initialize_constants :: proc() -> (res: int) {
|
||||
Optional for an EXE, as this would be called at the very end of a process.
|
||||
*/
|
||||
destroy_constants :: proc() {
|
||||
internal_destroy(INT_ONE, INT_ZERO, INT_MINUS_ONE, INT_INF, INT_MINUS_INF, INT_NAN);
|
||||
internal_destroy(INT_ONE, INT_ZERO, INT_MINUS_ONE, INT_INF, INT_MINUS_INF, INT_NAN)
|
||||
}
|
||||
|
||||
|
||||
assert_if_nil :: #force_inline proc(integers: ..^Int, loc := #caller_location) {
|
||||
integers := integers;
|
||||
integers := integers
|
||||
|
||||
for i in &integers {
|
||||
assert(i != nil, "(nil)", loc);
|
||||
assert(i != nil, "(nil)", loc)
|
||||
}
|
||||
}
|
||||
|
||||
+719
-719
File diff suppressed because it is too large
Load Diff
+45
-45
@@ -22,37 +22,37 @@ package math_big
|
||||
2's complement `and`, returns `dest = a & b;`
|
||||
*/
|
||||
int_and :: proc(dest, a, b: ^Int, allocator := context.allocator) -> (err: Error) {
|
||||
assert_if_nil(dest, a, b);
|
||||
context.allocator = allocator;
|
||||
assert_if_nil(dest, a, b)
|
||||
context.allocator = allocator
|
||||
|
||||
internal_clear_if_uninitialized(a, b) or_return;
|
||||
return #force_inline internal_int_and(dest, a, b);
|
||||
internal_clear_if_uninitialized(a, b) or_return
|
||||
return #force_inline internal_int_and(dest, a, b)
|
||||
}
|
||||
and :: proc { int_and, };
|
||||
and :: proc { int_and, }
|
||||
|
||||
/*
|
||||
2's complement `or`, returns `dest = a | b;`
|
||||
*/
|
||||
int_or :: proc(dest, a, b: ^Int, allocator := context.allocator) -> (err: Error) {
|
||||
assert_if_nil(dest, a, b);
|
||||
context.allocator = allocator;
|
||||
assert_if_nil(dest, a, b)
|
||||
context.allocator = allocator
|
||||
|
||||
internal_clear_if_uninitialized(a, b) or_return;
|
||||
return #force_inline internal_int_or(dest, a, b);
|
||||
internal_clear_if_uninitialized(a, b) or_return
|
||||
return #force_inline internal_int_or(dest, a, b)
|
||||
}
|
||||
or :: proc { int_or, };
|
||||
or :: proc { int_or, }
|
||||
|
||||
/*
|
||||
2's complement `xor`, returns `dest = a ^ b;`
|
||||
*/
|
||||
int_xor :: proc(dest, a, b: ^Int, allocator := context.allocator) -> (err: Error) {
|
||||
assert_if_nil(dest, a, b);
|
||||
context.allocator = allocator;
|
||||
assert_if_nil(dest, a, b)
|
||||
context.allocator = allocator
|
||||
|
||||
internal_clear_if_uninitialized(a, b) or_return;
|
||||
return #force_inline internal_int_xor(dest, a, b);
|
||||
internal_clear_if_uninitialized(a, b) or_return
|
||||
return #force_inline internal_int_xor(dest, a, b)
|
||||
}
|
||||
xor :: proc { int_xor, };
|
||||
xor :: proc { int_xor, }
|
||||
|
||||
/*
|
||||
dest = ~src
|
||||
@@ -61,31 +61,31 @@ int_complement :: proc(dest, src: ^Int, allocator := context.allocator) -> (err:
|
||||
/*
|
||||
Check that `src` and `dest` are usable.
|
||||
*/
|
||||
assert_if_nil(dest, src);
|
||||
context.allocator = allocator;
|
||||
assert_if_nil(dest, src)
|
||||
context.allocator = allocator
|
||||
|
||||
internal_clear_if_uninitialized(dest, src) or_return;
|
||||
return #force_inline internal_int_complement(dest, src);
|
||||
internal_clear_if_uninitialized(dest, src) or_return
|
||||
return #force_inline internal_int_complement(dest, src)
|
||||
}
|
||||
complement :: proc { int_complement, };
|
||||
complement :: proc { int_complement, }
|
||||
|
||||
/*
|
||||
quotient, remainder := numerator >> bits;
|
||||
`remainder` is allowed to be passed a `nil`, in which case `mod` won't be computed.
|
||||
*/
|
||||
int_shrmod :: proc(quotient, remainder, numerator: ^Int, bits: int, allocator := context.allocator) -> (err: Error) {
|
||||
assert_if_nil(quotient, numerator);
|
||||
context.allocator = allocator;
|
||||
assert_if_nil(quotient, numerator)
|
||||
context.allocator = allocator
|
||||
|
||||
if err = internal_clear_if_uninitialized(quotient, numerator); err != nil { return err; }
|
||||
return #force_inline internal_int_shrmod(quotient, remainder, numerator, bits);
|
||||
return #force_inline internal_int_shrmod(quotient, remainder, numerator, bits)
|
||||
}
|
||||
shrmod :: proc { int_shrmod, };
|
||||
shrmod :: proc { int_shrmod, }
|
||||
|
||||
int_shr :: proc(dest, source: ^Int, bits: int, allocator := context.allocator) -> (err: Error) {
|
||||
return #force_inline shrmod(dest, nil, source, bits, allocator);
|
||||
return #force_inline shrmod(dest, nil, source, bits, allocator)
|
||||
}
|
||||
shr :: proc { int_shr, };
|
||||
shr :: proc { int_shr, }
|
||||
|
||||
/*
|
||||
Shift right by `digits` * _DIGIT_BITS bits.
|
||||
@@ -94,38 +94,38 @@ int_shr_digit :: proc(quotient: ^Int, digits: int, allocator := context.allocato
|
||||
/*
|
||||
Check that `quotient` is usable.
|
||||
*/
|
||||
assert_if_nil(quotient);
|
||||
context.allocator = allocator;
|
||||
assert_if_nil(quotient)
|
||||
context.allocator = allocator
|
||||
|
||||
internal_clear_if_uninitialized(quotient) or_return;
|
||||
return #force_inline internal_int_shr_digit(quotient, digits);
|
||||
internal_clear_if_uninitialized(quotient) or_return
|
||||
return #force_inline internal_int_shr_digit(quotient, digits)
|
||||
}
|
||||
shr_digit :: proc { int_shr_digit, };
|
||||
shr_digit :: proc { int_shr_digit, }
|
||||
|
||||
/*
|
||||
Shift right by a certain bit count with sign extension.
|
||||
*/
|
||||
int_shr_signed :: proc(dest, src: ^Int, bits: int, allocator := context.allocator) -> (err: Error) {
|
||||
assert_if_nil(dest, src);
|
||||
context.allocator = allocator;
|
||||
assert_if_nil(dest, src)
|
||||
context.allocator = allocator
|
||||
|
||||
internal_clear_if_uninitialized(dest, src) or_return;
|
||||
return #force_inline internal_int_shr_signed(dest, src, bits);
|
||||
internal_clear_if_uninitialized(dest, src) or_return
|
||||
return #force_inline internal_int_shr_signed(dest, src, bits)
|
||||
}
|
||||
|
||||
shr_signed :: proc { int_shr_signed, };
|
||||
shr_signed :: proc { int_shr_signed, }
|
||||
|
||||
/*
|
||||
Shift left by a certain bit count.
|
||||
*/
|
||||
int_shl :: proc(dest, src: ^Int, bits: int, allocator := context.allocator) -> (err: Error) {
|
||||
assert_if_nil(dest, src);
|
||||
context.allocator = allocator;
|
||||
assert_if_nil(dest, src)
|
||||
context.allocator = allocator
|
||||
|
||||
internal_clear_if_uninitialized(dest, src) or_return;
|
||||
return #force_inline internal_int_shl(dest, src, bits);
|
||||
internal_clear_if_uninitialized(dest, src) or_return
|
||||
return #force_inline internal_int_shl(dest, src, bits)
|
||||
}
|
||||
shl :: proc { int_shl, };
|
||||
shl :: proc { int_shl, }
|
||||
|
||||
|
||||
/*
|
||||
@@ -135,10 +135,10 @@ int_shl_digit :: proc(quotient: ^Int, digits: int, allocator := context.allocato
|
||||
/*
|
||||
Check that `quotient` is usable.
|
||||
*/
|
||||
assert_if_nil(quotient);
|
||||
context.allocator = allocator;
|
||||
assert_if_nil(quotient)
|
||||
context.allocator = allocator
|
||||
|
||||
internal_clear_if_uninitialized(quotient) or_return;
|
||||
return #force_inline internal_int_shl_digit(quotient, digits);
|
||||
internal_clear_if_uninitialized(quotient) or_return
|
||||
return #force_inline internal_int_shl_digit(quotient, digits)
|
||||
}
|
||||
shl_digit :: proc { int_shl_digit, };
|
||||
+73
-73
@@ -16,43 +16,43 @@ package math_big
|
||||
Returns true if it is, false if not.
|
||||
*/
|
||||
int_prime_is_divisible :: proc(a: ^Int, allocator := context.allocator) -> (res: bool, err: Error) {
|
||||
assert_if_nil(a);
|
||||
context.allocator = allocator;
|
||||
assert_if_nil(a)
|
||||
context.allocator = allocator
|
||||
|
||||
internal_clear_if_uninitialized(a) or_return;
|
||||
internal_clear_if_uninitialized(a) or_return
|
||||
|
||||
for prime in _private_prime_table {
|
||||
rem := #force_inline int_mod_digit(a, prime) or_return;
|
||||
rem := #force_inline int_mod_digit(a, prime) or_return
|
||||
if rem == 0 {
|
||||
return true, nil;
|
||||
return true, nil
|
||||
}
|
||||
}
|
||||
/*
|
||||
Default to not divisible.
|
||||
*/
|
||||
return false, nil;
|
||||
return false, nil
|
||||
}
|
||||
|
||||
/*
|
||||
Computes xR**-1 == x (mod N) via Montgomery Reduction.
|
||||
*/
|
||||
internal_int_montgomery_reduce :: proc(x, n: ^Int, rho: DIGIT, allocator := context.allocator) -> (err: Error) {
|
||||
context.allocator = allocator;
|
||||
context.allocator = allocator
|
||||
/*
|
||||
Can the fast reduction [comba] method be used?
|
||||
Note that unlike in mul, you're safely allowed *less* than the available columns [255 per default],
|
||||
since carries are fixed up in the inner loop.
|
||||
*/
|
||||
digs := (n.used * 2) + 1;
|
||||
digs := (n.used * 2) + 1
|
||||
if digs < _WARRAY && x.used <= _WARRAY && n.used < _MAX_COMBA {
|
||||
return _private_montgomery_reduce_comba(x, n, rho);
|
||||
return _private_montgomery_reduce_comba(x, n, rho)
|
||||
}
|
||||
|
||||
/*
|
||||
Grow the input as required
|
||||
*/
|
||||
internal_grow(x, digs) or_return;
|
||||
x.used = digs;
|
||||
internal_grow(x, digs) or_return
|
||||
x.used = digs
|
||||
|
||||
for ix := 0; ix < n.used; ix += 1 {
|
||||
/*
|
||||
@@ -62,29 +62,29 @@ internal_int_montgomery_reduce :: proc(x, n: ^Int, rho: DIGIT, allocator := cont
|
||||
to reduce the input one digit at a time.
|
||||
*/
|
||||
|
||||
mu := DIGIT((_WORD(x.digit[ix]) * _WORD(rho)) & _WORD(_MASK));
|
||||
mu := DIGIT((_WORD(x.digit[ix]) * _WORD(rho)) & _WORD(_MASK))
|
||||
|
||||
/*
|
||||
a = a + mu * m * b**i
|
||||
Multiply and add in place.
|
||||
*/
|
||||
u := DIGIT(0);
|
||||
iy := int(0);
|
||||
u := DIGIT(0)
|
||||
iy := int(0)
|
||||
for ; iy < n.used; iy += 1 {
|
||||
/*
|
||||
Compute product and sum.
|
||||
*/
|
||||
r := (_WORD(mu) * _WORD(n.digit[iy]) + _WORD(u) + _WORD(x.digit[ix + iy]));
|
||||
r := (_WORD(mu) * _WORD(n.digit[iy]) + _WORD(u) + _WORD(x.digit[ix + iy]))
|
||||
|
||||
/*
|
||||
Get carry.
|
||||
*/
|
||||
u = DIGIT(r >> _DIGIT_BITS);
|
||||
u = DIGIT(r >> _DIGIT_BITS)
|
||||
|
||||
/*
|
||||
Fix digit.
|
||||
*/
|
||||
x.digit[ix + iy] = DIGIT(r & _WORD(_MASK));
|
||||
x.digit[ix + iy] = DIGIT(r & _WORD(_MASK))
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -92,10 +92,10 @@ internal_int_montgomery_reduce :: proc(x, n: ^Int, rho: DIGIT, allocator := cont
|
||||
Propagate carries upwards as required.
|
||||
*/
|
||||
for u != 0 {
|
||||
x.digit[ix + iy] += u;
|
||||
u = x.digit[ix + iy] >> _DIGIT_BITS;
|
||||
x.digit[ix + iy] &= _MASK;
|
||||
iy += 1;
|
||||
x.digit[ix + iy] += u
|
||||
u = x.digit[ix + iy] >> _DIGIT_BITS
|
||||
x.digit[ix + iy] &= _MASK
|
||||
iy += 1
|
||||
}
|
||||
}
|
||||
|
||||
@@ -106,26 +106,26 @@ internal_int_montgomery_reduce :: proc(x, n: ^Int, rho: DIGIT, allocator := cont
|
||||
|
||||
x = x/b**n.used.
|
||||
*/
|
||||
internal_clamp(x);
|
||||
internal_shr_digit(x, n.used);
|
||||
internal_clamp(x)
|
||||
internal_shr_digit(x, n.used)
|
||||
|
||||
/*
|
||||
if x >= n then x = x - n
|
||||
*/
|
||||
if internal_cmp_mag(x, n) != -1 {
|
||||
return internal_sub(x, x, n);
|
||||
return internal_sub(x, x, n)
|
||||
}
|
||||
|
||||
return nil;
|
||||
return nil
|
||||
}
|
||||
|
||||
int_montgomery_reduce :: proc(x, n: ^Int, rho: DIGIT, allocator := context.allocator) -> (err: Error) {
|
||||
assert_if_nil(x, n);
|
||||
context.allocator = allocator;
|
||||
assert_if_nil(x, n)
|
||||
context.allocator = allocator
|
||||
|
||||
internal_clear_if_uninitialized(x, n) or_return;
|
||||
internal_clear_if_uninitialized(x, n) or_return
|
||||
|
||||
return #force_inline internal_int_montgomery_reduce(x, n, rho);
|
||||
return #force_inline internal_int_montgomery_reduce(x, n, rho)
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -135,39 +135,39 @@ int_montgomery_reduce :: proc(x, n: ^Int, rho: DIGIT, allocator := context.alloc
|
||||
the leading bit of b. This saves alot of multiple precision shifting.
|
||||
*/
|
||||
internal_int_montgomery_calc_normalization :: proc(a, b: ^Int, allocator := context.allocator) -> (err: Error) {
|
||||
context.allocator = allocator;
|
||||
context.allocator = allocator
|
||||
/*
|
||||
How many bits of last digit does b use.
|
||||
*/
|
||||
bits := internal_count_bits(b) % _DIGIT_BITS;
|
||||
bits := internal_count_bits(b) % _DIGIT_BITS
|
||||
|
||||
if b.used > 1 {
|
||||
power := ((b.used - 1) * _DIGIT_BITS) + bits - 1;
|
||||
internal_int_power_of_two(a, power) or_return;
|
||||
power := ((b.used - 1) * _DIGIT_BITS) + bits - 1
|
||||
internal_int_power_of_two(a, power) or_return
|
||||
} else {
|
||||
internal_one(a);
|
||||
bits = 1;
|
||||
internal_one(a)
|
||||
bits = 1
|
||||
}
|
||||
|
||||
/*
|
||||
Now compute C = A * B mod b.
|
||||
*/
|
||||
for x := bits - 1; x < _DIGIT_BITS; x += 1 {
|
||||
internal_int_shl1(a, a) or_return;
|
||||
internal_int_shl1(a, a) or_return
|
||||
if internal_cmp_mag(a, b) != -1 {
|
||||
internal_sub(a, a, b) or_return;
|
||||
internal_sub(a, a, b) or_return
|
||||
}
|
||||
}
|
||||
return nil;
|
||||
return nil
|
||||
}
|
||||
|
||||
int_montgomery_calc_normalization :: proc(a, b: ^Int, allocator := context.allocator) -> (err: Error) {
|
||||
assert_if_nil(a, b);
|
||||
context.allocator = allocator;
|
||||
assert_if_nil(a, b)
|
||||
context.allocator = allocator
|
||||
|
||||
internal_clear_if_uninitialized(a, b) or_return;
|
||||
internal_clear_if_uninitialized(a, b) or_return
|
||||
|
||||
return #force_inline internal_int_montgomery_calc_normalization(a, b);
|
||||
return #force_inline internal_int_montgomery_calc_normalization(a, b)
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -182,29 +182,29 @@ internal_int_montgomery_setup :: proc(n: ^Int) -> (rho: DIGIT, err: Error) {
|
||||
=> 2*X*A - X*X*A*A = 1
|
||||
=> 2*(1) - (1) = 1
|
||||
*/
|
||||
b := n.digit[0];
|
||||
b := n.digit[0]
|
||||
if b & 1 == 0 { return 0, .Invalid_Argument; }
|
||||
|
||||
x := (((b + 2) & 4) << 1) + b; /* here x*a==1 mod 2**4 */
|
||||
x *= 2 - (b * x); /* here x*a==1 mod 2**8 */
|
||||
x *= 2 - (b * x); /* here x*a==1 mod 2**16 */
|
||||
x := (((b + 2) & 4) << 1) + b /* here x*a==1 mod 2**4 */
|
||||
x *= 2 - (b * x) /* here x*a==1 mod 2**8 */
|
||||
x *= 2 - (b * x) /* here x*a==1 mod 2**16 */
|
||||
when _WORD_TYPE_BITS == 64 {
|
||||
x *= 2 - (b * x); /* here x*a==1 mod 2**32 */
|
||||
x *= 2 - (b * x); /* here x*a==1 mod 2**64 */
|
||||
x *= 2 - (b * x) /* here x*a==1 mod 2**32 */
|
||||
x *= 2 - (b * x) /* here x*a==1 mod 2**64 */
|
||||
}
|
||||
|
||||
/*
|
||||
rho = -1/m mod b
|
||||
*/
|
||||
rho = DIGIT(((_WORD(1) << _WORD(_DIGIT_BITS)) - _WORD(x)) & _WORD(_MASK));
|
||||
return rho, nil;
|
||||
rho = DIGIT(((_WORD(1) << _WORD(_DIGIT_BITS)) - _WORD(x)) & _WORD(_MASK))
|
||||
return rho, nil
|
||||
}
|
||||
|
||||
int_montgomery_setup :: proc(n: ^Int, allocator := context.allocator) -> (rho: DIGIT, err: Error) {
|
||||
assert_if_nil(n);
|
||||
internal_clear_if_uninitialized(n, allocator) or_return;
|
||||
assert_if_nil(n)
|
||||
internal_clear_if_uninitialized(n, allocator) or_return
|
||||
|
||||
return #force_inline internal_int_montgomery_setup(n);
|
||||
return #force_inline internal_int_montgomery_setup(n)
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -213,44 +213,44 @@ int_montgomery_setup :: proc(n: ^Int, allocator := context.allocator) -> (rho: D
|
||||
number_of_rabin_miller_trials :: proc(bit_size: int) -> (number_of_trials: int) {
|
||||
switch {
|
||||
case bit_size <= 80:
|
||||
return - 1; /* Use deterministic algorithm for size <= 80 bits */
|
||||
return - 1 /* Use deterministic algorithm for size <= 80 bits */
|
||||
case bit_size >= 81 && bit_size < 96:
|
||||
return 37; /* max. error = 2^(-96) */
|
||||
return 37 /* max. error = 2^(-96) */
|
||||
case bit_size >= 96 && bit_size < 128:
|
||||
return 32; /* max. error = 2^(-96) */
|
||||
return 32 /* max. error = 2^(-96) */
|
||||
case bit_size >= 128 && bit_size < 160:
|
||||
return 40; /* max. error = 2^(-112) */
|
||||
return 40 /* max. error = 2^(-112) */
|
||||
case bit_size >= 160 && bit_size < 256:
|
||||
return 35; /* max. error = 2^(-112) */
|
||||
return 35 /* max. error = 2^(-112) */
|
||||
case bit_size >= 256 && bit_size < 384:
|
||||
return 27; /* max. error = 2^(-128) */
|
||||
return 27 /* max. error = 2^(-128) */
|
||||
case bit_size >= 384 && bit_size < 512:
|
||||
return 16; /* max. error = 2^(-128) */
|
||||
return 16 /* max. error = 2^(-128) */
|
||||
case bit_size >= 512 && bit_size < 768:
|
||||
return 18; /* max. error = 2^(-160) */
|
||||
return 18 /* max. error = 2^(-160) */
|
||||
case bit_size >= 768 && bit_size < 896:
|
||||
return 11; /* max. error = 2^(-160) */
|
||||
return 11 /* max. error = 2^(-160) */
|
||||
case bit_size >= 896 && bit_size < 1_024:
|
||||
return 10; /* max. error = 2^(-160) */
|
||||
return 10 /* max. error = 2^(-160) */
|
||||
case bit_size >= 1_024 && bit_size < 1_536:
|
||||
return 12; /* max. error = 2^(-192) */
|
||||
return 12 /* max. error = 2^(-192) */
|
||||
case bit_size >= 1_536 && bit_size < 2_048:
|
||||
return 8; /* max. error = 2^(-192) */
|
||||
return 8 /* max. error = 2^(-192) */
|
||||
case bit_size >= 2_048 && bit_size < 3_072:
|
||||
return 6; /* max. error = 2^(-192) */
|
||||
return 6 /* max. error = 2^(-192) */
|
||||
case bit_size >= 3_072 && bit_size < 4_096:
|
||||
return 4; /* max. error = 2^(-192) */
|
||||
return 4 /* max. error = 2^(-192) */
|
||||
case bit_size >= 4_096 && bit_size < 5_120:
|
||||
return 5; /* max. error = 2^(-256) */
|
||||
return 5 /* max. error = 2^(-256) */
|
||||
case bit_size >= 5_120 && bit_size < 6_144:
|
||||
return 4; /* max. error = 2^(-256) */
|
||||
return 4 /* max. error = 2^(-256) */
|
||||
case bit_size >= 6_144 && bit_size < 8_192:
|
||||
return 4; /* max. error = 2^(-256) */
|
||||
return 4 /* max. error = 2^(-256) */
|
||||
case bit_size >= 8_192 && bit_size < 9_216:
|
||||
return 3; /* max. error = 2^(-256) */
|
||||
return 3 /* max. error = 2^(-256) */
|
||||
case bit_size >= 9_216 && bit_size < 10_240:
|
||||
return 3; /* max. error = 2^(-256) */
|
||||
return 3 /* max. error = 2^(-256) */
|
||||
case:
|
||||
return 2; /* For keysizes bigger than 10_240 use always at least 2 Rounds */
|
||||
return 2 /* For keysizes bigger than 10_240 use always at least 2 Rounds */
|
||||
}
|
||||
}
|
||||
+645
-645
File diff suppressed because it is too large
Load Diff
+175
-175
@@ -21,14 +21,14 @@ package math_big
|
||||
High-level addition. Handles sign.
|
||||
*/
|
||||
int_add :: proc(dest, a, b: ^Int, allocator := context.allocator) -> (err: Error) {
|
||||
assert_if_nil(dest, a, b);
|
||||
context.allocator = allocator;
|
||||
assert_if_nil(dest, a, b)
|
||||
context.allocator = allocator
|
||||
|
||||
internal_clear_if_uninitialized(dest, a, b) or_return;
|
||||
internal_clear_if_uninitialized(dest, a, b) or_return
|
||||
/*
|
||||
All parameters have been initialized.
|
||||
*/
|
||||
return #force_inline internal_int_add_signed(dest, a, b);
|
||||
return #force_inline internal_int_add_signed(dest, a, b)
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -38,33 +38,33 @@ int_add :: proc(dest, a, b: ^Int, allocator := context.allocator) -> (err: Error
|
||||
dest = a + digit;
|
||||
*/
|
||||
int_add_digit :: proc(dest, a: ^Int, digit: DIGIT, allocator := context.allocator) -> (err: Error) {
|
||||
assert_if_nil(dest, a);
|
||||
context.allocator = allocator;
|
||||
assert_if_nil(dest, a)
|
||||
context.allocator = allocator
|
||||
|
||||
internal_clear_if_uninitialized(a) or_return;
|
||||
internal_clear_if_uninitialized(a) or_return
|
||||
/*
|
||||
Grow destination as required.
|
||||
*/
|
||||
grow(dest, a.used + 1) or_return;
|
||||
grow(dest, a.used + 1) or_return
|
||||
|
||||
/*
|
||||
All parameters have been initialized.
|
||||
*/
|
||||
return #force_inline internal_int_add_digit(dest, a, digit);
|
||||
return #force_inline internal_int_add_digit(dest, a, digit)
|
||||
}
|
||||
|
||||
/*
|
||||
High-level subtraction, dest = number - decrease. Handles signs.
|
||||
*/
|
||||
int_sub :: proc(dest, number, decrease: ^Int, allocator := context.allocator) -> (err: Error) {
|
||||
assert_if_nil(dest, number, decrease);
|
||||
context.allocator = allocator;
|
||||
assert_if_nil(dest, number, decrease)
|
||||
context.allocator = allocator
|
||||
|
||||
internal_clear_if_uninitialized(dest, number, decrease) or_return;
|
||||
internal_clear_if_uninitialized(dest, number, decrease) or_return
|
||||
/*
|
||||
All parameters have been initialized.
|
||||
*/
|
||||
return #force_inline internal_int_sub_signed(dest, number, decrease);
|
||||
return #force_inline internal_int_sub_signed(dest, number, decrease)
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -74,19 +74,19 @@ int_sub :: proc(dest, number, decrease: ^Int, allocator := context.allocator) ->
|
||||
dest = a - digit;
|
||||
*/
|
||||
int_sub_digit :: proc(dest, a: ^Int, digit: DIGIT, allocator := context.allocator) -> (err: Error) {
|
||||
assert_if_nil(dest, a);
|
||||
context.allocator = allocator;
|
||||
assert_if_nil(dest, a)
|
||||
context.allocator = allocator
|
||||
|
||||
internal_clear_if_uninitialized(a) or_return;
|
||||
internal_clear_if_uninitialized(a) or_return
|
||||
/*
|
||||
Grow destination as required.
|
||||
*/
|
||||
grow(dest, a.used + 1) or_return;
|
||||
grow(dest, a.used + 1) or_return
|
||||
|
||||
/*
|
||||
All parameters have been initialized.
|
||||
*/
|
||||
return #force_inline internal_int_sub_digit(dest, a, digit);
|
||||
return #force_inline internal_int_sub_digit(dest, a, digit)
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -94,64 +94,64 @@ int_sub_digit :: proc(dest, a: ^Int, digit: DIGIT, allocator := context.allocato
|
||||
dest = src >> 1
|
||||
*/
|
||||
int_halve :: proc(dest, src: ^Int, allocator := context.allocator) -> (err: Error) {
|
||||
assert_if_nil(dest, src);
|
||||
context.allocator = allocator;
|
||||
assert_if_nil(dest, src)
|
||||
context.allocator = allocator
|
||||
|
||||
internal_clear_if_uninitialized(dest, src) or_return;
|
||||
internal_clear_if_uninitialized(dest, src) or_return
|
||||
/*
|
||||
Grow destination as required.
|
||||
*/
|
||||
if dest != src { grow(dest, src.used + 1) or_return }
|
||||
|
||||
return #force_inline internal_int_shr1(dest, src);
|
||||
return #force_inline internal_int_shr1(dest, src)
|
||||
}
|
||||
halve :: proc { int_halve, };
|
||||
shr1 :: halve;
|
||||
halve :: proc { int_halve, }
|
||||
shr1 :: halve
|
||||
|
||||
/*
|
||||
dest = src * 2
|
||||
dest = src << 1
|
||||
*/
|
||||
int_double :: proc(dest, src: ^Int, allocator := context.allocator) -> (err: Error) {
|
||||
assert_if_nil(dest, src);
|
||||
context.allocator = allocator;
|
||||
assert_if_nil(dest, src)
|
||||
context.allocator = allocator
|
||||
|
||||
internal_clear_if_uninitialized(dest, src) or_return;
|
||||
internal_clear_if_uninitialized(dest, src) or_return
|
||||
/*
|
||||
Grow destination as required.
|
||||
*/
|
||||
if dest != src { grow(dest, src.used + 1) or_return; }
|
||||
|
||||
return #force_inline internal_int_shl1(dest, src);
|
||||
return #force_inline internal_int_shl1(dest, src)
|
||||
}
|
||||
double :: proc { int_double, };
|
||||
shl1 :: double;
|
||||
double :: proc { int_double, }
|
||||
shl1 :: double
|
||||
|
||||
/*
|
||||
Multiply by a DIGIT.
|
||||
*/
|
||||
int_mul_digit :: proc(dest, src: ^Int, multiplier: DIGIT, allocator := context.allocator) -> (err: Error) {
|
||||
assert_if_nil(dest, src);
|
||||
context.allocator = allocator;
|
||||
assert_if_nil(dest, src)
|
||||
context.allocator = allocator
|
||||
|
||||
internal_clear_if_uninitialized(src, dest) or_return;
|
||||
internal_clear_if_uninitialized(src, dest) or_return
|
||||
|
||||
return #force_inline internal_int_mul_digit(dest, src, multiplier);
|
||||
return #force_inline internal_int_mul_digit(dest, src, multiplier)
|
||||
}
|
||||
|
||||
/*
|
||||
High level multiplication (handles sign).
|
||||
*/
|
||||
int_mul :: proc(dest, src, multiplier: ^Int, allocator := context.allocator) -> (err: Error) {
|
||||
assert_if_nil(dest, src, multiplier);
|
||||
context.allocator = allocator;
|
||||
assert_if_nil(dest, src, multiplier)
|
||||
context.allocator = allocator
|
||||
|
||||
internal_clear_if_uninitialized(dest, src, multiplier) or_return;
|
||||
internal_clear_if_uninitialized(dest, src, multiplier) or_return
|
||||
|
||||
return #force_inline internal_int_mul(dest, src, multiplier);
|
||||
return #force_inline internal_int_mul(dest, src, multiplier)
|
||||
}
|
||||
|
||||
mul :: proc { int_mul, int_mul_digit, };
|
||||
mul :: proc { int_mul, int_mul_digit, }
|
||||
|
||||
sqr :: proc(dest, src: ^Int) -> (err: Error) { return mul(dest, src, src); }
|
||||
|
||||
@@ -160,46 +160,46 @@ sqr :: proc(dest, src: ^Int) -> (err: Error) { return mul(dest, src, src); }
|
||||
Both the quotient and remainder are optional and may be passed a nil.
|
||||
*/
|
||||
int_divmod :: proc(quotient, remainder, numerator, denominator: ^Int, allocator := context.allocator) -> (err: Error) {
|
||||
context.allocator = allocator;
|
||||
context.allocator = allocator
|
||||
|
||||
/*
|
||||
Early out if neither of the results is wanted.
|
||||
*/
|
||||
if quotient == nil && remainder == nil { return nil; }
|
||||
internal_clear_if_uninitialized(numerator, denominator) or_return;
|
||||
internal_clear_if_uninitialized(numerator, denominator) or_return
|
||||
|
||||
return #force_inline internal_divmod(quotient, remainder, numerator, denominator);
|
||||
return #force_inline internal_divmod(quotient, remainder, numerator, denominator)
|
||||
}
|
||||
|
||||
int_divmod_digit :: proc(quotient, numerator: ^Int, denominator: DIGIT, allocator := context.allocator) -> (remainder: DIGIT, err: Error) {
|
||||
assert_if_nil(quotient, numerator);
|
||||
context.allocator = allocator;
|
||||
assert_if_nil(quotient, numerator)
|
||||
context.allocator = allocator
|
||||
|
||||
internal_clear_if_uninitialized(numerator) or_return;
|
||||
internal_clear_if_uninitialized(numerator) or_return
|
||||
|
||||
return #force_inline internal_divmod(quotient, numerator, denominator);
|
||||
return #force_inline internal_divmod(quotient, numerator, denominator)
|
||||
}
|
||||
divmod :: proc{ int_divmod, int_divmod_digit, };
|
||||
divmod :: proc{ int_divmod, int_divmod_digit, }
|
||||
|
||||
int_div :: proc(quotient, numerator, denominator: ^Int, allocator := context.allocator) -> (err: Error) {
|
||||
assert_if_nil(quotient, numerator, denominator);
|
||||
context.allocator = allocator;
|
||||
assert_if_nil(quotient, numerator, denominator)
|
||||
context.allocator = allocator
|
||||
|
||||
internal_clear_if_uninitialized(numerator, denominator) or_return;
|
||||
internal_clear_if_uninitialized(numerator, denominator) or_return
|
||||
|
||||
return #force_inline internal_divmod(quotient, nil, numerator, denominator);
|
||||
return #force_inline internal_divmod(quotient, nil, numerator, denominator)
|
||||
}
|
||||
|
||||
int_div_digit :: proc(quotient, numerator: ^Int, denominator: DIGIT, allocator := context.allocator) -> (err: Error) {
|
||||
assert_if_nil(quotient, numerator);
|
||||
context.allocator = allocator;
|
||||
assert_if_nil(quotient, numerator)
|
||||
context.allocator = allocator
|
||||
|
||||
internal_clear_if_uninitialized(numerator) or_return;
|
||||
internal_clear_if_uninitialized(numerator) or_return
|
||||
|
||||
_ = #force_inline internal_divmod(quotient, numerator, denominator) or_return;
|
||||
return;
|
||||
_ = #force_inline internal_divmod(quotient, numerator, denominator) or_return
|
||||
return
|
||||
}
|
||||
div :: proc { int_div, int_div_digit, };
|
||||
div :: proc { int_div, int_div_digit, }
|
||||
|
||||
/*
|
||||
remainder = numerator % denominator.
|
||||
@@ -207,80 +207,80 @@ div :: proc { int_div, int_div_digit, };
|
||||
denominator < remainder <= 0 if denominator < 0
|
||||
*/
|
||||
int_mod :: proc(remainder, numerator, denominator: ^Int, allocator := context.allocator) -> (err: Error) {
|
||||
assert_if_nil(remainder, numerator, denominator);
|
||||
context.allocator = allocator;
|
||||
assert_if_nil(remainder, numerator, denominator)
|
||||
context.allocator = allocator
|
||||
|
||||
internal_clear_if_uninitialized(numerator, denominator) or_return;
|
||||
internal_clear_if_uninitialized(numerator, denominator) or_return
|
||||
|
||||
return #force_inline internal_int_mod(remainder, numerator, denominator);
|
||||
return #force_inline internal_int_mod(remainder, numerator, denominator)
|
||||
}
|
||||
|
||||
int_mod_digit :: proc(numerator: ^Int, denominator: DIGIT, allocator := context.allocator) -> (remainder: DIGIT, err: Error) {
|
||||
return #force_inline internal_divmod(nil, numerator, denominator, allocator);
|
||||
return #force_inline internal_divmod(nil, numerator, denominator, allocator)
|
||||
}
|
||||
|
||||
mod :: proc { int_mod, int_mod_digit, };
|
||||
mod :: proc { int_mod, int_mod_digit, }
|
||||
|
||||
/*
|
||||
remainder = (number + addend) % modulus.
|
||||
*/
|
||||
int_addmod :: proc(remainder, number, addend, modulus: ^Int, allocator := context.allocator) -> (err: Error) {
|
||||
assert_if_nil(remainder, number, addend);
|
||||
context.allocator = allocator;
|
||||
assert_if_nil(remainder, number, addend)
|
||||
context.allocator = allocator
|
||||
|
||||
internal_clear_if_uninitialized(number, addend, modulus) or_return;
|
||||
internal_clear_if_uninitialized(number, addend, modulus) or_return
|
||||
|
||||
return #force_inline internal_addmod(remainder, number, addend, modulus);
|
||||
return #force_inline internal_addmod(remainder, number, addend, modulus)
|
||||
}
|
||||
addmod :: proc { int_addmod, };
|
||||
addmod :: proc { int_addmod, }
|
||||
|
||||
/*
|
||||
remainder = (number - decrease) % modulus.
|
||||
*/
|
||||
int_submod :: proc(remainder, number, decrease, modulus: ^Int, allocator := context.allocator) -> (err: Error) {
|
||||
assert_if_nil(remainder, number, decrease);
|
||||
context.allocator = allocator;
|
||||
assert_if_nil(remainder, number, decrease)
|
||||
context.allocator = allocator
|
||||
|
||||
internal_clear_if_uninitialized(number, decrease, modulus) or_return;
|
||||
internal_clear_if_uninitialized(number, decrease, modulus) or_return
|
||||
|
||||
return #force_inline internal_submod(remainder, number, decrease, modulus);
|
||||
return #force_inline internal_submod(remainder, number, decrease, modulus)
|
||||
}
|
||||
submod :: proc { int_submod, };
|
||||
submod :: proc { int_submod, }
|
||||
|
||||
/*
|
||||
remainder = (number * multiplicand) % modulus.
|
||||
*/
|
||||
int_mulmod :: proc(remainder, number, multiplicand, modulus: ^Int, allocator := context.allocator) -> (err: Error) {
|
||||
assert_if_nil(remainder, number, multiplicand);
|
||||
context.allocator = allocator;
|
||||
assert_if_nil(remainder, number, multiplicand)
|
||||
context.allocator = allocator
|
||||
|
||||
internal_clear_if_uninitialized(number, multiplicand, modulus) or_return;
|
||||
internal_clear_if_uninitialized(number, multiplicand, modulus) or_return
|
||||
|
||||
return #force_inline internal_mulmod(remainder, number, multiplicand, modulus);
|
||||
return #force_inline internal_mulmod(remainder, number, multiplicand, modulus)
|
||||
}
|
||||
mulmod :: proc { int_mulmod, };
|
||||
mulmod :: proc { int_mulmod, }
|
||||
|
||||
/*
|
||||
remainder = (number * number) % modulus.
|
||||
*/
|
||||
int_sqrmod :: proc(remainder, number, modulus: ^Int, allocator := context.allocator) -> (err: Error) {
|
||||
assert_if_nil(remainder, number, modulus);
|
||||
context.allocator = allocator;
|
||||
assert_if_nil(remainder, number, modulus)
|
||||
context.allocator = allocator
|
||||
|
||||
internal_clear_if_uninitialized(number, modulus) or_return;
|
||||
internal_clear_if_uninitialized(number, modulus) or_return
|
||||
|
||||
return #force_inline internal_sqrmod(remainder, number, modulus);
|
||||
return #force_inline internal_sqrmod(remainder, number, modulus)
|
||||
}
|
||||
sqrmod :: proc { int_sqrmod, };
|
||||
sqrmod :: proc { int_sqrmod, }
|
||||
|
||||
|
||||
int_factorial :: proc(res: ^Int, n: int, allocator := context.allocator) -> (err: Error) {
|
||||
if n < 0 || n > FACTORIAL_MAX_N { return .Invalid_Argument; }
|
||||
assert_if_nil(res);
|
||||
assert_if_nil(res)
|
||||
|
||||
return #force_inline internal_int_factorial(res, n, allocator);
|
||||
return #force_inline internal_int_factorial(res, n, allocator)
|
||||
}
|
||||
factorial :: proc { int_factorial, };
|
||||
factorial :: proc { int_factorial, }
|
||||
|
||||
|
||||
/*
|
||||
@@ -299,8 +299,8 @@ factorial :: proc { int_factorial, };
|
||||
|
||||
*/
|
||||
int_choose_digit :: proc(res: ^Int, n, k: int, allocator := context.allocator) -> (err: Error) {
|
||||
assert_if_nil(res);
|
||||
context.allocator = allocator;
|
||||
assert_if_nil(res)
|
||||
context.allocator = allocator
|
||||
|
||||
if n < 0 || n > FACTORIAL_MAX_N { return .Invalid_Argument; }
|
||||
if k > n { return internal_zero(res); }
|
||||
@@ -308,8 +308,8 @@ int_choose_digit :: proc(res: ^Int, n, k: int, allocator := context.allocator) -
|
||||
/*
|
||||
res = n! / (k! * (n - k)!)
|
||||
*/
|
||||
n_fac, k_fac, n_minus_k_fac := &Int{}, &Int{}, &Int{};
|
||||
defer internal_destroy(n_fac, k_fac, n_minus_k_fac);
|
||||
n_fac, k_fac, n_minus_k_fac := &Int{}, &Int{}, &Int{}
|
||||
defer internal_destroy(n_fac, k_fac, n_minus_k_fac)
|
||||
|
||||
#force_inline internal_int_factorial(n_minus_k_fac, n - k) or_return;
|
||||
#force_inline internal_int_factorial(k_fac, k) or_return;
|
||||
@@ -318,112 +318,112 @@ int_choose_digit :: proc(res: ^Int, n, k: int, allocator := context.allocator) -
|
||||
#force_inline internal_int_factorial(n_fac, n) or_return;
|
||||
#force_inline internal_div(res, n_fac, k_fac) or_return;
|
||||
|
||||
return;
|
||||
return
|
||||
}
|
||||
choose :: proc { int_choose_digit, };
|
||||
choose :: proc { int_choose_digit, }
|
||||
|
||||
/*
|
||||
Function computing both GCD and (if target isn't `nil`) also LCM.
|
||||
*/
|
||||
int_gcd_lcm :: proc(res_gcd, res_lcm, a, b: ^Int, allocator := context.allocator) -> (err: Error) {
|
||||
if res_gcd == nil && res_lcm == nil { return nil; }
|
||||
assert_if_nil(a, b);
|
||||
context.allocator = allocator;
|
||||
assert_if_nil(a, b)
|
||||
context.allocator = allocator
|
||||
|
||||
internal_clear_if_uninitialized(a, b) or_return;
|
||||
return #force_inline internal_int_gcd_lcm(res_gcd, res_lcm, a, b);
|
||||
internal_clear_if_uninitialized(a, b) or_return
|
||||
return #force_inline internal_int_gcd_lcm(res_gcd, res_lcm, a, b)
|
||||
}
|
||||
gcd_lcm :: proc { int_gcd_lcm, };
|
||||
gcd_lcm :: proc { int_gcd_lcm, }
|
||||
|
||||
/*
|
||||
Greatest Common Divisor.
|
||||
*/
|
||||
int_gcd :: proc(res, a, b: ^Int, allocator := context.allocator) -> (err: Error) {
|
||||
return #force_inline int_gcd_lcm(res, nil, a, b, allocator);
|
||||
return #force_inline int_gcd_lcm(res, nil, a, b, allocator)
|
||||
}
|
||||
gcd :: proc { int_gcd, };
|
||||
gcd :: proc { int_gcd, }
|
||||
|
||||
/*
|
||||
Least Common Multiple.
|
||||
*/
|
||||
int_lcm :: proc(res, a, b: ^Int, allocator := context.allocator) -> (err: Error) {
|
||||
return #force_inline int_gcd_lcm(nil, res, a, b, allocator);
|
||||
return #force_inline int_gcd_lcm(nil, res, a, b, allocator)
|
||||
}
|
||||
lcm :: proc { int_lcm, };
|
||||
lcm :: proc { int_lcm, }
|
||||
|
||||
/*
|
||||
remainder = numerator % (1 << bits)
|
||||
*/
|
||||
int_mod_bits :: proc(remainder, numerator: ^Int, bits: int, allocator := context.allocator) -> (err: Error) {
|
||||
assert_if_nil(remainder, numerator);
|
||||
context.allocator = allocator;
|
||||
assert_if_nil(remainder, numerator)
|
||||
context.allocator = allocator
|
||||
|
||||
internal_clear_if_uninitialized(remainder, numerator) or_return;
|
||||
internal_clear_if_uninitialized(remainder, numerator) or_return
|
||||
if bits < 0 { return .Invalid_Argument; }
|
||||
|
||||
return #force_inline internal_int_mod_bits(remainder, numerator, bits);
|
||||
return #force_inline internal_int_mod_bits(remainder, numerator, bits)
|
||||
}
|
||||
|
||||
mod_bits :: proc { int_mod_bits, };
|
||||
mod_bits :: proc { int_mod_bits, }
|
||||
|
||||
|
||||
/*
|
||||
Logs and roots and such.
|
||||
*/
|
||||
int_log :: proc(a: ^Int, base: DIGIT, allocator := context.allocator) -> (res: int, err: Error) {
|
||||
assert_if_nil(a);
|
||||
context.allocator = allocator;
|
||||
assert_if_nil(a)
|
||||
context.allocator = allocator
|
||||
|
||||
internal_clear_if_uninitialized(a) or_return;
|
||||
internal_clear_if_uninitialized(a) or_return
|
||||
|
||||
return #force_inline internal_int_log(a, base);
|
||||
return #force_inline internal_int_log(a, base)
|
||||
}
|
||||
|
||||
digit_log :: proc(a: DIGIT, base: DIGIT) -> (log: int, err: Error) {
|
||||
return #force_inline internal_digit_log(a, base);
|
||||
return #force_inline internal_digit_log(a, base)
|
||||
}
|
||||
log :: proc { int_log, digit_log, };
|
||||
log :: proc { int_log, digit_log, }
|
||||
|
||||
/*
|
||||
Calculate `dest = base^power` using a square-multiply algorithm.
|
||||
*/
|
||||
int_pow :: proc(dest, base: ^Int, power: int, allocator := context.allocator) -> (err: Error) {
|
||||
assert_if_nil(dest, base);
|
||||
context.allocator = allocator;
|
||||
assert_if_nil(dest, base)
|
||||
context.allocator = allocator
|
||||
|
||||
internal_clear_if_uninitialized(dest, base) or_return;
|
||||
internal_clear_if_uninitialized(dest, base) or_return
|
||||
|
||||
return #force_inline internal_int_pow(dest, base, power);
|
||||
return #force_inline internal_int_pow(dest, base, power)
|
||||
}
|
||||
|
||||
/*
|
||||
Calculate `dest = base^power` using a square-multiply algorithm.
|
||||
*/
|
||||
int_pow_int :: proc(dest: ^Int, base, power: int, allocator := context.allocator) -> (err: Error) {
|
||||
assert_if_nil(dest);
|
||||
assert_if_nil(dest)
|
||||
|
||||
return #force_inline internal_pow(dest, base, power, allocator);
|
||||
return #force_inline internal_pow(dest, base, power, allocator)
|
||||
}
|
||||
|
||||
pow :: proc { int_pow, int_pow_int, small_pow, };
|
||||
exp :: pow;
|
||||
pow :: proc { int_pow, int_pow_int, small_pow, }
|
||||
exp :: pow
|
||||
|
||||
small_pow :: proc(base: _WORD, exponent: _WORD) -> (result: _WORD) {
|
||||
return #force_inline internal_small_pow(base, exponent);
|
||||
return #force_inline internal_small_pow(base, exponent)
|
||||
}
|
||||
|
||||
/*
|
||||
This function is less generic than `root_n`, simpler and faster.
|
||||
*/
|
||||
int_sqrt :: proc(dest, src: ^Int, allocator := context.allocator) -> (err: Error) {
|
||||
assert_if_nil(dest, src);
|
||||
context.allocator = allocator;
|
||||
assert_if_nil(dest, src)
|
||||
context.allocator = allocator
|
||||
|
||||
internal_clear_if_uninitialized(dest, src) or_return;
|
||||
internal_clear_if_uninitialized(dest, src) or_return
|
||||
|
||||
return #force_inline internal_int_sqrt(dest, src);
|
||||
return #force_inline internal_int_sqrt(dest, src)
|
||||
}
|
||||
sqrt :: proc { int_sqrt, };
|
||||
sqrt :: proc { int_sqrt, }
|
||||
|
||||
|
||||
/*
|
||||
@@ -434,22 +434,22 @@ sqrt :: proc { int_sqrt, };
|
||||
which will find the root in `log(n)` time where each step involves a fair bit.
|
||||
*/
|
||||
int_root_n :: proc(dest, src: ^Int, n: int, allocator := context.allocator) -> (err: Error) {
|
||||
context.allocator = allocator;
|
||||
context.allocator = allocator
|
||||
|
||||
/*
|
||||
Fast path for n == 2.
|
||||
*/
|
||||
if n == 2 { return sqrt(dest, src); }
|
||||
|
||||
assert_if_nil(dest, src);
|
||||
assert_if_nil(dest, src)
|
||||
/*
|
||||
Initialize dest + src if needed.
|
||||
*/
|
||||
internal_clear_if_uninitialized(dest, src) or_return;
|
||||
internal_clear_if_uninitialized(dest, src) or_return
|
||||
|
||||
return #force_inline internal_int_root_n(dest, src, n);
|
||||
return #force_inline internal_int_root_n(dest, src, n)
|
||||
}
|
||||
root_n :: proc { int_root_n, };
|
||||
root_n :: proc { int_root_n, }
|
||||
|
||||
/*
|
||||
Comparison routines.
|
||||
@@ -458,103 +458,103 @@ root_n :: proc { int_root_n, };
|
||||
int_is_initialized :: proc(a: ^Int) -> bool {
|
||||
if a == nil { return false; }
|
||||
|
||||
return #force_inline internal_int_is_initialized(a);
|
||||
return #force_inline internal_int_is_initialized(a)
|
||||
}
|
||||
|
||||
int_is_zero :: proc(a: ^Int, allocator := context.allocator) -> (zero: bool, err: Error) {
|
||||
assert_if_nil(a);
|
||||
context.allocator = allocator;
|
||||
assert_if_nil(a)
|
||||
context.allocator = allocator
|
||||
|
||||
internal_clear_if_uninitialized(a) or_return;
|
||||
internal_clear_if_uninitialized(a) or_return
|
||||
|
||||
return #force_inline internal_is_zero(a), nil;
|
||||
return #force_inline internal_is_zero(a), nil
|
||||
}
|
||||
|
||||
int_is_positive :: proc(a: ^Int, allocator := context.allocator) -> (positive: bool, err: Error) {
|
||||
assert_if_nil(a);
|
||||
context.allocator = allocator;
|
||||
assert_if_nil(a)
|
||||
context.allocator = allocator
|
||||
|
||||
internal_clear_if_uninitialized(a) or_return;
|
||||
internal_clear_if_uninitialized(a) or_return
|
||||
|
||||
return #force_inline internal_is_positive(a), nil;
|
||||
return #force_inline internal_is_positive(a), nil
|
||||
}
|
||||
|
||||
int_is_negative :: proc(a: ^Int, allocator := context.allocator) -> (negative: bool, err: Error) {
|
||||
assert_if_nil(a);
|
||||
context.allocator = allocator;
|
||||
assert_if_nil(a)
|
||||
context.allocator = allocator
|
||||
|
||||
internal_clear_if_uninitialized(a) or_return;
|
||||
internal_clear_if_uninitialized(a) or_return
|
||||
|
||||
return #force_inline internal_is_negative(a), nil;
|
||||
return #force_inline internal_is_negative(a), nil
|
||||
}
|
||||
|
||||
int_is_even :: proc(a: ^Int, allocator := context.allocator) -> (even: bool, err: Error) {
|
||||
assert_if_nil(a);
|
||||
context.allocator = allocator;
|
||||
assert_if_nil(a)
|
||||
context.allocator = allocator
|
||||
|
||||
internal_clear_if_uninitialized(a) or_return;
|
||||
internal_clear_if_uninitialized(a) or_return
|
||||
|
||||
return #force_inline internal_is_even(a), nil;
|
||||
return #force_inline internal_is_even(a), nil
|
||||
}
|
||||
|
||||
int_is_odd :: proc(a: ^Int, allocator := context.allocator) -> (odd: bool, err: Error) {
|
||||
assert_if_nil(a);
|
||||
context.allocator = allocator;
|
||||
assert_if_nil(a)
|
||||
context.allocator = allocator
|
||||
|
||||
internal_clear_if_uninitialized(a) or_return;
|
||||
internal_clear_if_uninitialized(a) or_return
|
||||
|
||||
return #force_inline internal_is_odd(a), nil;
|
||||
return #force_inline internal_is_odd(a), nil
|
||||
}
|
||||
|
||||
platform_int_is_power_of_two :: #force_inline proc(a: int) -> bool {
|
||||
return ((a) != 0) && (((a) & ((a) - 1)) == 0);
|
||||
return ((a) != 0) && (((a) & ((a) - 1)) == 0)
|
||||
}
|
||||
|
||||
int_is_power_of_two :: proc(a: ^Int, allocator := context.allocator) -> (res: bool, err: Error) {
|
||||
assert_if_nil(a);
|
||||
context.allocator = allocator;
|
||||
assert_if_nil(a)
|
||||
context.allocator = allocator
|
||||
|
||||
internal_clear_if_uninitialized(a) or_return;
|
||||
internal_clear_if_uninitialized(a) or_return
|
||||
|
||||
return #force_inline internal_is_power_of_two(a), nil;
|
||||
return #force_inline internal_is_power_of_two(a), nil
|
||||
}
|
||||
|
||||
/*
|
||||
Compare two `Int`s, signed.
|
||||
*/
|
||||
int_compare :: proc(a, b: ^Int, allocator := context.allocator) -> (comparison: int, err: Error) {
|
||||
assert_if_nil(a, b);
|
||||
context.allocator = allocator;
|
||||
assert_if_nil(a, b)
|
||||
context.allocator = allocator
|
||||
|
||||
internal_clear_if_uninitialized(a, b) or_return;
|
||||
internal_clear_if_uninitialized(a, b) or_return
|
||||
|
||||
return #force_inline internal_cmp(a, b), nil;
|
||||
return #force_inline internal_cmp(a, b), nil
|
||||
}
|
||||
int_cmp :: int_compare;
|
||||
int_cmp :: int_compare
|
||||
|
||||
/*
|
||||
Compare an `Int` to an unsigned number upto the size of the backing type.
|
||||
*/
|
||||
int_compare_digit :: proc(a: ^Int, b: DIGIT, allocator := context.allocator) -> (comparison: int, err: Error) {
|
||||
assert_if_nil(a);
|
||||
context.allocator = allocator;
|
||||
assert_if_nil(a)
|
||||
context.allocator = allocator
|
||||
|
||||
internal_clear_if_uninitialized(a) or_return;
|
||||
internal_clear_if_uninitialized(a) or_return
|
||||
|
||||
return #force_inline internal_cmp_digit(a, b), nil;
|
||||
return #force_inline internal_cmp_digit(a, b), nil
|
||||
}
|
||||
int_cmp_digit :: int_compare_digit;
|
||||
int_cmp_digit :: int_compare_digit
|
||||
|
||||
/*
|
||||
Compare the magnitude of two `Int`s, unsigned.
|
||||
*/
|
||||
int_compare_magnitude :: proc(a, b: ^Int, allocator := context.allocator) -> (res: int, err: Error) {
|
||||
assert_if_nil(a, b);
|
||||
context.allocator = allocator;
|
||||
assert_if_nil(a, b)
|
||||
context.allocator = allocator
|
||||
|
||||
internal_clear_if_uninitialized(a, b) or_return;
|
||||
internal_clear_if_uninitialized(a, b) or_return
|
||||
|
||||
return #force_inline internal_cmp_mag(a, b), nil;
|
||||
return #force_inline internal_cmp_mag(a, b), nil
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -564,10 +564,10 @@ int_compare_magnitude :: proc(a, b: ^Int, allocator := context.allocator) -> (re
|
||||
Assumes `a` not to be `nil` and to have been initialized.
|
||||
*/
|
||||
int_is_square :: proc(a: ^Int, allocator := context.allocator) -> (square: bool, err: Error) {
|
||||
assert_if_nil(a);
|
||||
context.allocator = allocator;
|
||||
assert_if_nil(a)
|
||||
context.allocator = allocator
|
||||
|
||||
internal_clear_if_uninitialized(a) or_return;
|
||||
internal_clear_if_uninitialized(a) or_return
|
||||
|
||||
return #force_inline internal_int_is_square(a);
|
||||
return #force_inline internal_int_is_square(a)
|
||||
}
|
||||
+140
-140
@@ -22,15 +22,15 @@ import "core:mem"
|
||||
This version of `itoa` allocates one behalf of the caller. The caller must free the string.
|
||||
*/
|
||||
int_itoa_string :: proc(a: ^Int, radix := i8(-1), zero_terminate := false, allocator := context.allocator) -> (res: string, err: Error) {
|
||||
assert_if_nil(a);
|
||||
context.allocator = allocator;
|
||||
assert_if_nil(a)
|
||||
context.allocator = allocator
|
||||
|
||||
a := a; radix := radix;
|
||||
clear_if_uninitialized(a) or_return;
|
||||
a := a; radix := radix
|
||||
clear_if_uninitialized(a) or_return
|
||||
/*
|
||||
Radix defaults to 10.
|
||||
*/
|
||||
radix = radix if radix > 0 else 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.
|
||||
@@ -41,39 +41,39 @@ int_itoa_string :: proc(a: ^Int, radix := i8(-1), zero_terminate := false, alloc
|
||||
Calculate the size of the buffer we need, and
|
||||
Exit if calculating the size returned an error.
|
||||
*/
|
||||
size := radix_size(a, radix, zero_terminate) or_return;
|
||||
size := radix_size(a, radix, zero_terminate) or_return
|
||||
|
||||
/*
|
||||
Allocate the buffer we need.
|
||||
*/
|
||||
buffer := make([]u8, size);
|
||||
buffer := make([]u8, size)
|
||||
|
||||
/*
|
||||
Write the digits out into the buffer.
|
||||
*/
|
||||
written: int;
|
||||
written, err = int_itoa_raw(a, radix, buffer, size, zero_terminate);
|
||||
written: int
|
||||
written, err = int_itoa_raw(a, radix, buffer, size, zero_terminate)
|
||||
|
||||
return string(buffer[:written]), err;
|
||||
return string(buffer[:written]), err
|
||||
}
|
||||
|
||||
/*
|
||||
This version of `itoa` allocates one behalf of the caller. The caller must free the string.
|
||||
*/
|
||||
int_itoa_cstring :: proc(a: ^Int, radix := i8(-1), allocator := context.allocator) -> (res: cstring, err: Error) {
|
||||
assert_if_nil(a);
|
||||
context.allocator = allocator;
|
||||
assert_if_nil(a)
|
||||
context.allocator = allocator
|
||||
|
||||
a := a; radix := radix;
|
||||
clear_if_uninitialized(a) or_return;
|
||||
a := a; radix := radix
|
||||
clear_if_uninitialized(a) or_return
|
||||
/*
|
||||
Radix defaults to 10.
|
||||
*/
|
||||
radix = radix if radix > 0 else 10;
|
||||
radix = radix if radix > 0 else 10
|
||||
|
||||
s: string;
|
||||
s, err = int_itoa_string(a, radix, true);
|
||||
return cstring(raw_data(s)), err;
|
||||
s: string
|
||||
s, err = int_itoa_string(a, radix, true)
|
||||
return cstring(raw_data(s)), err
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -97,57 +97,57 @@ int_itoa_cstring :: proc(a: ^Int, radix := i8(-1), allocator := context.allocato
|
||||
and having to perform a buffer overflow check each character.
|
||||
*/
|
||||
int_itoa_raw :: proc(a: ^Int, radix: i8, buffer: []u8, size := int(-1), zero_terminate := false) -> (written: int, err: Error) {
|
||||
assert_if_nil(a);
|
||||
a := a; radix := radix; size := size;
|
||||
clear_if_uninitialized(a) or_return;
|
||||
assert_if_nil(a)
|
||||
a := a; radix := radix; size := size
|
||||
clear_if_uninitialized(a) or_return
|
||||
/*
|
||||
Radix defaults to 10.
|
||||
*/
|
||||
radix = radix if radix > 0 else 10;
|
||||
radix = radix if radix > 0 else 10
|
||||
if radix < 2 || radix > 64 {
|
||||
return 0, .Invalid_Argument;
|
||||
return 0, .Invalid_Argument
|
||||
}
|
||||
|
||||
/*
|
||||
We weren't given a size. Let's compute it.
|
||||
*/
|
||||
if size == -1 {
|
||||
size = radix_size(a, radix, zero_terminate) or_return;
|
||||
size = radix_size(a, radix, zero_terminate) or_return
|
||||
}
|
||||
|
||||
/*
|
||||
Early exit if the buffer we were given is too small.
|
||||
*/
|
||||
available := len(buffer);
|
||||
available := len(buffer)
|
||||
if available < size {
|
||||
return 0, .Buffer_Overflow;
|
||||
return 0, .Buffer_Overflow
|
||||
}
|
||||
/*
|
||||
Fast path for when `Int` == 0 or the entire `Int` fits in a single radix digit.
|
||||
*/
|
||||
z, _ := is_zero(a);
|
||||
z, _ := is_zero(a)
|
||||
if z || (a.used == 1 && a.digit[0] < DIGIT(radix)) {
|
||||
if zero_terminate {
|
||||
available -= 1;
|
||||
buffer[available] = 0;
|
||||
available -= 1
|
||||
buffer[available] = 0
|
||||
}
|
||||
available -= 1;
|
||||
buffer[available] = RADIX_TABLE[a.digit[0]];
|
||||
available -= 1
|
||||
buffer[available] = RADIX_TABLE[a.digit[0]]
|
||||
|
||||
if n, _ := is_neg(a); n {
|
||||
available -= 1;
|
||||
buffer[available] = '-';
|
||||
available -= 1
|
||||
buffer[available] = '-'
|
||||
}
|
||||
|
||||
/*
|
||||
If we overestimated the size, we need to move the buffer left.
|
||||
*/
|
||||
written = len(buffer) - available;
|
||||
written = len(buffer) - available
|
||||
if written < size {
|
||||
diff := size - written;
|
||||
mem.copy(&buffer[0], &buffer[diff], written);
|
||||
diff := size - written
|
||||
mem.copy(&buffer[0], &buffer[diff], written)
|
||||
}
|
||||
return written, nil;
|
||||
return written, nil
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -155,32 +155,32 @@ int_itoa_raw :: proc(a: ^Int, radix: i8, buffer: []u8, size := int(-1), zero_ter
|
||||
*/
|
||||
if a.used == 1 || a.used == 2 {
|
||||
if zero_terminate {
|
||||
available -= 1;
|
||||
buffer[available] = 0;
|
||||
available -= 1
|
||||
buffer[available] = 0
|
||||
}
|
||||
|
||||
val := _WORD(a.digit[1]) << _DIGIT_BITS + _WORD(a.digit[0]);
|
||||
val := _WORD(a.digit[1]) << _DIGIT_BITS + _WORD(a.digit[0])
|
||||
for val > 0 {
|
||||
q := val / _WORD(radix);
|
||||
available -= 1;
|
||||
buffer[available] = RADIX_TABLE[val - (q * _WORD(radix))];
|
||||
q := val / _WORD(radix)
|
||||
available -= 1
|
||||
buffer[available] = RADIX_TABLE[val - (q * _WORD(radix))]
|
||||
|
||||
val = q;
|
||||
val = q
|
||||
}
|
||||
if n, _ := is_neg(a); n {
|
||||
available -= 1;
|
||||
buffer[available] = '-';
|
||||
available -= 1
|
||||
buffer[available] = '-'
|
||||
}
|
||||
|
||||
/*
|
||||
If we overestimated the size, we need to move the buffer left.
|
||||
*/
|
||||
written = len(buffer) - available;
|
||||
written = len(buffer) - available
|
||||
if written < size {
|
||||
diff := size - written;
|
||||
mem.copy(&buffer[0], &buffer[diff], written);
|
||||
diff := size - written
|
||||
mem.copy(&buffer[0], &buffer[diff], written)
|
||||
}
|
||||
return written, nil;
|
||||
return written, nil
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -188,57 +188,57 @@ int_itoa_raw :: proc(a: ^Int, radix: i8, buffer: []u8, size := int(-1), zero_ter
|
||||
*/
|
||||
if is_power_of_two(int(radix)) {
|
||||
if zero_terminate {
|
||||
available -= 1;
|
||||
buffer[available] = 0;
|
||||
available -= 1
|
||||
buffer[available] = 0
|
||||
}
|
||||
|
||||
shift, count: int;
|
||||
shift, count: int
|
||||
// mask := _WORD(radix - 1);
|
||||
shift, err = log(DIGIT(radix), 2);
|
||||
count, err = count_bits(a);
|
||||
digit: _WORD;
|
||||
shift, err = log(DIGIT(radix), 2)
|
||||
count, err = count_bits(a)
|
||||
digit: _WORD
|
||||
|
||||
for offset := 0; offset < count; offset += shift {
|
||||
bits_to_get := int(min(count - offset, shift));
|
||||
bits_to_get := int(min(count - offset, shift))
|
||||
|
||||
digit, err = int_bitfield_extract(a, offset, bits_to_get);
|
||||
digit, err = int_bitfield_extract(a, offset, bits_to_get)
|
||||
if err != nil {
|
||||
return len(buffer) - available, .Invalid_Argument;
|
||||
return len(buffer) - available, .Invalid_Argument
|
||||
}
|
||||
available -= 1;
|
||||
buffer[available] = RADIX_TABLE[digit];
|
||||
available -= 1
|
||||
buffer[available] = RADIX_TABLE[digit]
|
||||
}
|
||||
|
||||
if n, _ := is_neg(a); n {
|
||||
available -= 1;
|
||||
buffer[available] = '-';
|
||||
available -= 1
|
||||
buffer[available] = '-'
|
||||
}
|
||||
|
||||
/*
|
||||
If we overestimated the size, we need to move the buffer left.
|
||||
*/
|
||||
written = len(buffer) - available;
|
||||
written = len(buffer) - available
|
||||
if written < size {
|
||||
diff := size - written;
|
||||
mem.copy(&buffer[0], &buffer[diff], written);
|
||||
diff := size - written
|
||||
mem.copy(&buffer[0], &buffer[diff], written)
|
||||
}
|
||||
return written, nil;
|
||||
return written, nil
|
||||
}
|
||||
|
||||
return _itoa_raw_full(a, radix, buffer, zero_terminate);
|
||||
return _itoa_raw_full(a, radix, buffer, zero_terminate)
|
||||
}
|
||||
|
||||
itoa :: proc{int_itoa_string, int_itoa_raw};
|
||||
int_to_string :: int_itoa_string;
|
||||
int_to_cstring :: int_itoa_cstring;
|
||||
itoa :: proc{int_itoa_string, int_itoa_raw}
|
||||
int_to_string :: int_itoa_string
|
||||
int_to_cstring :: int_itoa_cstring
|
||||
|
||||
/*
|
||||
Read a string [ASCII] in a given radix.
|
||||
*/
|
||||
int_atoi :: proc(res: ^Int, input: string, radix := i8(10), allocator := context.allocator) -> (err: Error) {
|
||||
assert_if_nil(res);
|
||||
input := input;
|
||||
context.allocator = allocator;
|
||||
assert_if_nil(res)
|
||||
input := input
|
||||
context.allocator = allocator
|
||||
|
||||
/*
|
||||
Make sure the radix is ok.
|
||||
@@ -249,92 +249,92 @@ int_atoi :: proc(res: ^Int, input: string, radix := i8(10), allocator := context
|
||||
/*
|
||||
Set the integer to the default of zero.
|
||||
*/
|
||||
internal_zero(res) or_return;
|
||||
internal_zero(res) or_return
|
||||
|
||||
/*
|
||||
We'll interpret an empty string as zero.
|
||||
*/
|
||||
if len(input) == 0 {
|
||||
return nil;
|
||||
return nil
|
||||
}
|
||||
|
||||
/*
|
||||
If the leading digit is a minus set the sign to negative.
|
||||
Given the above early out, the length should be at least 1.
|
||||
*/
|
||||
sign := Sign.Zero_or_Positive;
|
||||
sign := Sign.Zero_or_Positive
|
||||
if input[0] == '-' {
|
||||
input = input[1:];
|
||||
sign = .Negative;
|
||||
input = input[1:]
|
||||
sign = .Negative
|
||||
}
|
||||
|
||||
/*
|
||||
Process each digit of the string.
|
||||
*/
|
||||
ch: rune;
|
||||
ch: rune
|
||||
for len(input) > 0 {
|
||||
/* if the radix <= 36 the conversion is case insensitive
|
||||
* this allows numbers like 1AB and 1ab to represent the same value
|
||||
* [e.g. in hex]
|
||||
*/
|
||||
|
||||
ch = rune(input[0]);
|
||||
ch = rune(input[0])
|
||||
if radix <= 36 && ch >= 'a' && ch <= 'z' {
|
||||
ch -= 32; // 'a' - 'A'
|
||||
ch -= 32 // 'a' - 'A'
|
||||
}
|
||||
|
||||
pos := ch - '+';
|
||||
pos := ch - '+'
|
||||
if RADIX_TABLE_REVERSE_SIZE <= pos {
|
||||
break;
|
||||
break
|
||||
}
|
||||
y := RADIX_TABLE_REVERSE[pos];
|
||||
y := RADIX_TABLE_REVERSE[pos]
|
||||
/* if the char was found in the map
|
||||
* and is less than the given radix add it
|
||||
* to the number, otherwise exit the loop.
|
||||
*/
|
||||
if y >= u8(radix) {
|
||||
break;
|
||||
break
|
||||
}
|
||||
|
||||
internal_mul(res, res, DIGIT(radix)) or_return;
|
||||
internal_add(res, res, DIGIT(y)) or_return;
|
||||
internal_mul(res, res, DIGIT(radix)) or_return
|
||||
internal_add(res, res, DIGIT(y)) or_return
|
||||
|
||||
input = input[1:];
|
||||
input = input[1:]
|
||||
}
|
||||
/*
|
||||
If an illegal character was found, fail.
|
||||
*/
|
||||
if len(input) > 0 && ch != 0 && ch != '\r' && ch != '\n' {
|
||||
return .Invalid_Argument;
|
||||
return .Invalid_Argument
|
||||
}
|
||||
/*
|
||||
Set the sign only if res != 0.
|
||||
*/
|
||||
if res.used > 0 {
|
||||
res.sign = sign;
|
||||
res.sign = sign
|
||||
}
|
||||
|
||||
return nil;
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
atoi :: proc { int_atoi, };
|
||||
atoi :: proc { int_atoi, }
|
||||
|
||||
/*
|
||||
We size for `string` by default.
|
||||
*/
|
||||
radix_size :: proc(a: ^Int, radix: i8, zero_terminate := false, allocator := context.allocator) -> (size: int, err: Error) {
|
||||
a := a;
|
||||
assert_if_nil(a);
|
||||
a := a
|
||||
assert_if_nil(a)
|
||||
|
||||
if radix < 2 || radix > 64 { return -1, .Invalid_Argument; }
|
||||
clear_if_uninitialized(a) or_return;
|
||||
clear_if_uninitialized(a) or_return
|
||||
|
||||
if internal_is_zero(a) {
|
||||
if zero_terminate {
|
||||
return 2, nil;
|
||||
return 2, nil
|
||||
}
|
||||
return 1, nil;
|
||||
return 1, nil
|
||||
}
|
||||
|
||||
if internal_is_power_of_two(a) {
|
||||
@@ -345,37 +345,37 @@ radix_size :: proc(a: ^Int, radix: i8, zero_terminate := false, allocator := con
|
||||
used = a.used,
|
||||
sign = .Zero_or_Positive,
|
||||
digit = a.digit,
|
||||
};
|
||||
}
|
||||
|
||||
size = internal_log(t, DIGIT(radix)) or_return;
|
||||
size = internal_log(t, DIGIT(radix)) or_return
|
||||
} else {
|
||||
la, k := &Int{}, &Int{};
|
||||
defer internal_destroy(la, k);
|
||||
la, k := &Int{}, &Int{}
|
||||
defer internal_destroy(la, k)
|
||||
|
||||
/* la = floor(log_2(a)) + 1 */
|
||||
bit_count := internal_count_bits(a);
|
||||
internal_set(la, bit_count) or_return;
|
||||
bit_count := internal_count_bits(a)
|
||||
internal_set(la, bit_count) or_return
|
||||
|
||||
/* k = floor(2^29/log_2(radix)) + 1 */
|
||||
lb := _log_bases;
|
||||
internal_set(k, lb[radix]) or_return;
|
||||
lb := _log_bases
|
||||
internal_set(k, lb[radix]) or_return
|
||||
|
||||
/* n = floor((la * k) / 2^29) + 1 */
|
||||
internal_mul(k, la, k) or_return;
|
||||
internal_shr(k, k, _RADIX_SIZE_SCALE) or_return;
|
||||
internal_mul(k, la, k) or_return
|
||||
internal_shr(k, k, _RADIX_SIZE_SCALE) or_return
|
||||
|
||||
/* The "+1" here is the "+1" in "floor((la * k) / 2^29) + 1" */
|
||||
/* n = n + 1 + EOS + sign */
|
||||
size_, _ := internal_get(k, u128);
|
||||
size = int(size_);
|
||||
size_, _ := internal_get(k, u128)
|
||||
size = int(size_)
|
||||
}
|
||||
|
||||
/*
|
||||
log truncates to zero, so we need to add one more, and one for `-` if negative.
|
||||
*/
|
||||
size += 2 if a.sign == .Negative else 1;
|
||||
size += 1 if zero_terminate else 0;
|
||||
return size, nil;
|
||||
size += 2 if a.sign == .Negative else 1
|
||||
size += 1 if zero_terminate else 0
|
||||
return size, nil
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -392,7 +392,7 @@ radix_size :: proc(a: ^Int, radix: i8, zero_terminate := false, allocator := con
|
||||
for 64 bit "int".
|
||||
*/
|
||||
|
||||
_RADIX_SIZE_SCALE :: 29;
|
||||
_RADIX_SIZE_SCALE :: 29
|
||||
_log_bases :: [65]u32{
|
||||
0, 0, 0x20000001, 0x14309399, 0x10000001,
|
||||
0xdc81a35, 0xc611924, 0xb660c9e, 0xaaaaaab, 0xa1849cd,
|
||||
@@ -407,12 +407,12 @@ _log_bases :: [65]u32{
|
||||
0x5ab7d68, 0x5a42df0, 0x59d1506, 0x5962ffe, 0x58f7c57,
|
||||
0x588f7bc, 0x582a000, 0x57c7319, 0x5766f1d, 0x5709243,
|
||||
0x56adad9, 0x565474d, 0x55fd61f, 0x55a85e8, 0x5555556,
|
||||
};
|
||||
}
|
||||
|
||||
/*
|
||||
Characters used in radix conversions.
|
||||
*/
|
||||
RADIX_TABLE := "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz+/";
|
||||
RADIX_TABLE := "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz+/"
|
||||
RADIX_TABLE_REVERSE := [RADIX_TABLE_REVERSE_SIZE]u8{
|
||||
0x3e, 0xff, 0xff, 0xff, 0x3f, 0x00, 0x01, 0x02, 0x03, 0x04, /* +,-./01234 */
|
||||
0x05, 0x06, 0x07, 0x08, 0x09, 0xff, 0xff, 0xff, 0xff, 0xff, /* 56789:;<=> */
|
||||
@@ -422,59 +422,59 @@ RADIX_TABLE_REVERSE := [RADIX_TABLE_REVERSE_SIZE]u8{
|
||||
0xff, 0xff, 0xff, 0xff, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, /* ]^_`abcdef */
|
||||
0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, /* ghijklmnop */
|
||||
0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, /* qrstuvwxyz */
|
||||
};
|
||||
RADIX_TABLE_REVERSE_SIZE :: 80;
|
||||
}
|
||||
RADIX_TABLE_REVERSE_SIZE :: 80
|
||||
|
||||
/*
|
||||
Stores a bignum as a ASCII string in a given radix (2..64)
|
||||
The buffer must be appropriately sized. This routine doesn't check.
|
||||
*/
|
||||
_itoa_raw_full :: proc(a: ^Int, radix: i8, buffer: []u8, zero_terminate := false, allocator := context.allocator) -> (written: int, err: Error) {
|
||||
assert_if_nil(a);
|
||||
context.allocator = allocator;
|
||||
assert_if_nil(a)
|
||||
context.allocator = allocator
|
||||
|
||||
temp, denominator := &Int{}, &Int{};
|
||||
temp, denominator := &Int{}, &Int{}
|
||||
|
||||
internal_copy(temp, a) or_return;
|
||||
internal_set(denominator, radix) or_return;
|
||||
internal_copy(temp, a) or_return
|
||||
internal_set(denominator, radix) or_return
|
||||
|
||||
available := len(buffer);
|
||||
available := len(buffer)
|
||||
if zero_terminate {
|
||||
available -= 1;
|
||||
buffer[available] = 0;
|
||||
available -= 1
|
||||
buffer[available] = 0
|
||||
}
|
||||
|
||||
if a.sign == .Negative {
|
||||
temp.sign = .Zero_or_Positive;
|
||||
temp.sign = .Zero_or_Positive
|
||||
}
|
||||
|
||||
remainder: DIGIT;
|
||||
remainder: DIGIT
|
||||
for {
|
||||
if remainder, err = #force_inline internal_divmod(temp, temp, DIGIT(radix)); err != nil {
|
||||
internal_destroy(temp, denominator);
|
||||
return len(buffer) - available, err;
|
||||
internal_destroy(temp, denominator)
|
||||
return len(buffer) - available, err
|
||||
}
|
||||
available -= 1;
|
||||
buffer[available] = RADIX_TABLE[remainder];
|
||||
available -= 1
|
||||
buffer[available] = RADIX_TABLE[remainder]
|
||||
if temp.used == 0 {
|
||||
break;
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if a.sign == .Negative {
|
||||
available -= 1;
|
||||
buffer[available] = '-';
|
||||
available -= 1
|
||||
buffer[available] = '-'
|
||||
}
|
||||
|
||||
internal_destroy(temp, denominator);
|
||||
internal_destroy(temp, denominator)
|
||||
|
||||
/*
|
||||
If we overestimated the size, we need to move the buffer left.
|
||||
*/
|
||||
written = len(buffer) - available;
|
||||
written = len(buffer) - available
|
||||
if written < len(buffer) {
|
||||
diff := len(buffer) - written;
|
||||
mem.copy(&buffer[0], &buffer[diff], written);
|
||||
diff := len(buffer) - written
|
||||
mem.copy(&buffer[0], &buffer[diff], written)
|
||||
}
|
||||
return written, nil;
|
||||
return written, nil
|
||||
}
|
||||
+137
-137
@@ -25,24 +25,24 @@ PyRes :: struct {
|
||||
}
|
||||
|
||||
@export test_initialize_constants :: proc "c" () -> (res: u64) {
|
||||
context = runtime.default_context();
|
||||
res = u64(initialize_constants());
|
||||
context = runtime.default_context()
|
||||
res = u64(initialize_constants())
|
||||
//assert(MUL_KARATSUBA_CUTOFF >= 40);
|
||||
return res;
|
||||
return res
|
||||
}
|
||||
|
||||
@export test_error_string :: proc "c" (err: Error) -> (res: cstring) {
|
||||
context = runtime.default_context();
|
||||
es := Error_String;
|
||||
return strings.clone_to_cstring(es[err], context.temp_allocator);
|
||||
context = runtime.default_context()
|
||||
es := Error_String
|
||||
return strings.clone_to_cstring(es[err], context.temp_allocator)
|
||||
}
|
||||
|
||||
@export test_add :: proc "c" (a, b: cstring) -> (res: PyRes) {
|
||||
context = runtime.default_context();
|
||||
err: Error;
|
||||
context = runtime.default_context()
|
||||
err: Error
|
||||
|
||||
aa, bb, sum := &Int{}, &Int{}, &Int{};
|
||||
defer internal_destroy(aa, bb, sum);
|
||||
aa, bb, sum := &Int{}, &Int{}, &Int{}
|
||||
defer internal_destroy(aa, bb, sum)
|
||||
|
||||
if err = atoi(aa, string(a), 16); err != nil { return PyRes{res=":add:atoi(a):", err=err}; }
|
||||
if err = atoi(bb, string(b), 16); err != nil { return PyRes{res=":add:atoi(b):", err=err}; }
|
||||
@@ -52,18 +52,18 @@ PyRes :: struct {
|
||||
if err = #force_inline internal_add(sum, aa, bb); err != nil { return PyRes{res=":add:add(sum,a,b):", err=err}; }
|
||||
}
|
||||
|
||||
r: cstring;
|
||||
r, err = int_itoa_cstring(sum, 16, context.temp_allocator);
|
||||
r: cstring
|
||||
r, err = int_itoa_cstring(sum, 16, context.temp_allocator)
|
||||
if err != nil { return PyRes{res=":add:itoa(sum):", err=err}; }
|
||||
return PyRes{res = r, err = nil};
|
||||
return PyRes{res = r, err = nil}
|
||||
}
|
||||
|
||||
@export test_sub :: proc "c" (a, b: cstring) -> (res: PyRes) {
|
||||
context = runtime.default_context();
|
||||
err: Error;
|
||||
context = runtime.default_context()
|
||||
err: Error
|
||||
|
||||
aa, bb, sum := &Int{}, &Int{}, &Int{};
|
||||
defer internal_destroy(aa, bb, sum);
|
||||
aa, bb, sum := &Int{}, &Int{}, &Int{}
|
||||
defer internal_destroy(aa, bb, sum)
|
||||
|
||||
if err = atoi(aa, string(a), 16); err != nil { return PyRes{res=":sub:atoi(a):", err=err}; }
|
||||
if err = atoi(bb, string(b), 16); err != nil { return PyRes{res=":sub:atoi(b):", err=err}; }
|
||||
@@ -73,63 +73,63 @@ PyRes :: struct {
|
||||
if err = #force_inline internal_sub(sum, aa, bb); err != nil { return PyRes{res=":sub:sub(sum,a,b):", err=err}; }
|
||||
}
|
||||
|
||||
r: cstring;
|
||||
r, err = int_itoa_cstring(sum, 16, context.temp_allocator);
|
||||
r: cstring
|
||||
r, err = int_itoa_cstring(sum, 16, context.temp_allocator)
|
||||
if err != nil { return PyRes{res=":sub:itoa(sum):", err=err}; }
|
||||
return PyRes{res = r, err = nil};
|
||||
return PyRes{res = r, err = nil}
|
||||
}
|
||||
|
||||
@export test_mul :: proc "c" (a, b: cstring) -> (res: PyRes) {
|
||||
context = runtime.default_context();
|
||||
err: Error;
|
||||
context = runtime.default_context()
|
||||
err: Error
|
||||
|
||||
aa, bb, product := &Int{}, &Int{}, &Int{};
|
||||
defer internal_destroy(aa, bb, product);
|
||||
aa, bb, product := &Int{}, &Int{}, &Int{}
|
||||
defer internal_destroy(aa, bb, product)
|
||||
|
||||
if err = atoi(aa, string(a), 16); err != nil { return PyRes{res=":mul:atoi(a):", err=err}; }
|
||||
if err = atoi(bb, string(b), 16); err != nil { return PyRes{res=":mul:atoi(b):", err=err}; }
|
||||
if err = #force_inline internal_mul(product, aa, bb); err != nil { return PyRes{res=":mul:mul(product,a,b):", err=err}; }
|
||||
|
||||
r: cstring;
|
||||
r, err = int_itoa_cstring(product, 16, context.temp_allocator);
|
||||
r: cstring
|
||||
r, err = int_itoa_cstring(product, 16, context.temp_allocator)
|
||||
if err != nil { return PyRes{res=":mul:itoa(product):", err=err}; }
|
||||
return PyRes{res = r, err = nil};
|
||||
return PyRes{res = r, err = nil}
|
||||
}
|
||||
|
||||
@export test_sqr :: proc "c" (a: cstring) -> (res: PyRes) {
|
||||
context = runtime.default_context();
|
||||
err: Error;
|
||||
context = runtime.default_context()
|
||||
err: Error
|
||||
|
||||
aa, square := &Int{}, &Int{};
|
||||
defer internal_destroy(aa, square);
|
||||
aa, square := &Int{}, &Int{}
|
||||
defer internal_destroy(aa, square)
|
||||
|
||||
if err = atoi(aa, string(a), 16); err != nil { return PyRes{res=":sqr:atoi(a):", err=err}; }
|
||||
if err = #force_inline internal_sqr(square, aa); err != nil { return PyRes{res=":sqr:sqr(square,a):", err=err}; }
|
||||
|
||||
r: cstring;
|
||||
r, err = int_itoa_cstring(square, 16, context.temp_allocator);
|
||||
r: cstring
|
||||
r, err = int_itoa_cstring(square, 16, context.temp_allocator)
|
||||
if err != nil { return PyRes{res=":sqr:itoa(square):", err=err}; }
|
||||
return PyRes{res = r, err = nil};
|
||||
return PyRes{res = r, err = nil}
|
||||
}
|
||||
|
||||
/*
|
||||
NOTE(Jeroen): For simplicity, we don't return the quotient and the remainder, just the quotient.
|
||||
*/
|
||||
@export test_div :: proc "c" (a, b: cstring) -> (res: PyRes) {
|
||||
context = runtime.default_context();
|
||||
err: Error;
|
||||
context = runtime.default_context()
|
||||
err: Error
|
||||
|
||||
aa, bb, quotient := &Int{}, &Int{}, &Int{};
|
||||
defer internal_destroy(aa, bb, quotient);
|
||||
aa, bb, quotient := &Int{}, &Int{}, &Int{}
|
||||
defer internal_destroy(aa, bb, quotient)
|
||||
|
||||
if err = atoi(aa, string(a), 16); err != nil { return PyRes{res=":div:atoi(a):", err=err}; }
|
||||
if err = atoi(bb, string(b), 16); err != nil { return PyRes{res=":div:atoi(b):", err=err}; }
|
||||
if err = #force_inline internal_div(quotient, aa, bb); err != nil { return PyRes{res=":div:div(quotient,a,b):", err=err}; }
|
||||
|
||||
r: cstring;
|
||||
r, err = int_itoa_cstring(quotient, 16, context.temp_allocator);
|
||||
r: cstring
|
||||
r, err = int_itoa_cstring(quotient, 16, context.temp_allocator)
|
||||
if err != nil { return PyRes{res=":div:itoa(quotient):", err=err}; }
|
||||
return PyRes{res = r, err = nil};
|
||||
return PyRes{res = r, err = nil}
|
||||
}
|
||||
|
||||
|
||||
@@ -137,254 +137,254 @@ PyRes :: struct {
|
||||
res = log(a, base)
|
||||
*/
|
||||
@export test_log :: proc "c" (a: cstring, base := DIGIT(2)) -> (res: PyRes) {
|
||||
context = runtime.default_context();
|
||||
err: Error;
|
||||
l: int;
|
||||
context = runtime.default_context()
|
||||
err: Error
|
||||
l: int
|
||||
|
||||
aa := &Int{};
|
||||
defer internal_destroy(aa);
|
||||
aa := &Int{}
|
||||
defer internal_destroy(aa)
|
||||
|
||||
if err = atoi(aa, string(a), 16); err != nil { return PyRes{res=":log:atoi(a):", err=err}; }
|
||||
if l, err = #force_inline internal_log(aa, base); err != nil { return PyRes{res=":log:log(a, base):", err=err}; }
|
||||
|
||||
#force_inline internal_zero(aa);
|
||||
aa.digit[0] = DIGIT(l) & _MASK;
|
||||
aa.digit[1] = DIGIT(l) >> _DIGIT_BITS;
|
||||
aa.used = 2;
|
||||
clamp(aa);
|
||||
aa.digit[0] = DIGIT(l) & _MASK
|
||||
aa.digit[1] = DIGIT(l) >> _DIGIT_BITS
|
||||
aa.used = 2
|
||||
clamp(aa)
|
||||
|
||||
r: cstring;
|
||||
r, err = int_itoa_cstring(aa, 16, context.temp_allocator);
|
||||
r: cstring
|
||||
r, err = int_itoa_cstring(aa, 16, context.temp_allocator)
|
||||
if err != nil { return PyRes{res=":log:itoa(res):", err=err}; }
|
||||
return PyRes{res = r, err = nil};
|
||||
return PyRes{res = r, err = nil}
|
||||
}
|
||||
|
||||
/*
|
||||
dest = base^power
|
||||
*/
|
||||
@export test_pow :: proc "c" (base: cstring, power := int(2)) -> (res: PyRes) {
|
||||
context = runtime.default_context();
|
||||
err: Error;
|
||||
context = runtime.default_context()
|
||||
err: Error
|
||||
|
||||
dest, bb := &Int{}, &Int{};
|
||||
defer internal_destroy(dest, bb);
|
||||
dest, bb := &Int{}, &Int{}
|
||||
defer internal_destroy(dest, bb)
|
||||
|
||||
if err = atoi(bb, string(base), 16); err != nil { return PyRes{res=":pow:atoi(base):", err=err}; }
|
||||
if err = #force_inline internal_pow(dest, bb, power); err != nil { return PyRes{res=":pow:pow(dest, base, power):", err=err}; }
|
||||
|
||||
r: cstring;
|
||||
r, err = int_itoa_cstring(dest, 16, context.temp_allocator);
|
||||
r: cstring
|
||||
r, err = int_itoa_cstring(dest, 16, context.temp_allocator)
|
||||
if err != nil { return PyRes{res=":log:itoa(res):", err=err}; }
|
||||
return PyRes{res = r, err = nil};
|
||||
return PyRes{res = r, err = nil}
|
||||
}
|
||||
|
||||
/*
|
||||
dest = sqrt(src)
|
||||
*/
|
||||
@export test_sqrt :: proc "c" (source: cstring) -> (res: PyRes) {
|
||||
context = runtime.default_context();
|
||||
err: Error;
|
||||
context = runtime.default_context()
|
||||
err: Error
|
||||
|
||||
src := &Int{};
|
||||
defer internal_destroy(src);
|
||||
src := &Int{}
|
||||
defer internal_destroy(src)
|
||||
|
||||
if err = atoi(src, string(source), 16); err != nil { return PyRes{res=":sqrt:atoi(src):", err=err}; }
|
||||
if err = #force_inline internal_sqrt(src, src); err != nil { return PyRes{res=":sqrt:sqrt(src):", err=err}; }
|
||||
|
||||
r: cstring;
|
||||
r, err = int_itoa_cstring(src, 16, context.temp_allocator);
|
||||
r: cstring
|
||||
r, err = int_itoa_cstring(src, 16, context.temp_allocator)
|
||||
if err != nil { return PyRes{res=":log:itoa(res):", err=err}; }
|
||||
return PyRes{res = r, err = nil};
|
||||
return PyRes{res = r, err = nil}
|
||||
}
|
||||
|
||||
/*
|
||||
dest = root_n(src, power)
|
||||
*/
|
||||
@export test_root_n :: proc "c" (source: cstring, power: int) -> (res: PyRes) {
|
||||
context = runtime.default_context();
|
||||
err: Error;
|
||||
context = runtime.default_context()
|
||||
err: Error
|
||||
|
||||
src := &Int{};
|
||||
defer internal_destroy(src);
|
||||
src := &Int{}
|
||||
defer internal_destroy(src)
|
||||
|
||||
if err = atoi(src, string(source), 16); err != nil { return PyRes{res=":root_n:atoi(src):", err=err}; }
|
||||
if err = #force_inline internal_root_n(src, src, power); err != nil { return PyRes{res=":root_n:root_n(src):", err=err}; }
|
||||
|
||||
r: cstring;
|
||||
r, err = int_itoa_cstring(src, 16, context.temp_allocator);
|
||||
r: cstring
|
||||
r, err = int_itoa_cstring(src, 16, context.temp_allocator)
|
||||
if err != nil { return PyRes{res=":root_n:itoa(res):", err=err}; }
|
||||
return PyRes{res = r, err = nil};
|
||||
return PyRes{res = r, err = nil}
|
||||
}
|
||||
|
||||
/*
|
||||
dest = shr_digit(src, digits)
|
||||
*/
|
||||
@export test_shr_digit :: proc "c" (source: cstring, digits: int) -> (res: PyRes) {
|
||||
context = runtime.default_context();
|
||||
err: Error;
|
||||
context = runtime.default_context()
|
||||
err: Error
|
||||
|
||||
src := &Int{};
|
||||
defer internal_destroy(src);
|
||||
src := &Int{}
|
||||
defer internal_destroy(src)
|
||||
|
||||
if err = atoi(src, string(source), 16); err != nil { return PyRes{res=":shr_digit:atoi(src):", err=err}; }
|
||||
if err = #force_inline internal_shr_digit(src, digits); err != nil { return PyRes{res=":shr_digit:shr_digit(src):", err=err}; }
|
||||
|
||||
r: cstring;
|
||||
r, err = int_itoa_cstring(src, 16, context.temp_allocator);
|
||||
r: cstring
|
||||
r, err = int_itoa_cstring(src, 16, context.temp_allocator)
|
||||
if err != nil { return PyRes{res=":shr_digit:itoa(res):", err=err}; }
|
||||
return PyRes{res = r, err = nil};
|
||||
return PyRes{res = r, err = nil}
|
||||
}
|
||||
|
||||
/*
|
||||
dest = shl_digit(src, digits)
|
||||
*/
|
||||
@export test_shl_digit :: proc "c" (source: cstring, digits: int) -> (res: PyRes) {
|
||||
context = runtime.default_context();
|
||||
err: Error;
|
||||
context = runtime.default_context()
|
||||
err: Error
|
||||
|
||||
src := &Int{};
|
||||
defer internal_destroy(src);
|
||||
src := &Int{}
|
||||
defer internal_destroy(src)
|
||||
|
||||
if err = atoi(src, string(source), 16); err != nil { return PyRes{res=":shl_digit:atoi(src):", err=err}; }
|
||||
if err = #force_inline internal_shl_digit(src, digits); err != nil { return PyRes{res=":shl_digit:shr_digit(src):", err=err}; }
|
||||
|
||||
r: cstring;
|
||||
r, err = int_itoa_cstring(src, 16, context.temp_allocator);
|
||||
r: cstring
|
||||
r, err = int_itoa_cstring(src, 16, context.temp_allocator)
|
||||
if err != nil { return PyRes{res=":shl_digit:itoa(res):", err=err}; }
|
||||
return PyRes{res = r, err = nil};
|
||||
return PyRes{res = r, err = nil}
|
||||
}
|
||||
|
||||
/*
|
||||
dest = shr(src, bits)
|
||||
*/
|
||||
@export test_shr :: proc "c" (source: cstring, bits: int) -> (res: PyRes) {
|
||||
context = runtime.default_context();
|
||||
err: Error;
|
||||
context = runtime.default_context()
|
||||
err: Error
|
||||
|
||||
src := &Int{};
|
||||
defer internal_destroy(src);
|
||||
src := &Int{}
|
||||
defer internal_destroy(src)
|
||||
|
||||
if err = atoi(src, string(source), 16); err != nil { return PyRes{res=":shr:atoi(src):", err=err}; }
|
||||
if err = #force_inline internal_shr(src, src, bits); err != nil { return PyRes{res=":shr:shr(src, bits):", err=err}; }
|
||||
|
||||
r: cstring;
|
||||
r, err = int_itoa_cstring(src, 16, context.temp_allocator);
|
||||
r: cstring
|
||||
r, err = int_itoa_cstring(src, 16, context.temp_allocator)
|
||||
if err != nil { return PyRes{res=":shr:itoa(res):", err=err}; }
|
||||
return PyRes{res = r, err = nil};
|
||||
return PyRes{res = r, err = nil}
|
||||
}
|
||||
|
||||
/*
|
||||
dest = shr_signed(src, bits)
|
||||
*/
|
||||
@export test_shr_signed :: proc "c" (source: cstring, bits: int) -> (res: PyRes) {
|
||||
context = runtime.default_context();
|
||||
err: Error;
|
||||
context = runtime.default_context()
|
||||
err: Error
|
||||
|
||||
src := &Int{};
|
||||
defer internal_destroy(src);
|
||||
src := &Int{}
|
||||
defer internal_destroy(src)
|
||||
|
||||
if err = atoi(src, string(source), 16); err != nil { return PyRes{res=":shr_signed:atoi(src):", err=err}; }
|
||||
if err = #force_inline internal_shr_signed(src, src, bits); err != nil { return PyRes{res=":shr_signed:shr_signed(src, bits):", err=err}; }
|
||||
|
||||
r: cstring;
|
||||
r, err = int_itoa_cstring(src, 16, context.temp_allocator);
|
||||
r: cstring
|
||||
r, err = int_itoa_cstring(src, 16, context.temp_allocator)
|
||||
if err != nil { return PyRes{res=":shr_signed:itoa(res):", err=err}; }
|
||||
return PyRes{res = r, err = nil};
|
||||
return PyRes{res = r, err = nil}
|
||||
}
|
||||
|
||||
/*
|
||||
dest = shl(src, bits)
|
||||
*/
|
||||
@export test_shl :: proc "c" (source: cstring, bits: int) -> (res: PyRes) {
|
||||
context = runtime.default_context();
|
||||
err: Error;
|
||||
context = runtime.default_context()
|
||||
err: Error
|
||||
|
||||
src := &Int{};
|
||||
defer internal_destroy(src);
|
||||
src := &Int{}
|
||||
defer internal_destroy(src)
|
||||
|
||||
if err = atoi(src, string(source), 16); err != nil { return PyRes{res=":shl:atoi(src):", err=err}; }
|
||||
if err = #force_inline internal_shl(src, src, bits); err != nil { return PyRes{res=":shl:shl(src, bits):", err=err}; }
|
||||
|
||||
r: cstring;
|
||||
r, err = int_itoa_cstring(src, 16, context.temp_allocator);
|
||||
r: cstring
|
||||
r, err = int_itoa_cstring(src, 16, context.temp_allocator)
|
||||
if err != nil { return PyRes{res=":shl:itoa(res):", err=err}; }
|
||||
return PyRes{res = r, err = nil};
|
||||
return PyRes{res = r, err = nil}
|
||||
}
|
||||
|
||||
/*
|
||||
dest = factorial(n)
|
||||
*/
|
||||
@export test_factorial :: proc "c" (n: int) -> (res: PyRes) {
|
||||
context = runtime.default_context();
|
||||
err: Error;
|
||||
context = runtime.default_context()
|
||||
err: Error
|
||||
|
||||
dest := &Int{};
|
||||
defer internal_destroy(dest);
|
||||
dest := &Int{}
|
||||
defer internal_destroy(dest)
|
||||
|
||||
if err = #force_inline internal_int_factorial(dest, n); err != nil { return PyRes{res=":factorial:factorial(n):", err=err}; }
|
||||
|
||||
r: cstring;
|
||||
r, err = int_itoa_cstring(dest, 16, context.temp_allocator);
|
||||
r: cstring
|
||||
r, err = int_itoa_cstring(dest, 16, context.temp_allocator)
|
||||
if err != nil { return PyRes{res=":factorial:itoa(res):", err=err}; }
|
||||
return PyRes{res = r, err = nil};
|
||||
return PyRes{res = r, err = nil}
|
||||
}
|
||||
|
||||
/*
|
||||
dest = gcd(a, b)
|
||||
*/
|
||||
@export test_gcd :: proc "c" (a, b: cstring) -> (res: PyRes) {
|
||||
context = runtime.default_context();
|
||||
err: Error;
|
||||
context = runtime.default_context()
|
||||
err: Error
|
||||
|
||||
ai, bi, dest := &Int{}, &Int{}, &Int{};
|
||||
defer internal_destroy(ai, bi, dest);
|
||||
ai, bi, dest := &Int{}, &Int{}, &Int{}
|
||||
defer internal_destroy(ai, bi, dest)
|
||||
|
||||
if err = atoi(ai, string(a), 16); err != nil { return PyRes{res=":gcd:atoi(a):", err=err}; }
|
||||
if err = atoi(bi, string(b), 16); err != nil { return PyRes{res=":gcd:atoi(b):", err=err}; }
|
||||
if err = #force_inline internal_int_gcd_lcm(dest, nil, ai, bi); err != nil { return PyRes{res=":gcd:gcd(a, b):", err=err}; }
|
||||
|
||||
r: cstring;
|
||||
r, err = int_itoa_cstring(dest, 16, context.temp_allocator);
|
||||
r: cstring
|
||||
r, err = int_itoa_cstring(dest, 16, context.temp_allocator)
|
||||
if err != nil { return PyRes{res=":gcd:itoa(res):", err=err}; }
|
||||
return PyRes{res = r, err = nil};
|
||||
return PyRes{res = r, err = nil}
|
||||
}
|
||||
|
||||
/*
|
||||
dest = lcm(a, b)
|
||||
*/
|
||||
@export test_lcm :: proc "c" (a, b: cstring) -> (res: PyRes) {
|
||||
context = runtime.default_context();
|
||||
err: Error;
|
||||
context = runtime.default_context()
|
||||
err: Error
|
||||
|
||||
ai, bi, dest := &Int{}, &Int{}, &Int{};
|
||||
defer internal_destroy(ai, bi, dest);
|
||||
ai, bi, dest := &Int{}, &Int{}, &Int{}
|
||||
defer internal_destroy(ai, bi, dest)
|
||||
|
||||
if err = atoi(ai, string(a), 16); err != nil { return PyRes{res=":lcm:atoi(a):", err=err}; }
|
||||
if err = atoi(bi, string(b), 16); err != nil { return PyRes{res=":lcm:atoi(b):", err=err}; }
|
||||
if err = #force_inline internal_int_gcd_lcm(nil, dest, ai, bi); err != nil { return PyRes{res=":lcm:lcm(a, b):", err=err}; }
|
||||
|
||||
r: cstring;
|
||||
r, err = int_itoa_cstring(dest, 16, context.temp_allocator);
|
||||
r: cstring
|
||||
r, err = int_itoa_cstring(dest, 16, context.temp_allocator)
|
||||
if err != nil { return PyRes{res=":lcm:itoa(res):", err=err}; }
|
||||
return PyRes{res = r, err = nil};
|
||||
return PyRes{res = r, err = nil}
|
||||
}
|
||||
|
||||
/*
|
||||
dest = lcm(a, b)
|
||||
*/
|
||||
@export test_is_square :: proc "c" (a: cstring) -> (res: PyRes) {
|
||||
context = runtime.default_context();
|
||||
err: Error;
|
||||
square: bool;
|
||||
context = runtime.default_context()
|
||||
err: Error
|
||||
square: bool
|
||||
|
||||
ai := &Int{};
|
||||
defer internal_destroy(ai);
|
||||
ai := &Int{}
|
||||
defer internal_destroy(ai)
|
||||
|
||||
if err = atoi(ai, string(a), 16); err != nil { return PyRes{res=":is_square:atoi(a):", err=err}; }
|
||||
if square, err = #force_inline internal_int_is_square(ai); err != nil { return PyRes{res=":is_square:is_square(a):", err=err}; }
|
||||
|
||||
if square {
|
||||
return PyRes{"True", nil};
|
||||
return PyRes{"True", nil}
|
||||
}
|
||||
return PyRes{"False", nil};
|
||||
return PyRes{"False", nil}
|
||||
}
|
||||
+19
-19
@@ -24,58 +24,58 @@ Category :: enum {
|
||||
sqr,
|
||||
bitfield_extract,
|
||||
rm_trials,
|
||||
};
|
||||
}
|
||||
|
||||
Event :: struct {
|
||||
ticks: time.Duration,
|
||||
count: int,
|
||||
cycles: u64,
|
||||
}
|
||||
Timings := [Category]Event{};
|
||||
Timings := [Category]Event{}
|
||||
|
||||
print_timings :: proc() {
|
||||
duration :: proc(d: time.Duration) -> (res: string) {
|
||||
switch {
|
||||
case d < time.Microsecond:
|
||||
return fmt.tprintf("%v ns", time.duration_nanoseconds(d));
|
||||
return fmt.tprintf("%v ns", time.duration_nanoseconds(d))
|
||||
case d < time.Millisecond:
|
||||
return fmt.tprintf("%v µs", time.duration_microseconds(d));
|
||||
return fmt.tprintf("%v µs", time.duration_microseconds(d))
|
||||
case:
|
||||
return fmt.tprintf("%v ms", time.duration_milliseconds(d));
|
||||
return fmt.tprintf("%v ms", time.duration_milliseconds(d))
|
||||
}
|
||||
}
|
||||
|
||||
for v in Timings {
|
||||
if v.count > 0 {
|
||||
fmt.println("\nTimings:");
|
||||
break;
|
||||
fmt.println("\nTimings:")
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
for v, i in Timings {
|
||||
if v.count > 0 {
|
||||
avg_ticks := time.Duration(f64(v.ticks) / f64(v.count));
|
||||
avg_cycles := f64(v.cycles) / f64(v.count);
|
||||
avg_ticks := time.Duration(f64(v.ticks) / f64(v.count))
|
||||
avg_cycles := f64(v.cycles) / f64(v.count)
|
||||
|
||||
fmt.printf("\t%v: %s / %v cycles (avg), %s / %v cycles (total, %v calls)\n", i, duration(avg_ticks), avg_cycles, duration(v.ticks), v.cycles, v.count);
|
||||
fmt.printf("\t%v: %s / %v cycles (avg), %s / %v cycles (total, %v calls)\n", i, duration(avg_ticks), avg_cycles, duration(v.ticks), v.cycles, v.count)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@(deferred_in_out=_SCOPE_END)
|
||||
SCOPED_TIMING :: #force_inline proc(c: Category) -> (ticks: time.Tick, cycles: u64) {
|
||||
cycles = time.read_cycle_counter();
|
||||
ticks = time.tick_now();
|
||||
return;
|
||||
cycles = time.read_cycle_counter()
|
||||
ticks = time.tick_now()
|
||||
return
|
||||
}
|
||||
_SCOPE_END :: #force_inline proc(c: Category, ticks: time.Tick, cycles: u64) {
|
||||
cycles_now := time.read_cycle_counter();
|
||||
ticks_now := time.tick_now();
|
||||
cycles_now := time.read_cycle_counter()
|
||||
ticks_now := time.tick_now()
|
||||
|
||||
Timings[c].ticks = time.tick_diff(ticks, ticks_now);
|
||||
Timings[c].cycles = cycles_now - cycles;
|
||||
Timings[c].count += 1;
|
||||
Timings[c].ticks = time.tick_diff(ticks, ticks_now)
|
||||
Timings[c].cycles = cycles_now - cycles
|
||||
Timings[c].count += 1
|
||||
}
|
||||
SCOPED_COUNT_ADD :: #force_inline proc(c: Category, count: int) {
|
||||
Timings[c].count += count;
|
||||
Timings[c].count += count
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user