use super::{
errors::ErrorCodes,
ticks::{
MIN_TICK, TICK_HAS_DEBT_ARRAY_SIZE, TICK_HAS_DEBT_CHILDREN_SIZE,
TICK_HAS_DEBT_CHILDREN_SIZE_IN_BITS, TOTAL_INDICES_NEEDED, get_first_tick_for_array_index,
},
};
use crate::{
math::{casting::Cast, safe_math::SafeMath},
programs::vaults::accounts::TickHasDebtArray,
};
use anchor_lang::Result;
impl TickHasDebtArray {
pub fn has_bits(&self, map_id: usize) -> bool {
self.tick_has_debt[map_id]
.children_bits
.iter()
.any(|&x| x != 0)
}
pub fn clear_bits(
&mut self,
map_index: usize,
byte_index: usize,
bit_index: usize,
) -> Result<()> {
let mut bitmap: [u8; TICK_HAS_DEBT_CHILDREN_SIZE] =
self.tick_has_debt[map_index].children_bits;
if bit_index > 0 {
let mask = (1 << bit_index) - 1;
bitmap[byte_index] &= mask;
} else {
bitmap[byte_index] = 0;
}
for i in (byte_index + 1)..TICK_HAS_DEBT_CHILDREN_SIZE {
bitmap[i] = 0;
}
self.tick_has_debt[map_index].children_bits = bitmap;
Ok(())
}
pub fn fetch_next_top_tick(&mut self, mut map_index: usize) -> Result<(i32, bool)> {
loop {
if self.has_bits(map_index.cast()?) {
let (next_tick, has_next_tick) = self.get_next_tick(map_index.cast()?)?;
if has_next_tick {
return Ok((next_tick, true));
}
}
if map_index == 0 {
if self.index == 0 {
return Ok((MIN_TICK, true));
} else {
return Ok((MIN_TICK, false));
}
}
map_index -= 1;
}
}
fn get_most_significant_bit(&self, map_id: usize, byte_idx: usize) -> u32 {
let bits: u8 = self.tick_has_debt[map_id].children_bits[byte_idx];
bits.leading_zeros()
}
fn get_next_tick(&self, map_index: usize) -> Result<(i32, bool)> {
for byte_idx in (0..TICK_HAS_DEBT_CHILDREN_SIZE).rev() {
if self.tick_has_debt[map_index].children_bits[byte_idx] != 0 {
let leading_zeros = self.get_most_significant_bit(map_index, byte_idx);
let bit_pos = 7 - leading_zeros as usize;
let tick_within_map = byte_idx * 8 + bit_pos;
let map_first_tick = self.get_first_tick_for_map_index(map_index)?;
return Ok((map_first_tick + tick_within_map as i32, true));
}
}
Ok((MIN_TICK, false))
}
fn get_first_tick_for_map_index(&self, map_index: usize) -> Result<i32> {
get_first_tick_for_map_in_array(self.index, map_index.cast()?)
}
}
pub fn get_first_tick_for_map_in_array(array_index: u8, map_index: u8) -> Result<i32> {
if array_index >= TOTAL_INDICES_NEEDED as u8 || map_index >= TICK_HAS_DEBT_ARRAY_SIZE as u8 {
return Err(ErrorCodes::VaultTickHasDebtOutOfRange.into());
}
let array_first_tick = get_first_tick_for_array_index(array_index)?;
let map_first_tick = array_first_tick
.safe_add((map_index as i32).safe_mul(TICK_HAS_DEBT_CHILDREN_SIZE_IN_BITS as i32)?)?;
Ok(map_first_tick)
}