use crate::natural::Natural;
use crate::natural::conversion::to_limbs::LimbIterator;
use crate::platform::Limb;
use core::ops::Index;
use malachite_base::num::arithmetic::traits::PowerOf2;
use malachite_base::num::basic::integers::PrimitiveInt;
use malachite_base::num::conversion::traits::ExactFrom;
use malachite_base::num::logic::traits::{BitAccess, BitIterable, SignificantBits};
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub struct NaturalBitIterator<'a> {
pub(crate) significant_bits: u64,
pub(crate) limbs: LimbIterator<'a>,
remaining: usize,
indices_are_in_same_limb: bool,
current_limb_forward: Limb,
current_limb_back: Limb,
i_mask: Limb,
j_mask: Limb,
}
impl Iterator for NaturalBitIterator<'_> {
type Item = bool;
fn next(&mut self) -> Option<bool> {
if self.remaining != 0 {
let bit = self.current_limb_forward & self.i_mask != 0;
self.i_mask <<= 1;
if self.i_mask == 0 {
self.i_mask = 1;
if let Some(next) = self.limbs.next() {
self.current_limb_forward = next;
} else {
self.current_limb_forward = self.current_limb_back;
self.indices_are_in_same_limb = true;
}
}
self.remaining -= 1;
Some(bit)
} else {
None
}
}
fn size_hint(&self) -> (usize, Option<usize>) {
(self.remaining, Some(self.remaining))
}
}
impl DoubleEndedIterator for NaturalBitIterator<'_> {
fn next_back(&mut self) -> Option<bool> {
if self.remaining != 0 {
let bit = self.current_limb_back & self.j_mask != 0;
self.j_mask >>= 1;
if self.j_mask == 0 {
self.j_mask = Limb::power_of_2(Limb::WIDTH - 1);
if let Some(next_back) = self.limbs.next_back() {
self.current_limb_back = next_back;
} else {
self.current_limb_back = self.current_limb_forward;
self.indices_are_in_same_limb = true;
}
}
self.remaining -= 1;
Some(bit)
} else {
None
}
}
}
impl ExactSizeIterator for NaturalBitIterator<'_> {}
impl Index<u64> for NaturalBitIterator<'_> {
type Output = bool;
fn index(&self, index: u64) -> &bool {
if self.limbs.n.get_bit(index) {
&true
} else {
&false
}
}
}
impl<'a> BitIterable for &'a Natural {
type BitIterator = NaturalBitIterator<'a>;
fn bits(self) -> NaturalBitIterator<'a> {
let significant_bits = self.significant_bits();
let remainder = significant_bits & Limb::WIDTH_MASK;
let mut bits = NaturalBitIterator {
significant_bits,
limbs: self.limbs(),
remaining: usize::exact_from(significant_bits),
indices_are_in_same_limb: significant_bits <= Limb::WIDTH,
current_limb_forward: 0,
current_limb_back: 0,
i_mask: 1,
j_mask: if remainder != 0 {
Limb::power_of_2(remainder - 1)
} else {
Limb::power_of_2(Limb::WIDTH - 1)
},
};
if let Some(next) = bits.limbs.next() {
bits.current_limb_forward = next;
}
if let Some(next_back) = bits.limbs.next_back() {
bits.current_limb_back = next_back;
} else {
bits.current_limb_back = bits.current_limb_forward;
}
bits
}
}