Remove unneeded semicolons from the core library

This commit is contained in:
gingerBill
2021-08-31 22:21:13 +01:00
parent b176af2742
commit 251da264ed
187 changed files with 27227 additions and 27227 deletions
+16 -16
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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)
}
}
File diff suppressed because it is too large Load Diff
+45 -45
View File
@@ -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
View File
@@ -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
View File
File diff suppressed because it is too large Load Diff
+175 -175
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
}