use std::fmt::{self, Debug};
use self_cell::self_cell;
use smallvec::SmallVec;
use crate::{split, BaoTree, BlockSize, ChunkNum, ChunkRanges, ChunkRangesRef, TreeNode};
#[derive(Debug, PartialEq, Eq)]
#[cfg(test)]
pub struct NodeInfo<'a> {
pub node: TreeNode,
pub is_root: bool,
pub ranges: &'a ChunkRangesRef,
pub l_ranges: &'a ChunkRangesRef,
pub r_ranges: &'a ChunkRangesRef,
pub full: bool,
pub query_leaf: bool,
pub is_half_leaf: bool,
}
#[derive(Debug)]
#[cfg(test)]
pub struct PreOrderPartialIterRef<'a> {
tree: BaoTree,
min_level: u8,
stack: SmallVec<[(TreeNode, &'a ChunkRangesRef); 8]>,
shifted_filled_size: TreeNode,
shifted_root: TreeNode,
}
#[cfg(test)]
impl<'a> PreOrderPartialIterRef<'a> {
pub fn new(tree: BaoTree, ranges: &'a ChunkRangesRef, min_level: u8) -> Self {
let mut stack = SmallVec::new();
let (shifted_root, shifted_filled_size) = tree.shifted();
stack.push((shifted_root, ranges));
Self {
tree,
min_level,
stack,
shifted_filled_size,
shifted_root,
}
}
pub fn tree(&self) -> &BaoTree {
&self.tree
}
}
#[cfg(test)]
impl<'a> Iterator for PreOrderPartialIterRef<'a> {
type Item = NodeInfo<'a>;
fn next(&mut self) -> Option<Self::Item> {
let tree = &self.tree;
loop {
let (shifted, ranges) = self.stack.pop()?;
if ranges.is_empty() {
continue;
}
let node = shifted.subtract_block_size(tree.block_size.0);
let is_half_leaf = !tree.is_persisted(node);
let (l_ranges, r_ranges) = if !is_half_leaf {
split(ranges, node)
} else {
(ranges, ranges)
};
let full = ranges.is_all();
let query_leaf = shifted.is_leaf() || (full && node.level() < self.min_level as u32);
if !query_leaf {
let l = shifted.left_child().unwrap();
let r = shifted.right_descendant(self.shifted_filled_size).unwrap();
self.stack.push((r, r_ranges));
self.stack.push((l, l_ranges));
}
let is_root = shifted == self.shifted_root;
break Some(NodeInfo {
node,
ranges,
l_ranges,
r_ranges,
full,
query_leaf,
is_root,
is_half_leaf,
});
}
}
}
#[derive(Debug)]
pub struct PostOrderNodeIter {
len: TreeNode,
curr: TreeNode,
prev: Prev,
}
impl PostOrderNodeIter {
pub fn new(root: TreeNode, len: TreeNode) -> Self {
Self {
curr: root,
len,
prev: Prev::Parent,
}
}
fn go_up(&mut self, curr: TreeNode) {
let prev = curr;
(self.curr, self.prev) = if let Some(parent) = curr.restricted_parent(self.len) {
(
parent,
if prev < parent {
Prev::Left
} else {
Prev::Right
},
)
} else {
(curr, Prev::Done)
};
}
}
impl Iterator for PostOrderNodeIter {
type Item = TreeNode;
fn next(&mut self) -> Option<Self::Item> {
loop {
let curr = self.curr;
match self.prev {
Prev::Parent => {
if let Some(child) = curr.left_child() {
self.curr = child;
self.prev = Prev::Parent;
} else {
self.go_up(curr);
break Some(curr);
}
}
Prev::Left => {
self.curr = curr.right_descendant(self.len).unwrap();
self.prev = Prev::Parent;
}
Prev::Right => {
self.go_up(curr);
break Some(curr);
}
Prev::Done => {
break None;
}
}
}
}
}
#[derive(Debug)]
pub struct PreOrderNodeIter {
len: TreeNode,
curr: TreeNode,
prev: Prev,
}
impl PreOrderNodeIter {
pub fn new(root: TreeNode, len: TreeNode) -> Self {
Self {
curr: root,
len,
prev: Prev::Parent,
}
}
fn go_up(&mut self, curr: TreeNode) {
let prev = curr;
(self.curr, self.prev) = if let Some(parent) = curr.restricted_parent(self.len) {
(
parent,
if prev < parent {
Prev::Left
} else {
Prev::Right
},
)
} else {
(curr, Prev::Done)
};
}
}
impl Iterator for PreOrderNodeIter {
type Item = TreeNode;
fn next(&mut self) -> Option<Self::Item> {
loop {
let curr = self.curr;
match self.prev {
Prev::Parent => {
if let Some(child) = curr.left_child() {
self.curr = child;
self.prev = Prev::Parent;
} else {
self.go_up(curr);
}
break Some(curr);
}
Prev::Left => {
self.curr = curr.right_descendant(self.len).unwrap();
self.prev = Prev::Parent;
}
Prev::Right => {
self.go_up(curr);
}
Prev::Done => {
break None;
}
}
}
}
}
#[derive(Debug)]
enum Prev {
Parent,
Left,
Right,
Done,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum BaoChunk<R = ()> {
Parent {
node: TreeNode,
is_root: bool,
left: bool,
right: bool,
ranges: R,
},
Leaf {
start_chunk: ChunkNum,
size: usize,
is_root: bool,
ranges: R,
},
}
impl<T> BaoChunk<T> {
#[cfg(test)]
pub fn to_debug_string(&self, max_level: usize) -> String {
match self {
BaoChunk::Parent { node, is_root, .. } => {
let n = max_level.saturating_sub(node.level() as usize + 1);
let prefix = " ".repeat(n);
let start_chunk = node.chunk_range().start;
format!(
"{}{},{},{}",
prefix,
start_chunk.to_bytes(),
node.level(),
is_root
)
}
BaoChunk::Leaf {
start_chunk,
size,
is_root,
..
} => {
let prefix = " ".repeat(max_level);
format!("{}{},{},{}", prefix, start_chunk.to_bytes(), size, is_root)
}
}
}
pub fn without_ranges(&self) -> BaoChunk {
match self {
Self::Parent {
node,
is_root,
left,
right,
..
} => BaoChunk::Parent {
node: *node,
is_root: *is_root,
left: *left,
right: *right,
ranges: (),
},
Self::Leaf {
start_chunk,
size,
is_root,
..
} => BaoChunk::Leaf {
start_chunk: *start_chunk,
size: *size,
is_root: *is_root,
ranges: (),
},
}
}
}
#[derive(Debug)]
pub struct PostOrderChunkIter {
tree: BaoTree,
inner: PostOrderNodeIter,
stack: SmallVec<[BaoChunk; 2]>,
shifted_root: TreeNode,
}
impl PostOrderChunkIter {
pub fn new(tree: BaoTree) -> Self {
let (shifted_root, shifted_len) = tree.shifted();
let inner = PostOrderNodeIter::new(shifted_root, shifted_len);
Self {
tree,
inner,
stack: Default::default(),
shifted_root,
}
}
}
impl Iterator for PostOrderChunkIter {
type Item = BaoChunk;
fn next(&mut self) -> Option<Self::Item> {
loop {
if let Some(item) = self.stack.pop() {
return Some(item);
}
let shifted = self.inner.next()?;
let is_root = shifted == self.shifted_root;
let node = shifted.subtract_block_size(self.tree.block_size.0);
if shifted.is_leaf() {
let tree = &self.tree;
let (s, m, e) = tree.leaf_byte_ranges3(node);
let l_start_chunk = node.chunk_range().start;
let r_start_chunk = l_start_chunk + tree.chunk_group_chunks();
let is_half_leaf = m == e;
if !is_half_leaf {
self.stack.push(BaoChunk::Parent {
node,
is_root,
left: true,
right: true,
ranges: (),
});
self.stack.push(BaoChunk::Leaf {
is_root: false,
start_chunk: r_start_chunk,
size: (e - m).try_into().unwrap(),
ranges: (),
});
};
break Some(BaoChunk::Leaf {
is_root: is_root && is_half_leaf,
start_chunk: l_start_chunk,
size: (m - s).try_into().unwrap(),
ranges: (),
});
} else {
self.stack.push(BaoChunk::Parent {
node,
is_root,
left: true,
right: true,
ranges: (),
});
}
}
}
}
impl BaoChunk {
pub fn size(&self) -> usize {
match self {
Self::Parent { .. } => 64,
Self::Leaf { size, .. } => *size,
}
}
}
impl<T: Default> Default for BaoChunk<T> {
fn default() -> Self {
Self::Leaf {
is_root: true,
size: 0,
start_chunk: ChunkNum(0),
ranges: T::default(),
}
}
}
#[derive(Debug)]
pub struct PreOrderPartialChunkIterRef<'a> {
tree: BaoTree,
min_full_level: u8,
stack: SmallVec<[(TreeNode, &'a ChunkRangesRef); 8]>,
shifted_filled_size: TreeNode,
shifted_root: TreeNode,
buffer: SmallVec<[BaoChunk<&'a ChunkRangesRef>; 2]>,
}
impl<'a> PreOrderPartialChunkIterRef<'a> {
pub fn new(tree: BaoTree, ranges: &'a ChunkRangesRef, min_full_level: u8) -> Self {
let mut stack = SmallVec::new();
let (shifted_root, shifted_filled_size) = tree.shifted();
stack.push((shifted_root, ranges));
Self {
tree,
min_full_level,
stack,
shifted_filled_size,
shifted_root,
buffer: SmallVec::new(),
}
}
pub fn tree(&self) -> &BaoTree {
&self.tree
}
pub fn min_full_level(&self) -> u8 {
self.min_full_level
}
}
impl<'a> Iterator for PreOrderPartialChunkIterRef<'a> {
type Item = BaoChunk<&'a ChunkRangesRef>;
fn next(&mut self) -> Option<Self::Item> {
if let Some(item) = self.buffer.pop() {
return Some(item);
}
let tree = &self.tree;
let (shifted, ranges) = self.stack.pop()?;
debug_assert!(!ranges.is_empty());
let node = shifted.subtract_block_size(tree.block_size.0);
let ranges_is_all = ranges.is_all();
let below_min_full_level = node.level() < self.min_full_level as u32;
let query_leaf = ranges_is_all && below_min_full_level;
let is_root = shifted == self.shifted_root;
let chunk_range = node.chunk_range();
let byte_range = tree.byte_range(node);
let size = (byte_range.end - byte_range.start).try_into().unwrap();
if query_leaf {
Some(BaoChunk::Leaf {
start_chunk: chunk_range.start,
size,
is_root,
ranges,
})
} else if !shifted.is_leaf() {
let (l_ranges, r_ranges) = split(ranges, node);
if !r_ranges.is_empty() {
let r = shifted.right_descendant(self.shifted_filled_size).unwrap();
self.stack.push((r, r_ranges));
}
if !l_ranges.is_empty() {
let l = shifted.left_child().unwrap();
self.stack.push((l, l_ranges));
}
Some(BaoChunk::Parent {
node,
left: !l_ranges.is_empty(),
right: !r_ranges.is_empty(),
is_root,
ranges,
})
} else {
let mid_chunk = node.mid();
let mid = mid_chunk.to_bytes();
if mid >= tree.size {
Some(BaoChunk::Leaf {
start_chunk: chunk_range.start,
size,
is_root,
ranges,
})
} else {
let (l_ranges, r_ranges) = split(ranges, node);
if !r_ranges.is_empty() {
self.buffer.push(BaoChunk::Leaf {
start_chunk: mid_chunk,
size: (byte_range.end - mid).try_into().unwrap(),
is_root: false,
ranges: r_ranges,
});
}
if !l_ranges.is_empty() {
self.buffer.push(BaoChunk::Leaf {
start_chunk: chunk_range.start,
size: (mid - byte_range.start).try_into().unwrap(),
is_root: false,
ranges: l_ranges,
});
}
Some(BaoChunk::Parent {
node,
left: !l_ranges.is_empty(),
right: !r_ranges.is_empty(),
is_root,
ranges,
})
}
}
}
}
#[derive(Debug)]
pub struct ResponseIterRef<'a> {
inner: PreOrderPartialChunkIterRef<'a>,
}
impl<'a> ResponseIterRef<'a> {
pub fn new(tree: BaoTree, ranges: &'a ChunkRangesRef) -> Self {
let tree1 = BaoTree::new(tree.size, BlockSize::ZERO);
Self {
inner: PreOrderPartialChunkIterRef::new(tree1, ranges, tree.block_size.0),
}
}
pub fn tree(&self) -> BaoTree {
BaoTree::new(
self.inner.tree().size,
BlockSize(self.inner.min_full_level()),
)
}
}
impl Iterator for ResponseIterRef<'_> {
type Item = BaoChunk;
fn next(&mut self) -> Option<Self::Item> {
Some(self.inner.next()?.without_ranges())
}
}
self_cell! {
pub(crate) struct ResponseIterInner {
owner: ChunkRanges,
#[not_covariant]
dependent: ResponseIterRef,
}
}
impl ResponseIterInner {
fn next(&mut self) -> Option<BaoChunk> {
self.with_dependent_mut(|_, iter| iter.next())
}
fn tree(&self) -> BaoTree {
self.with_dependent(|_, iter| iter.tree())
}
}
pub struct ResponseIter(ResponseIterInner);
impl fmt::Debug for ResponseIter {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("ResponseIter").finish_non_exhaustive()
}
}
impl ResponseIter {
pub fn new(tree: BaoTree, ranges: ChunkRanges) -> Self {
Self(ResponseIterInner::new(ranges, |ranges| {
ResponseIterRef::new(tree, ranges)
}))
}
pub fn tree(&self) -> BaoTree {
self.0.tree()
}
}
impl Iterator for ResponseIter {
type Item = BaoChunk;
fn next(&mut self) -> Option<Self::Item> {
self.0.next()
}
}