aboutsummaryrefslogtreecommitdiff
path: root/core/math/big/helpers.odin
diff options
context:
space:
mode:
authorJeroen van Rijn <Kelimion@users.noreply.github.com>2021-08-04 21:25:38 +0200
committerJeroen van Rijn <Kelimion@users.noreply.github.com>2021-08-11 20:59:53 +0200
commit463003e86a96cf5cc0b05fc96d01f5118272911f (patch)
tree69764855742bc3422300393c7a26cc607e9525c1 /core/math/big/helpers.odin
parent85a2a8815e2ae06d23ec23224e00084e143363e2 (diff)
bit: Improved bitfield extraction.
Diffstat (limited to 'core/math/big/helpers.odin')
-rw-r--r--core/math/big/helpers.odin86
1 files changed, 29 insertions, 57 deletions
diff --git a/core/math/big/helpers.odin b/core/math/big/helpers.odin
index 9217589db..f46509162 100644
--- a/core/math/big/helpers.odin
+++ b/core/math/big/helpers.odin
@@ -13,6 +13,8 @@ import "core:mem"
import "core:intrinsics"
import rnd "core:math/rand"
+// import "core:fmt"
+
/*
TODO: Int.flags and Constants like ONE, NAN, etc, are not yet properly handled everywhere.
*/
@@ -193,9 +195,7 @@ extract_bit :: proc(a: ^Int, bit_offset: int) -> (bit: DIGIT, err: Error) {
/*
Check that `a`is usable.
*/
- if err = clear_if_uninitialized(a); err != nil {
- return 0, err;
- }
+ if err = clear_if_uninitialized(a); err != nil { return 0, err; }
limb := bit_offset / _DIGIT_BITS;
if limb < 0 || limb >= a.used {
@@ -207,72 +207,44 @@ extract_bit :: proc(a: ^Int, bit_offset: int) -> (bit: DIGIT, err: Error) {
return 1 if ((a.digit[limb] & i) != 0) else 0, nil;
}
-/*
- TODO: Optimize.
-*/
int_bitfield_extract :: proc(a: ^Int, offset, count: int) -> (res: _WORD, err: Error) {
/*
- Check that `a`is usable.
+ Check that `a` is usable.
*/
- if err = clear_if_uninitialized(a); err != nil {
- return 0, err;
- }
+ if err = clear_if_uninitialized(a); err != nil { return 0, err; }
+ if count > _WORD_BITS || count < 1 { return 0, .Invalid_Argument; }
- if count > _WORD_BITS || count < 1 {
- return 0, .Invalid_Argument;
- }
+ for shift := 0; shift < count; shift += 1 {
+ bit_offset := offset + shift;
- when true {
- v: DIGIT;
- e: Error;
+ limb := bit_offset / _DIGIT_BITS;
+ mask := DIGIT(1 << DIGIT((bit_offset % _DIGIT_BITS)));
- for shift := 0; shift < count; shift += 1 {
- o := offset + shift;
- v, e = extract_bit(a, o);
- if e != nil {
- break;
- }
- res = res + _WORD(v) << uint(shift);
+ if (a.digit[limb] & mask) != 0 {
+ res += _WORD(1) << uint(shift);
}
+ }
+ return res, nil;
+}
- return res, e;
- } else {
- limb_lo := offset / _DIGIT_BITS;
- bits_lo := offset % _DIGIT_BITS;
- limb_hi := (offset + count) / _DIGIT_BITS;
- bits_hi := (offset + count) % _DIGIT_BITS;
+int_bitfield_extract_fast :: proc(a: ^Int, offset, count: int) -> (res: _WORD, err: Error) {
+ /*
+ Check that `a` is usable.
+ */
+ if err = clear_if_uninitialized(a); err != nil { return 0, err; }
+ if count > _WORD_BITS || count < 1 { return 0, .Invalid_Argument; }
- if limb_lo < 0 || limb_lo >= a.used || limb_hi < 0 || limb_hi >= a.used {
- return 0, .Invalid_Argument;
- }
+ for shift := 0; shift < count; shift += 1 {
+ bit_offset := offset + shift;
- for i := limb_hi; i >= limb_lo; i -= 1 {
- res <<= _DIGIT_BITS;
-
- /*
- Determine which bits to extract from each DIGIT. The whole DIGIT's worth by default.
- */
- bit_count := _DIGIT_BITS;
- bit_offset := 0;
- if i == limb_lo {
- bit_count -= bits_lo;
- bit_offset = _DIGIT_BITS - bit_count;
- } else if i == limb_hi {
- bit_count = bits_hi;
- bit_offset = 0;
- }
-
- d := a.digit[i];
-
- v := (d >> uint(bit_offset)) & DIGIT(1 << uint(bit_count - 1));
- m := DIGIT(1 << uint(bit_count-1));
- r := v & m;
-
- res |= _WORD(r);
- }
- return res, nil;
+ limb := bit_offset / _DIGIT_BITS;
+ mask := DIGIT(1 << DIGIT((bit_offset % _DIGIT_BITS)));
+ if (a.digit[limb] & mask) != 0 {
+ res += _WORD(1) << uint(shift);
+ }
}
+ return res, nil;
}
/*