Documentation
use crate::def::*;

#[derive(Clone, Copy, Default, PartialEq, Eq, PartialOrd, Ord)]
pub struct Bset(pub u128, pub u128);

impl Debug for Bset {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        ll(*self).fmt(f)
    }
}

fn ll(set: Bset) -> Vec<(u8, u8)> {
    let mut sink = vec![];
    for i in set.get() {
        if let Some((_, b)) = sink.last_mut() {
            if *b == i - 1 {
                *b += 1;
                continue;
            }
        }
        sink.push((i, i));
    }
    sink
}

fn tolist(i: u128, offset: u8, sink: &mut Vec<(u8, u8)>) {
    for j in 0..128 {
        if 0 != ((i >> j) & 1) {
            if let Some((_, b)) = sink.last_mut() {
                if *b == (j + offset) - 1 {
                    *b += 1;
                    continue;
                }
            }
            sink.push((j, j));
        }
    }
}

pub fn brange(a: u128, b: u128) -> u128 {
    let hi = !0 >> (127 - b);
    let lo = (1 << a) - 1;
    hi ^ lo
}

impl Bset {
    pub fn getb(self) -> [bool; 256] {
        let mut e = [false; 256];
        for (o, i) in [self.0, self.1].iter().enumerate() {
            let o = o * 128;
            for j in 0..128 {
                e[(j + o)] = 0 != ((i >> j) & 1);
            }
        }
        e
    }
    pub fn pairs(self) -> Vec<(u8, u8)> {
        let mut e = vec![];
        tolist(self.0, 000, &mut e);
        tolist(self.1, 128, &mut e);
        e
    }

    pub fn get(self) -> Vec<u8> {
        self.getb()
            .iter()
            .enumerate()
            .filter(|x| *x.1)
            .map(|x| x.0 as u8)
            .collect()
    }

    pub fn range(a: char, b: char) -> Bset {
        Bset::brange(a as u8, b as u8)
    }

    pub fn brange(a: u8, b: u8) -> Bset {
        let a = a as u128;
        let b = b as u128;
        let llo = if a < 128 { brange(a, b.min(127)) } else { 0 };
        let hhi = if b >= 128 {
            brange(a.max(128) - 128, b.max(128) - 128)
        } else {
            0
        };
        Bset(llo, hhi)
    }

    pub fn fromchar(a: char) -> Bset {
        Bset::range(a, a)
    }

    pub fn frombyte(a: u8) -> Bset {
        Bset::brange(a, a)
    }

    pub fn str(s: &str) -> Bset {
        s.as_bytes()
            .iter()
            .fold(Bset(0, 0), |a, b| a | Bset::frombyte(*b))
    }
}

impl Not for Bset {
    type Output = Bset;
    fn not(self) -> Bset {
        let l = self;
        Bset(!l.0, !l.1)
    }
}

impl BitOr for Bset {
    type Output = Self;
    fn bitor(self, r: Bset) -> Bset {
        let l = self;
        Bset(l.0 | r.0, l.1 | r.1)
    }
}

impl BitOrAssign for Bset {
    fn bitor_assign(&mut self, r: Bset) {
        *self = *self | r;
    }
}

impl BitAnd for Bset {
    type Output = Self;
    fn bitand(self, r: Bset) -> Bset {
        let l = self;
        Bset(l.0 & r.0, l.1 & r.1)
    }
}

impl BitXor for Bset {
    type Output = Self;
    fn bitxor(self, r: Bset) -> Bset {
        let l = self;
        Bset(l.0 ^ r.0, l.1 ^ r.1)
    }
}