use std::ops::{BitAnd, BitOr, BitXor};
use crate::{bit_block::BitBlock, config::Config};
pub type SizeHint = (usize, usize);
fn max_data_blocks<Conf: Config>() -> usize {
<Conf as Config>::MAX_CAPACITY / Conf::DataBitBlock::size()
}
pub trait BitSetOp: Default + Copy + 'static{
const TRUSTED_HIERARCHY: bool;
const HIERARCHY_OPERANDS_CONTAIN_RESULT: bool;
fn hierarchy_op<T: BitBlock>(left: T, right: T) -> T;
fn data_op<T: BitBlock>(left: T, right: T) -> T;
fn data_blocks_size_hint<Conf: Config>(
left_size_hint: SizeHint, right_size_hint: SizeHint
) -> SizeHint;
}
#[derive(Default, Copy, Clone)]
pub struct And;
impl BitSetOp for And {
const TRUSTED_HIERARCHY: bool = false;
const HIERARCHY_OPERANDS_CONTAIN_RESULT: bool = true;
#[inline]
fn hierarchy_op<T: BitBlock>(left: T, right: T) -> T {
BitAnd::bitand(left, right)
}
#[inline]
fn data_op<T: BitBlock>(left: T, right: T) -> T {
BitAnd::bitand(left, right)
}
#[inline]
fn data_blocks_size_hint<Conf: Config>(
left_size_hint: SizeHint, right_size_hint: SizeHint
) -> SizeHint {
let max = usize::max(left_size_hint.1, right_size_hint.1);
(0, max)
}
}
#[derive(Default, Copy, Clone)]
pub struct Or;
impl BitSetOp for Or {
const TRUSTED_HIERARCHY: bool = true;
const HIERARCHY_OPERANDS_CONTAIN_RESULT: bool = false;
#[inline]
fn hierarchy_op<T: BitBlock>(left: T, right: T) -> T {
BitOr::bitor(left, right)
}
#[inline]
fn data_op<T: BitBlock>(left: T, right: T) -> T {
BitOr::bitor(left, right)
}
#[inline]
fn data_blocks_size_hint<Conf: Config>(
left_size_hint: SizeHint, right_size_hint: SizeHint
) -> SizeHint {
let min = usize::max(left_size_hint.0, right_size_hint.0);
let max = usize::min(
max_data_blocks::<Conf>(),
left_size_hint.1 + right_size_hint.1
);
(min, max)
}
}
#[derive(Default, Copy, Clone)]
pub struct Xor;
impl BitSetOp for Xor {
const TRUSTED_HIERARCHY: bool = false;
const HIERARCHY_OPERANDS_CONTAIN_RESULT: bool = false;
#[inline]
fn hierarchy_op<T: BitBlock>(left: T, right: T) -> T {
BitOr::bitor(left, right)
}
#[inline]
fn data_op<T: BitBlock>(left: T, right: T) -> T {
BitXor::bitxor(left, right)
}
#[inline]
fn data_blocks_size_hint<Conf: Config>(
left_size_hint: SizeHint, right_size_hint: SizeHint
) -> SizeHint {
let max = usize::min(
max_data_blocks::<Conf>(),
left_size_hint.1 + right_size_hint.1
);
(0, max)
}
}
#[derive(Default, Copy, Clone)]
pub struct Sub;
impl BitSetOp for Sub {
const TRUSTED_HIERARCHY: bool = false;
const HIERARCHY_OPERANDS_CONTAIN_RESULT: bool = false;
#[inline]
fn hierarchy_op<T: BitBlock>(left: T, _right: T) -> T {
left
}
#[inline]
fn data_op<T: BitBlock>(left: T, right: T) -> T {
left & (left ^ right)
}
#[inline]
fn data_blocks_size_hint<Conf: Config>(
left_size_hint: SizeHint, right_size_hint: SizeHint
) -> SizeHint {
let min = usize::saturating_sub(left_size_hint.0, right_size_hint.0);
(min, left_size_hint.1)
}
}