mirror of
https://github.com/Ed94/Odin.git
synced 2026-08-06 23:58:50 +00:00
Add internal_int_(pack, unpack).
This commit is contained in:
@@ -431,6 +431,117 @@ internal_int_write_to_ascii_file :: proc(a: ^Int, filename: string, radix := i8(
|
||||
return nil if ok else .Cannot_Write_File;
|
||||
}
|
||||
|
||||
/*
|
||||
Calculate the size needed for `internal_int_pack`.
|
||||
|
||||
See https://gmplib.org/manual/Integer-Import-and-Export.html
|
||||
*/
|
||||
internal_int_pack_count :: proc(a: ^Int, $T: typeid, nails := 0) -> (size_needed: int) {
|
||||
assert(nails >= 0 && nails < (size_of(T) * 8));
|
||||
|
||||
bits := internal_count_bits(a);
|
||||
size := size_of(T);
|
||||
|
||||
size_needed = bits / ((size * 8) - nails);
|
||||
size_needed += 1 if (bits % ((size * 8) - nails)) != 0 else 0;
|
||||
|
||||
return size_needed;
|
||||
}
|
||||
|
||||
/*
|
||||
Based on gmp's mpz_export.
|
||||
See https://gmplib.org/manual/Integer-Import-and-Export.html
|
||||
|
||||
`buf` is a pre-allocated slice of type `T` "words", which must be an unsigned integer of some description.
|
||||
Use `internal_int_pack_count(a, T, nails)` to calculate the necessary size.
|
||||
The library internally uses `DIGIT` as the type, which is u64 or u32 depending on the platform.
|
||||
You are of course welcome to export to []u8, []u32be, and so forth.
|
||||
After this you can use `mem.slice_data_cast` to interpret the buffer as bytes if you so choose.
|
||||
|
||||
`nails` are the number of top bits the output "word" reserves.
|
||||
To mimic the internals of this library, this would be 4.
|
||||
|
||||
To use the minimum amount of output bytes, set `nails` to 0 and pass a `[]u8`.
|
||||
IMPORTANT: `pack` serializes the magnitude of an Int, that is, the output is unsigned.
|
||||
|
||||
Assumes `a` not to be `nil` and to have been initialized.
|
||||
*/
|
||||
internal_int_pack :: proc(a: ^Int, buf: []$T, nails := 0, order := Order.LSB_First) -> (written: int, err: Error)
|
||||
where intrinsics.type_is_integer(T) && intrinsics.type_is_unsigned(T) && size_of(T) <= 16 {
|
||||
|
||||
assert(nails >= 0 && nails < (size_of(T) * 8));
|
||||
|
||||
type_size := size_of(T);
|
||||
type_bits := (type_size * 8) - nails;
|
||||
|
||||
word_count := internal_int_pack_count(a, T, nails);
|
||||
bit_count := internal_count_bits(a);
|
||||
|
||||
if len(buf) < word_count {
|
||||
return 0, .Buffer_Overflow;
|
||||
}
|
||||
|
||||
bit_offset := 0;
|
||||
word_offset := 0;
|
||||
|
||||
#no_bounds_check for i := 0; i < word_count; i += 1 {
|
||||
bit_offset = i * type_bits;
|
||||
if order == .MSB_First {
|
||||
word_offset = word_count - i - 1;
|
||||
} else {
|
||||
word_offset = i;
|
||||
}
|
||||
|
||||
bits_to_get := min(type_bits, bit_count - bit_offset);
|
||||
W := internal_int_bitfield_extract(a, bit_offset, bits_to_get) or_return;
|
||||
buf[word_offset] = T(W);
|
||||
}
|
||||
|
||||
return word_count, nil;
|
||||
}
|
||||
|
||||
|
||||
|
||||
internal_int_unpack :: proc(a: ^Int, buf: []$T, nails := 0, order := Order.LSB_First, allocator := context.allocator) -> (err: Error)
|
||||
where intrinsics.type_is_integer(T) && intrinsics.type_is_unsigned(T) && size_of(T) <= 16 {
|
||||
assert(nails >= 0 && nails < (size_of(T) * 8));
|
||||
context.allocator = allocator;
|
||||
|
||||
type_size := size_of(T);
|
||||
type_bits := (type_size * 8) - nails;
|
||||
type_mask := T(1 << uint(type_bits)) - 1;
|
||||
|
||||
if len(buf) == 0 {
|
||||
return .Invalid_Argument;
|
||||
}
|
||||
|
||||
bit_count := type_bits * len(buf);
|
||||
digit_count := (bit_count / _DIGIT_BITS) + min(1, bit_count % _DIGIT_BITS);
|
||||
|
||||
/*
|
||||
Pre-size output Int.
|
||||
*/
|
||||
internal_grow(a, digit_count) or_return;
|
||||
|
||||
t := &Int{};
|
||||
defer internal_destroy(t);
|
||||
|
||||
if order == .LSB_First {
|
||||
for W, i in buf {
|
||||
internal_set(t, W & type_mask) or_return;
|
||||
internal_shl(t, t, type_bits * i) or_return;
|
||||
internal_add(a, a, t) or_return;
|
||||
}
|
||||
} else {
|
||||
for W in buf {
|
||||
internal_set(t, W & type_mask) or_return;
|
||||
internal_shl(a, a, type_bits) or_return;
|
||||
internal_add(a, a, t) or_return;
|
||||
}
|
||||
}
|
||||
|
||||
return internal_clamp(a);
|
||||
}
|
||||
|
||||
/*
|
||||
Overestimate the size needed for the bigint to string conversion by a very small amount.
|
||||
|
||||
Reference in New Issue
Block a user