use std::{fmt, iter, mem};
use sorted_iter::{assume::AssumeSortedByItemExt, sorted_iterator::SortedByItem};
use crate::{div_ceil, Bitset, PackedIntArray};
#[derive(Debug, Default, Clone)]
pub struct JaggedBitset {
ends: PackedIntArray<usize, u32>,
bits: Bitset<Box<[u32]>>,
}
impl JaggedBitset {
#[inline]
#[must_use]
pub fn bit(&self, x: usize, y: usize) -> bool {
if y >= self.capacity() {
return false;
}
let start = y.checked_sub(1).map_or(Some(0), |i| self.ends.get(&i));
let end = self.ends.get(&y);
let (Some(start), Some(end)) = (start, end) else {
return false;
};
let (start, end) = (start as usize, end as usize);
if x >= (end - start) {
return false;
}
self.bits.bit(start + x)
}
#[inline]
#[must_use]
pub fn max_width(&self) -> u32 {
let max = (0..self.capacity()).filter_map(|i| self.get_width(i)).max();
max.unwrap_or(0)
}
#[must_use]
pub fn height(&self) -> usize {
let first_occupied = self.ends.rev_iter().next();
first_occupied.map_or(0, |(k, _)| k)
}
#[inline]
#[must_use]
pub fn capacity(&self) -> usize {
self.ends.capacity()
}
#[inline]
#[must_use]
pub fn width(&self, index: usize) -> u32 {
self.get_width(index).unwrap()
}
#[inline]
#[must_use]
pub fn get_width(&self, index: usize) -> Option<u32> {
let start = index
.checked_sub(1)
.map_or(Some(0), |i| self.ends.get(&i))?;
let end = self.ends.get(&index)?;
Some(end - start)
}
pub fn row(&self, index: usize) -> impl Iterator<Item = u32> + SortedByItem + '_ {
self.get_row(index).unwrap()
}
#[must_use]
pub fn get_row(&self, index: usize) -> Option<impl Iterator<Item = u32> + SortedByItem + '_> {
let start = index
.checked_sub(1)
.map_or(Some(0), |i| self.ends.get(&i))?;
let end = self.ends.get(&index)?;
let range = start as usize..end as usize;
let bits = self.bits.ones_in_range(range).map(move |i| i - start);
let bits = bits.assume_sorted_by_item();
let is_not_empty = start != end;
Some(is_not_empty.then_some(bits).into_iter().flatten())
}
#[must_use]
pub const fn braille_trans_display(&self) -> BrailleTransposedDisplay {
BrailleTransposedDisplay { bitset: self }
}
#[must_use]
pub const fn braille_display(&self) -> BrailleDisplay {
BrailleDisplay { bitset: self }
}
}
#[derive(Debug, Clone, Default)]
pub struct Builder {
ends: Vec<u32>,
bits: Bitset<Vec<u32>>,
}
impl Builder {
#[must_use]
pub fn new() -> Self {
Self::default()
}
#[must_use]
pub fn with_capacity(cap: usize) -> Self {
Builder {
ends: Vec::with_capacity(cap),
bits: Bitset(Vec::new()),
}
}
#[must_use]
pub fn build(&mut self) -> JaggedBitset {
JaggedBitset {
ends: self.ends.drain(..).enumerate().collect(),
bits: Bitset(std::mem::take(&mut self.bits.0).into_boxed_slice()),
}
}
pub fn with_row(&mut self, row: impl IntoIterator<Item = u32>) -> &mut Self {
let start = self.ends.last().map_or(0, |i| *i);
let mut row_len = 0;
for bit in row {
let bit_len = self.bits.bit_len();
let bit_in_array = (bit + start) as usize;
if bit_len <= bit_in_array {
let extra_blocks = (bit_in_array - bit_len) / mem::size_of::<u32>() + 1;
self.bits.0.extend(iter::repeat(0).take(extra_blocks));
}
self.bits.enable_bit(bit_in_array);
row_len = row_len.max(bit + 1);
}
self.ends.push(start + row_len);
self
}
}
fn display_braille(
f: &mut fmt::Formatter,
height: usize,
width: usize,
get_bit: impl Fn(usize, usize) -> u32,
) -> fmt::Result {
if width == 0 {
write!(f, "\u{1fb74}\u{1fb70}")?;
}
for y in 0..div_ceil(height, 4) {
if y != 0 {
writeln!(f)?;
}
write!(f, "\u{1fb74}")?;
for x in 0..div_ceil(width, 2) {
let get_bit = |offset_x, offset_y| get_bit(x * 2 + offset_x, y * 4 + offset_y);
let offset = get_bit(0, 0)
| get_bit(1, 0) << 3
| get_bit(0, 1) << 1
| get_bit(1, 1) << 4
| get_bit(0, 2) << 2
| get_bit(1, 2) << 5
| get_bit(0, 3) << 6
| get_bit(1, 3) << 7;
let character = char::from_u32(0x2800 + offset).unwrap();
write!(f, "{character}")?;
}
write!(f, "\u{1fb70}")?;
}
Ok(())
}
#[derive(Clone, Copy)]
pub struct BrailleTransposedDisplay<'a> {
bitset: &'a JaggedBitset,
}
impl<'a> fmt::Debug for BrailleTransposedDisplay<'a> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Display::fmt(self, f)
}
}
impl<'a> fmt::Display for BrailleTransposedDisplay<'a> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let height = self.bitset.max_width() as usize;
let width = self.bitset.height();
display_braille(f, height, width, |x, y| u32::from(self.bitset.bit(y, x)))
}
}
#[derive(Clone, Copy)]
pub struct BrailleDisplay<'a> {
bitset: &'a JaggedBitset,
}
impl<'a> fmt::Debug for BrailleDisplay<'a> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Display::fmt(self, f)
}
}
impl<'a> fmt::Display for BrailleDisplay<'a> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let width = self.bitset.max_width() as usize;
let height = self.bitset.height();
display_braille(f, height, width, |x, y| u32::from(self.bitset.bit(x, y)))
}
}