use {Bits, BitSliceable};
use BlockType;
use iter::BlockIter;
use traits::get_masked_block;
use std::cmp;
#[derive(Clone, Debug)]
pub struct BitNot<T>(T);
impl<T> BitNot<T> {
pub (crate) fn new(bits: T) -> Self {
BitNot(bits)
}
}
#[derive(Clone, Debug)]
pub struct BitAnd<T, U>(BitBinOp<T, U>);
impl<T: Bits, U: Bits<Block = T::Block>> BitAnd<T, U> {
pub (crate) fn new(bits1: T, bits2: U) -> Self {
BitAnd(BitBinOp::new(bits1, bits2))
}
}
#[derive(Clone, Debug)]
pub struct BitOr<T, U>(BitBinOp<T, U>);
impl<T: Bits, U: Bits<Block = T::Block>> BitOr<T, U> {
pub (crate) fn new(bits1: T, bits2: U) -> Self {
BitOr(BitBinOp::new(bits1, bits2))
}
}
#[derive(Clone, Debug)]
pub struct BitXor<T, U>(BitBinOp<T, U>);
impl<T: Bits, U: Bits<Block = T::Block>> BitXor<T, U> {
pub (crate) fn new(bits1: T, bits2: U) -> Self {
BitXor(BitBinOp::new(bits1, bits2))
}
}
#[derive(Clone, Debug)]
pub struct BitZip<T, U, F> {
ops: BitBinOp<T, U>,
fun: F,
}
impl<T: Bits, U: Bits<Block = T::Block>, F> BitZip<T, U, F> {
pub (crate) fn new(bits1: T, bits2: U, fun: F) -> Self {
BitZip {
ops: BitBinOp::new(bits1, bits2),
fun,
}
}
}
#[derive(Clone, Debug)]
struct BitBinOp<T, U> {
op1: T,
op2: U,
len: u64,
}
impl<T: Bits, U: Bits<Block = T::Block>> BitBinOp<T, U> {
fn new(op1: T, op2: U) -> Self {
let len = cmp::min(op1.bit_len(), op2.bit_len());
BitBinOp { op1, op2, len, }
}
fn bit1(&self, position: u64) -> bool {
self.op1.get_bit(position)
}
fn bit2(&self, position: u64) -> bool {
self.op2.get_bit(position)
}
fn block1(&self, position: usize) -> T::Block {
self.op1.get_raw_block(position)
}
fn block2(&self, position: usize) -> T::Block {
self.op2.get_raw_block(position)
}
}
impl<T: Bits> Bits for BitNot<T> {
type Block = T::Block;
fn bit_len(&self) -> u64 {
self.0.bit_len()
}
fn get_bit(&self, position: u64) -> bool {
!self.0.get_bit(position)
}
fn get_block(&self, position: usize) -> Self::Block {
!self.0.get_block(position)
}
fn get_raw_block(&self, position: usize) -> Self::Block {
!self.0.get_raw_block(position)
}
}
impl_index_from_bits! {
impl[T: Bits] Index<u64> for BitNot<T>;
}
impl<R, T> BitSliceable<R> for BitNot<T>
where T: BitSliceable<R> {
type Slice = BitNot<T::Slice>;
fn bit_slice(self, range: R) -> Self::Slice {
BitNot(self.0.bit_slice(range))
}
}
impl_bit_sliceable_adapter! {
impl['a, T: Bits] BitSliceable for &'a BitNot<T>;
}
impl<T, U> PartialEq<U> for BitNot<T>
where T: Bits,
U: Bits<Block = T::Block> {
fn eq(&self, other: &U) -> bool {
BlockIter::new(self) == BlockIter::new(other)
}
}
macro_rules! impl_bits_bin_op {
( $target:ident as $block_op:tt $bool_op:tt ) => {
impl<T, U> Bits for $target<T, U>
where T: Bits,
U: Bits<Block = T::Block>
{
type Block = T::Block;
fn bit_len(&self) -> u64 {
self.0.len
}
fn get_bit(&self, position: u64) -> bool {
assert!( position < self.bit_len(),
format!("{}::get_bit: out of bounds", stringify!($target)) );
self.0.bit1(position) $bool_op self.0.bit2(position)
}
fn get_block(&self, position: usize) -> Self::Block {
assert!( position < self.block_len(),
format!("{}::get_block: out of bounds", stringify!($target)) );
get_masked_block(self, position)
}
fn get_raw_block(&self, position: usize) -> Self::Block {
self.0.block1(position) $block_op self.0.block2(position)
}
}
impl_index_from_bits! {
impl[T: Bits, U: Bits<Block = T::Block>] Index<u64> for $target<T, U>;
}
impl<Block, R, T, U> BitSliceable<R> for $target<T, U>
where Block: BlockType,
R: Clone,
T: BitSliceable<R, Block = Block>,
U: BitSliceable<R, Block = Block> {
type Slice = $target<T::Slice, U::Slice>;
fn bit_slice(self, range: R) -> Self::Slice {
$target(BitBinOp::new(self.0.op1.bit_slice(range.clone()),
self.0.op2.bit_slice(range)))
}
}
impl_bit_sliceable_adapter! {
impl['a, T: Bits, U: Bits<Block = T::Block>] BitSliceable for &'a $target<T, U>;
}
impl<T, U, V> PartialEq<V> for $target<T, U>
where T: Bits,
U: Bits<Block = T::Block>,
V: Bits<Block = T::Block> {
fn eq(&self, other: &V) -> bool {
BlockIter::new(self) == BlockIter::new(other)
}
}
};
}
impl_bits_bin_op!(BitAnd as & &&);
impl_bits_bin_op!(BitOr as | ||);
impl_bits_bin_op!(BitXor as ^ ^);
impl<T, U, F> Bits for BitZip<T, U, F>
where T: Bits,
U: Bits<Block = T::Block>,
F: Fn(T::Block, T::Block) -> T::Block {
type Block = T::Block;
fn bit_len(&self) -> u64 {
self.ops.len
}
fn get_block(&self, position: usize) -> Self::Block {
assert!( position < self.block_len(), "BitZip::get_block: out of bounds" );
get_masked_block(self, position)
}
fn get_raw_block(&self, position: usize) -> Self::Block {
(self.fun)(self.ops.block1(position), self.ops.block2(position))
}
}
impl_index_from_bits! {
impl[T: Bits, U: Bits<Block = T::Block>,
F: Fn(T::Block, T::Block) -> T::Block]
Index<u64> for BitZip<T, U, F>;
}
impl<Block, R, T, U, F> BitSliceable<R> for BitZip<T, U, F>
where Block: BlockType,
R: Clone,
T: BitSliceable<R, Block = Block>,
U: BitSliceable<R, Block = Block>,
F: Fn(Block, Block) -> Block {
type Slice = BitZip<T::Slice, U::Slice, F>;
fn bit_slice(self, range: R) -> Self::Slice {
BitZip {
ops: BitBinOp::new(self.ops.op1.bit_slice(range.clone()),
self.ops.op2.bit_slice(range)),
fun: self.fun,
}
}
}
impl_bit_sliceable_adapter! {
impl['a, T: Bits, U: Bits<Block = T::Block>,
F: Fn(T::Block, T::Block) -> T::Block]
BitSliceable for &'a BitZip<T, U, F>;
}
impl<T, U, F, V> PartialEq<V> for BitZip<T, U, F>
where T: Bits,
U: Bits<Block = T::Block>,
V: Bits<Block = T::Block>,
F: Fn(T::Block, T::Block) -> T::Block {
fn eq(&self, other: &V) -> bool {
BlockIter::new(self) == BlockIter::new(other)
}
}