use super::{
super::extend_lifetime,
BitRefMut,
Bits64,
Index256,
Index64,
};
#[derive(Debug, Copy, Clone, PartialEq, Eq, scale::Encode, scale::Decode)]
#[cfg_attr(feature = "std", derive(tetsy_scale_info::TypeInfo))]
pub struct Bits256 {
bits: [Bits64; 4],
}
impl Default for Bits256 {
fn default() -> Self {
Self {
bits: Default::default(),
}
}
}
#[derive(Debug, Copy, Clone)]
pub struct Iter<'a> {
bits: &'a Bits256,
start: u16,
end: u16,
}
impl<'a> Iter<'a> {
fn new(bits256: &'a Bits256, len: u16) -> Self {
Self {
bits: bits256,
start: 0,
end: len,
}
}
fn remaining(&self) -> u16 {
self.end - self.start
}
}
impl<'a> ExactSizeIterator for Iter<'a> {}
impl<'a> Iterator for Iter<'a> {
type Item = bool;
fn next(&mut self) -> Option<Self::Item> {
<Self as Iterator>::nth(self, 0)
}
fn nth(&mut self, n: usize) -> Option<Self::Item> {
assert!(n < 256);
let n = n as u16;
if self.start + n >= self.end {
return None
}
let start = self.start + n;
self.start += 1 + n;
Some(self.bits.get(start as u8))
}
fn size_hint(&self) -> (usize, Option<usize>) {
let remaining = self.remaining() as usize;
(remaining, Some(remaining))
}
fn count(self) -> usize {
self.remaining() as usize
}
}
impl<'a> DoubleEndedIterator for Iter<'a> {
fn next_back(&mut self) -> Option<Self::Item> {
<Self as DoubleEndedIterator>::nth_back(self, 0)
}
fn nth_back(&mut self, n: usize) -> Option<Self::Item> {
assert!(n < 256);
let n = n as u16;
if self.start + n >= self.end {
return None
}
self.end -= 1 + n;
Some(self.bits.get(self.end as u8))
}
}
#[derive(Debug)]
pub struct IterMut<'a> {
bits: &'a mut Bits256,
start: u16,
end: u16,
}
impl<'a> IterMut<'a> {
fn new(bits256: &'a mut Bits256, len: u16) -> Self {
Self {
bits: bits256,
start: 0,
end: len,
}
}
fn remaining(&self) -> u16 {
self.end - self.start
}
fn get<'b>(&'b mut self, index: u8) -> BitRefMut<'a> {
unsafe { BitRefMut::new(extend_lifetime(&mut self.bits), index) }
}
}
impl<'a> ExactSizeIterator for IterMut<'a> {}
impl<'a> Iterator for IterMut<'a> {
type Item = BitRefMut<'a>;
fn next(&mut self) -> Option<Self::Item> {
<Self as Iterator>::nth(self, 0)
}
fn nth(&mut self, n: usize) -> Option<Self::Item> {
assert!(n < 256);
let n = n as u16;
if self.start + n >= self.end {
return None
}
let start = self.start + n;
self.start += 1 + n;
Some(self.get(start as u8))
}
fn size_hint(&self) -> (usize, Option<usize>) {
let remaining = self.remaining() as usize;
(remaining, Some(remaining))
}
fn count(self) -> usize {
self.remaining() as usize
}
}
impl<'a> DoubleEndedIterator for IterMut<'a> {
fn next_back(&mut self) -> Option<Self::Item> {
<Self as DoubleEndedIterator>::nth_back(self, 0)
}
fn nth_back(&mut self, n: usize) -> Option<Self::Item> {
assert!(n < 256);
let n = n as u16;
if self.start + n >= self.end {
return None
}
self.end -= 1 + n;
Some(self.get(self.end as u8))
}
}
impl Bits256 {
fn bits_at(&self, index: Index256) -> (&u64, Index64) {
(&self.bits[(index / 64) as usize], index % 64)
}
fn bits_at_mut(&mut self, index: Index256) -> (&mut u64, Index64) {
(&mut self.bits[(index / 64) as usize], index % 64)
}
pub(super) fn iter(&self, len: u16) -> Iter {
Iter::new(self, len)
}
pub(super) fn iter_mut(&mut self, len: u16) -> IterMut {
IterMut::new(self, len)
}
pub fn get(&self, at: Index256) -> bool {
let (bits64, pos64) = self.bits_at(at);
bits64 & (0x01 << (63 - pos64)) != 0
}
pub(super) fn set_to(&mut self, at: Index256, new_value: bool) {
if new_value {
self.set(at)
} else {
self.reset(at)
}
}
pub(super) fn flip(&mut self, at: Index256) {
self.xor(at, true)
}
pub(super) fn set(&mut self, at: Index256) {
self.or(at, true)
}
pub(super) fn reset(&mut self, at: Index256) {
self.and(at, false)
}
fn op_at_with<F>(&mut self, at: Index256, rhs: bool, op: F)
where
F: FnOnce(&mut Bits64, Bits64),
{
let (bits64, pos64) = self.bits_at_mut(at);
let rhs = (rhs as u64) << (63 - pos64);
op(bits64, rhs);
}
pub(super) fn and(&mut self, at: Index256, rhs: bool) {
self.op_at_with(at, !rhs, |bits64, rhs| *bits64 &= !rhs)
}
pub(super) fn or(&mut self, at: Index256, rhs: bool) {
self.op_at_with(at, rhs, |bits64, rhs| *bits64 |= rhs)
}
pub(super) fn xor(&mut self, at: Index256, rhs: bool) {
self.op_at_with(at, rhs, |bits64, rhs| *bits64 ^= rhs)
}
pub fn position_first_zero(&self) -> Option<u8> {
let mut offset: u32 = 0;
for bits64 in &self.bits {
if *bits64 != !0 {
return Some(((!bits64).leading_zeros() + offset) as u8)
}
offset += 64;
}
None
}
}
#[cfg(test)]
mod tests {
use super::Bits256;
#[test]
fn default_works() {
assert_eq!(
Bits256::default(),
Bits256 {
bits: [0x00, 0x00, 0x00, 0x00],
}
);
}
fn populated_bits256() -> Bits256 {
let mut bits256 = Bits256::default();
for i in 0..256 {
let i = i as u8;
bits256.set_to(i, (i % 5) == 0 || (i % 13) == 0);
}
bits256
}
#[test]
fn get_works() {
let bits256 = populated_bits256();
for i in 0..256 {
let i = i as u8;
assert_eq!(bits256.get(i), (i % 5) == 0 || (i % 13) == 0);
}
}
#[test]
fn set_works() {
let mut bits256 = populated_bits256();
for i in 0..256 {
let i = i as u8;
bits256.set(i);
assert_eq!(bits256.get(i), true);
}
}
#[test]
fn reset_works() {
let mut bits256 = populated_bits256();
for i in 0..256 {
let i = i as u8;
bits256.reset(i);
assert_eq!(bits256.get(i), false);
}
}
#[test]
fn and_works() {
let mut bits256 = populated_bits256();
for i in 0..256 {
let i = i as u8;
bits256.and(i, i % 2 == 0);
assert_eq!(
bits256.get(i),
(i % 2) == 0 && ((i % 5) == 0 || (i % 13) == 0)
);
}
}
#[test]
fn or_works() {
let mut bits256 = populated_bits256();
for i in 0..256 {
let i = i as u8;
bits256.or(i, i % 2 == 0);
assert_eq!(
bits256.get(i),
(i % 2) == 0 || (i % 5) == 0 || (i % 13) == 0
);
}
}
#[test]
fn xor_works() {
let mut bits256 = populated_bits256();
for i in 0..256 {
let i = i as u8;
bits256.xor(i, i % 2 == 0);
let a = (i % 2) == 0;
let b = (i % 5) == 0 || (i % 13) == 0;
assert_eq!(bits256.get(i), a != b);
}
}
#[test]
fn position_first_zero_works() {
let empty = Bits256::default();
assert_eq!(empty.position_first_zero(), Some(0));
let first_bit_is_set = Bits256 {
bits: [0x8000_0000_0000_0000, 0x00, 0x00, 0x00],
};
assert_eq!(first_bit_is_set.position_first_zero(), Some(1));
let first_bit_is_set = Bits256 {
bits: [!0, !0, !0, !1],
};
assert_eq!(first_bit_is_set.position_first_zero(), Some(3 * 64 + 63));
let first_bit_is_set = Bits256 {
bits: [!0, !0, !0xFFFF_FFFF, !1],
};
assert_eq!(first_bit_is_set.position_first_zero(), Some(2 * 64 + 32));
let all_bits_set = Bits256 {
bits: [!0, !0, !0, !0],
};
assert_eq!(all_bits_set.position_first_zero(), None);
}
}