use crate::*;
use basic_tree::*;
use locators::LocResult;
enum Fragment<'a, D: Data, T = ()> {
Value(&'a mut D::Value),
Node(&'a mut BasicNode<D, T>),
}
struct IterLocatorMut<'a, D: Data, L, T = ()> {
left: D::Summary,
stack: Vec<(Fragment<'a, D, T>, D::Summary)>,
locator: L,
}
impl<'a, D: Data, L, T> IterLocatorMut<'a, D, L, T> {
pub fn new(tree: &'a mut BasicTree<D, T>, locator: L) -> Self {
let mut res = IterLocatorMut {
left: Default::default(),
stack: vec![],
locator,
};
res.push(tree, Default::default());
res
}
fn push(&mut self, tree: &'a mut BasicTree<D, T>, summary: D::Summary) {
if let Some(node) = tree.node_mut() {
self.stack.push((Fragment::Node(node), summary));
}
}
}
impl<'a, D: Data, L: Locator<D>, T> Iterator for IterLocatorMut<'a, D, L, T> {
type Item = &'a mut D::Value;
fn size_hint(&self) -> (usize, Option<usize>) {
if self.stack.is_empty() {
(0, Some(0))
} else {
(self.stack.len(), None)
}
}
fn next(&mut self) -> Option<Self::Item> {
loop {
let (frag, summary) = match self.stack.pop() {
None => return None,
Some(x) => x,
};
let node = match frag {
Fragment::Value(val) => {
self.left = self.left + (*val).to_summary();
return Some(val);
}
Fragment::Node(node) => node,
};
node.access();
let value = &mut node.node_value;
let right_node = &mut node.right;
let left_node = &mut node.left;
let value_summary = (*value).to_summary();
let near_left_summary: D::Summary = self.left + left_node.subtree_summary();
let near_right_summary: D::Summary = right_node.subtree_summary() + summary;
let dir = self
.locator
.locate(near_left_summary, value, near_right_summary);
match dir {
LocResult::GoLeft => {
if !self.stack.is_empty() {
panic!("GoLeft received in the middle of a segment");
}
self.push(left_node, value_summary + near_right_summary);
}
LocResult::GoRight => {
self.push(right_node, summary);
self.left = near_left_summary + value_summary;
}
LocResult::Accept => {
self.push(right_node, summary);
self.stack
.push((Fragment::Value(value), near_right_summary));
self.push(left_node, value_summary + near_right_summary);
}
}
}
}
}
pub struct IterLocator<'a, D: Data, L, T = ()> {
mut_iter: IterLocatorMut<'a, D, L, T>,
}
impl<'a, D: Data, L: Locator<D>, T> IterLocator<'a, D, L, T> {
pub fn new(tree: &'a mut BasicTree<D, T>, locator: L) -> Self {
IterLocator {
mut_iter: IterLocatorMut::new(tree, locator),
}
}
}
impl<'a, D: Data, L: Locator<D>, T> Iterator for IterLocator<'a, D, L, T> {
type Item = &'a D::Value;
fn size_hint(&self) -> (usize, Option<usize>) {
self.mut_iter.size_hint()
}
fn next(&mut self) -> Option<Self::Item> {
Some(&*self.mut_iter.next()?)
}
}
enum OFragment<D: Data, T = ()> {
Value(D::Value),
Node(Box<BasicNode<D, T>>),
}
pub struct IntoIter<D: Data, L, T = ()> {
left: D::Summary,
stack: Vec<(OFragment<D, T>, D::Summary)>,
locator: L,
}
impl<D: Data, L, T> IntoIter<D, L, T> {
pub fn new(tree: BasicTree<D, T>, locator: L) -> Self {
let mut res = IntoIter {
left: Default::default(),
stack: vec![],
locator,
};
res.push(tree, Default::default());
res
}
fn push(&mut self, tree: BasicTree<D, T>, summary: D::Summary) {
if let Some(boxed_node) = tree.into_node_boxed() {
self.stack.push((OFragment::Node(boxed_node), summary));
}
}
}
impl<D: Data, L: Locator<D>, T> Iterator for IntoIter<D, L, T> {
type Item = D::Value;
fn size_hint(&self) -> (usize, Option<usize>) {
if self.stack.is_empty() {
(0, Some(0))
} else {
(self.stack.len(), None)
}
}
fn next(&mut self) -> Option<Self::Item> {
loop {
let (frag, summary) = match self.stack.pop() {
None => return None,
Some(x) => x,
};
let mut node = match frag {
OFragment::Value(val) => {
self.left = self.left + val.to_summary();
return Some(val);
}
OFragment::Node(node) => node,
};
node.access();
let value = node.node_value;
let right_node = node.right;
let left_node = node.left;
let value_summary = value.to_summary();
let near_left_summary: D::Summary = self.left + left_node.subtree_summary();
let near_right_summary: D::Summary = right_node.subtree_summary() + summary;
let dir = self
.locator
.locate(near_left_summary, &value, near_right_summary);
match dir {
LocResult::GoLeft => {
if !self.stack.is_empty() {
panic!("GoLeft received in the middle of a segment");
}
self.push(left_node, value_summary + near_right_summary);
}
LocResult::GoRight => {
self.push(right_node, summary);
self.left = near_left_summary + value_summary;
}
LocResult::Accept => {
self.push(right_node, summary);
self.stack
.push((OFragment::Value(value), near_right_summary));
self.push(left_node, value_summary + near_right_summary);
}
}
}
}
}