diff options
| author | Jeroen van Rijn <Kelimion@users.noreply.github.com> | 2021-08-04 21:25:38 +0200 |
|---|---|---|
| committer | Jeroen van Rijn <Kelimion@users.noreply.github.com> | 2021-08-11 20:59:53 +0200 |
| commit | 463003e86a96cf5cc0b05fc96d01f5118272911f (patch) | |
| tree | 69764855742bc3422300393c7a26cc607e9525c1 /core/math/big/helpers.odin | |
| parent | 85a2a8815e2ae06d23ec23224e00084e143363e2 (diff) | |
bit: Improved bitfield extraction.
Diffstat (limited to 'core/math/big/helpers.odin')
| -rw-r--r-- | core/math/big/helpers.odin | 86 |
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; } /* |