const GHR_MAX_WORDS: usize = 16;
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub struct Ghr {
bits: [u64; GHR_MAX_WORDS],
len: u16,
}
impl Default for Ghr {
fn default() -> Self {
Self { bits: [0; GHR_MAX_WORDS], len: 0 }
}
}
impl Ghr {
pub fn with_len(max_bits: usize) -> Self {
assert!(
max_bits <= GHR_MAX_WORDS * 64,
"GHR: requested {max_bits} bits exceeds capacity of {} bits",
GHR_MAX_WORDS * 64,
);
Self { bits: [0; GHR_MAX_WORDS], len: max_bits as u16 }
}
#[cfg(test)]
#[inline]
pub const fn val(&self) -> u64 {
self.bits[0]
}
#[inline]
pub const fn word(&self, idx: usize) -> u64 {
if idx < GHR_MAX_WORDS { self.bits[idx] } else { 0 }
}
#[inline]
pub const fn bit(&self, pos: usize) -> bool {
let word_idx = pos / 64;
let bit_idx = pos % 64;
if word_idx >= GHR_MAX_WORDS {
return false;
}
(self.bits[word_idx] >> bit_idx) & 1 != 0
}
pub fn push(&mut self, taken: bool) {
for i in (1..GHR_MAX_WORDS).rev() {
self.bits[i] = (self.bits[i] << 1) | (self.bits[i - 1] >> 63);
}
self.bits[0] = (self.bits[0] << 1) | (taken as u64);
let len = self.len as usize;
if len > 0 && len < GHR_MAX_WORDS * 64 {
let top_word_idx = len / 64;
let top_bit_count = len % 64;
if top_word_idx < GHR_MAX_WORDS {
if top_bit_count > 0 {
self.bits[top_word_idx] &= (1u64 << top_bit_count) - 1;
} else {
self.bits[top_word_idx] = 0;
}
for w in &mut self.bits[top_word_idx + 1..] {
*w = 0;
}
}
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_ghr_with_len() {
let ghr = Ghr::with_len(712);
assert_eq!(ghr.len, 712);
assert_eq!(ghr.val(), 0);
}
#[test]
fn test_ghr_push_and_bit() {
let mut ghr = Ghr::with_len(128);
ghr.push(true);
ghr.push(false);
ghr.push(true);
assert!(ghr.bit(0)); assert!(!ghr.bit(1)); assert!(ghr.bit(2)); assert!(!ghr.bit(3)); }
#[test]
fn test_ghr_push_across_word_boundary() {
let mut ghr = Ghr::with_len(128);
for i in 0..65 {
ghr.push(i == 0); }
assert!(ghr.bit(64));
assert!(!ghr.bit(63));
assert!(!ghr.bit(65));
}
#[test]
fn test_ghr_push_masks_to_len() {
let mut ghr = Ghr::with_len(5);
for _ in 0..10 {
ghr.push(true);
}
assert!(ghr.bit(0));
assert!(ghr.bit(4));
assert!(!ghr.bit(5)); }
#[test]
fn test_ghr_default() {
let ghr = Ghr::default();
assert_eq!(ghr.len, 0);
assert_eq!(ghr.val(), 0);
assert!(!ghr.bit(0));
}
#[test]
fn test_ghr_copy_semantics() {
let mut ghr = Ghr::with_len(64);
ghr.push(true);
let snapshot = ghr; ghr.push(false); assert!(snapshot.bit(0)); assert!(!ghr.bit(0)); }
}