use crate::libraries::big_num::U256;
use crate::libraries::bit_math;
use anchor_lang::prelude::*;
use std::ops::BitXor;
pub const BITMAP_SEED: &str = "b";
#[account(zero_copy)]
#[derive(Default)]
#[repr(packed)]
pub struct TickBitmapState {
pub bump: u8,
pub word_pos: i16,
pub word: [u64; 4],
}
pub struct Position {
pub word_pos: i16,
pub bit_pos: u8,
}
pub struct NextBit {
pub next: u8,
pub initialized: bool,
}
pub fn position(tick_by_spacing: i32) -> Position {
Position {
word_pos: (tick_by_spacing >> 8) as i16,
bit_pos: (tick_by_spacing % 256) as u8,
}
}
impl TickBitmapState {
pub fn flip_bit(&mut self, bit_pos: u8) {
let word = U256(self.word);
let mask = U256::from(1) << bit_pos;
self.word = word.bitxor(mask).0;
}
pub fn next_initialized_bit(&self, bit_pos: u8, lte: bool) -> NextBit {
let word = U256(self.word);
if lte {
let mask = (U256::from(1) << bit_pos) - 1 + (U256::from(1) << bit_pos);
let masked = word & mask;
let initialized = masked != U256::default();
let next = if initialized {
bit_math::most_significant_bit(masked)
} else {
0
};
NextBit { next, initialized }
} else {
let mask = !((U256::from(1) << bit_pos) - 1);
let masked = word & mask;
let initialized = masked != U256::default();
let next = if initialized {
bit_math::least_significant_bit(masked)
} else {
u8::MAX
};
NextBit { next, initialized }
}
}
#[cfg(test)]
fn is_initialized(self, bit_pos: u8) -> bool {
let next_bit = self.next_initialized_bit(bit_pos, true);
next_bit.next == bit_pos && next_bit.initialized
}
#[cfg(test)]
fn init_bits(&mut self, bit_positions: &[u8]) {
for bit_pos in bit_positions {
self.flip_bit(*bit_pos);
}
}
}
#[cfg(test)]
mod tests {
use super::*;
mod is_initialized {
use super::*;
#[test]
fn is_false_at_first() {
let tick_bitmap = TickBitmapState::default();
assert!(!tick_bitmap.is_initialized(1));
}
#[test]
fn is_flipped_by_flip_tick() {
let mut tick_bitmap = TickBitmapState::default();
tick_bitmap.flip_bit(1);
assert!(tick_bitmap.is_initialized(1));
}
#[test]
fn is_flipped_back_by_flip_tick() {
let mut tick_bitmap = TickBitmapState::default();
tick_bitmap.flip_bit(1);
tick_bitmap.flip_bit(1);
assert!(!tick_bitmap.is_initialized(1));
}
#[test]
fn is_not_changed_by_another_flip_to_a_different_tick() {
let mut tick_bitmap = TickBitmapState::default();
tick_bitmap.flip_bit(2);
assert!(!tick_bitmap.is_initialized(1));
}
}
mod is_flipped {
use super::*;
#[test]
fn flips_only_the_specified_tick() {
let mut tick_bitmap = TickBitmapState::default();
tick_bitmap.flip_bit(230);
assert!(tick_bitmap.is_initialized(230));
assert!(!tick_bitmap.is_initialized(229));
assert!(!tick_bitmap.is_initialized(231));
tick_bitmap.flip_bit(230);
assert!(!tick_bitmap.is_initialized(230));
assert!(!tick_bitmap.is_initialized(229));
assert!(!tick_bitmap.is_initialized(231));
}
}
mod next_initialized_bit_within_one_word {
use super::*;
mod lte_is_false {
use super::*;
#[test]
fn returns_same_bit_if_initialized() {
let mut tick_bitmap = TickBitmapState::default();
tick_bitmap.init_bits(&[70, 78, 84, 139, 240]);
let NextBit { next, initialized } = tick_bitmap.next_initialized_bit(78, false);
assert!(initialized);
assert_eq!(next, 78);
}
#[test]
fn returns_bit_at_right_if_at_uninitialized_bit() {
let mut tick_bitmap = TickBitmapState::default();
tick_bitmap.init_bits(&[70, 78, 84, 139, 240]);
let NextBit { next, initialized } = tick_bitmap.next_initialized_bit(78 + 1, false);
assert!(initialized);
assert_eq!(next, 84);
}
#[test]
fn does_not_exceed_boundary_if_no_initialized_bit() {
let tick_bitmap = TickBitmapState::default();
let NextBit { next, initialized } = tick_bitmap.next_initialized_bit(0, false);
assert!(!initialized);
assert_eq!(next, 255);
}
}
mod lte_is_true {
use super::*;
#[test]
fn returns_same_bit_if_initialized() {
let mut tick_bitmap = TickBitmapState::default();
tick_bitmap.init_bits(&[70, 78, 84, 139, 240]);
let NextBit { next, initialized } = tick_bitmap.next_initialized_bit(78, true);
assert!(initialized);
assert_eq!(next, 78);
}
#[test]
fn returns_bit_directly_to_the_left_of_input_bit_if_not_initialized() {
let mut tick_bitmap = TickBitmapState::default();
tick_bitmap.init_bits(&[70, 78, 84, 139, 240]);
let NextBit { next, initialized } = tick_bitmap.next_initialized_bit(79, true);
assert!(initialized);
assert_eq!(next, 78);
}
#[test]
fn will_not_exceed_lower_boundary() {
let mut tick_bitmap = TickBitmapState::default();
tick_bitmap.init_bits(&[70, 78, 84, 139, 240]);
let NextBit { next, initialized } = tick_bitmap.next_initialized_bit(1, true);
assert!(!initialized);
assert_eq!(next, 0);
}
#[test]
fn at_the_lower_boundary() {
let mut tick_bitmap = TickBitmapState::default();
tick_bitmap.init_bits(&[70, 78, 84, 139, 240]);
let NextBit { next, initialized } = tick_bitmap.next_initialized_bit(0, true);
assert!(!initialized);
assert_eq!(next, 0);
}
#[test]
fn returns_bit_at_left_if_not_initialized() {
let mut tick_bitmap = TickBitmapState::default();
tick_bitmap.init_bits(&[70, 78, 84, 139, 240]);
let NextBit { next, initialized } = tick_bitmap.next_initialized_bit(71, true);
assert!(initialized);
assert_eq!(next, 70);
}
#[test]
fn entire_empty_word() {
let tick_bitmap = TickBitmapState::default();
let NextBit { next, initialized } = tick_bitmap.next_initialized_bit(255, true);
assert!(!initialized);
assert_eq!(next, 0);
}
#[test]
fn halfway_through_empty_word() {
let tick_bitmap = TickBitmapState::default();
let NextBit { next, initialized } = tick_bitmap.next_initialized_bit(127, true);
assert!(!initialized);
assert_eq!(next, 0);
}
}
}
}