mirror of
https://github.com/Ed94/Odin.git
synced 2026-08-05 15:18:49 +00:00
bit: Improved bitfield extraction.
This commit is contained in:
+33
-61
@@ -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, e;
|
||||
} else {
|
||||
limb_lo := offset / _DIGIT_BITS;
|
||||
bits_lo := offset % _DIGIT_BITS;
|
||||
limb_hi := (offset + count) / _DIGIT_BITS;
|
||||
bits_hi := (offset + count) % _DIGIT_BITS;
|
||||
|
||||
if limb_lo < 0 || limb_lo >= a.used || limb_hi < 0 || limb_hi >= a.used {
|
||||
return 0, .Invalid_Argument;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
}
|
||||
return res, nil;
|
||||
}
|
||||
|
||||
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; }
|
||||
|
||||
for shift := 0; shift < count; shift += 1 {
|
||||
bit_offset := offset + shift;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
Reference in New Issue
Block a user