use num::{One, Zero};
use crate::prefix::{Comparison, IpPrefix};
use self::gluemap::GlueMap;
pub use self::iter::{Children, Ranges};
enum Direction {
Left,
Right,
}
#[derive(Clone, Debug)]
pub struct Node<P: IpPrefix> {
prefix: P,
gluemap: GlueMap<P>,
left: Option<Box<Node<P>>>,
right: Option<Box<Node<P>>>,
}
impl<P: IpPrefix> Node<P> {
fn new(prefix: P, gluemap: GlueMap<P>) -> Self {
Node {
prefix,
gluemap,
left: None,
right: None,
}
}
pub fn prefix(&self) -> &P {
&self.prefix
}
pub fn add(mut self: Box<Self>, mut other: Box<Self>) -> Box<Self> {
match self.prefix().compare_with(other.prefix()) {
Comparison::Equal => {
self.gluemap |= other.gluemap;
if let Some(child) = other.left {
self = self.add(child);
}
if let Some(child) = other.right {
self = self.add(child);
}
self
}
Comparison::Subprefix(common) => {
other.gluemap &= !self.gluemap;
match other.branch_direction(common) {
Direction::Left => {
if let Some(child) = self.left {
let new_child = child.add(other);
self.left = Some(new_child);
} else {
self.left = Some(other);
}
}
Direction::Right => {
if let Some(child) = self.right {
let new_child = child.add(other);
self.right = Some(new_child);
} else {
self.right = Some(other);
}
}
};
self
}
Comparison::Superprefix(common) => {
self.gluemap &= !other.gluemap;
match self.branch_direction(common) {
Direction::Left => {
if let Some(child) = other.left {
let new_child = child.add(self);
other.left = Some(new_child);
} else {
other.left = Some(self);
}
}
Direction::Right => {
if let Some(child) = other.right {
let new_child = child.add(self);
other.right = Some(new_child);
} else {
other.right = Some(self);
}
}
};
other
}
Comparison::Divergent(common) => {
let glue_prefix = self.prefix.new_from(common).unwrap();
let mut glue = Box::new(Self::new(glue_prefix, GlueMap::zero()));
match self.branch_direction(common) {
Direction::Left => {
glue.left = Some(self);
glue.right = Some(other);
}
Direction::Right => {
glue.left = Some(other);
glue.right = Some(self);
}
};
glue
}
}
}
pub fn remove(mut self: Box<Self>, other: &mut Self) -> Box<Self> {
if let Some(mut child) = other.left.take() {
self = self.remove(&mut child);
}
if let Some(mut child) = other.right.take() {
self = self.remove(&mut child);
}
match self.prefix().compare_with(other.prefix()) {
Comparison::Superprefix(_) | Comparison::Equal => {
self.gluemap &= !other.gluemap;
if let Some(child) = self.left.take() {
self.left = Some(child.remove(other));
};
if let Some(child) = self.right.take() {
self.right = Some(child.remove(other));
};
}
Comparison::Subprefix(common) => {
let deaggr_mask = self.gluemap & other.gluemap;
if deaggr_mask != GlueMap::zero() {
self.gluemap &= !deaggr_mask;
self = self
.prefix
.into_subprefixes(other.prefix.length())
.map(|p| Box::new(Self::new(p, deaggr_mask)))
.fold(self, |this, n| this.add(n));
}
match other.branch_direction(common) {
Direction::Left => {
if let Some(child) = self.left.take() {
self.left = Some(child.remove(other));
};
}
Direction::Right => {
if let Some(child) = self.right.take() {
self.right = Some(child.remove(other));
};
}
}
}
_ => (),
};
self
}
pub fn aggregate(mut self: Box<Self>, mut mask: Option<GlueMap<P>>) -> Option<Box<Self>> {
if mask.is_none() {
mask = Some(GlueMap::zero())
}
self.gluemap &= !mask.unwrap();
*mask.as_mut().unwrap() |= self.gluemap;
if let Some(child) = self.left.take() {
self.left = child.aggregate(mask);
}
if let Some(child) = self.right.take() {
self.right = child.aggregate(mask);
}
let aggr_length = self.prefix().length() + 1;
let did_aggr = if let (Some(l), Some(r)) = (&mut self.left, &mut self.right) {
if l.prefix().length() == aggr_length && r.prefix().length() == aggr_length {
let aggr_bits = l.gluemap & r.gluemap;
l.gluemap &= !aggr_bits;
r.gluemap &= !aggr_bits;
self.gluemap |= aggr_bits;
aggr_bits != GlueMap::zero()
} else {
false
}
} else {
false
};
if did_aggr {
if let Some(child) = self.left.take() {
self.left = child.clean();
};
if let Some(child) = self.right.take() {
self.right = child.clean();
};
Some(self)
} else {
self.clean()
}
}
fn clean(self: Box<Self>) -> Option<Box<Self>> {
if self.gluemap == GlueMap::zero() {
match (&self.left, &self.right) {
(None, None) => None,
(Some(_), None) => self.left,
(None, Some(_)) => self.right,
_ => Some(self),
}
} else {
Some(self)
}
}
pub fn search(&self, qnode: &Self) -> Option<&Self> {
match self.prefix().compare_with(qnode.prefix()) {
Comparison::Equal | Comparison::Subprefix(_)
if self.gluemap & qnode.gluemap == qnode.gluemap =>
{
Some(self)
}
Comparison::Subprefix(common) => match qnode.branch_direction(common) {
Direction::Left => {
if let Some(child) = &self.left {
child.search(qnode)
} else {
None
}
}
Direction::Right => {
if let Some(child) = &self.right {
child.search(qnode)
} else {
None
}
}
},
_ => None,
}
}
fn intersect_nodes(&self, qnode: &Self) -> Option<Box<Self>> {
match self.prefix().compare_with(qnode.prefix()) {
Comparison::Divergent(_) => None,
cmp => {
let prefix = if let Comparison::Subprefix(_) = cmp {
qnode.prefix().to_owned()
} else {
self.prefix().to_owned()
};
let mut new = Box::new(Node::new(prefix, self.gluemap & qnode.gluemap));
if let Some(child) = &self.left {
if let Some(intersect_child) = child.intersect_nodes(qnode) {
new = new.add(intersect_child);
};
};
if let Some(child) = &self.right {
if let Some(intersect_child) = child.intersect_nodes(qnode) {
new = new.add(intersect_child);
};
};
Some(new)
}
}
}
fn branch_direction(&self, bit_index: u8) -> Direction {
let next_index = bit_index + 1;
let mask = P::Bits::one() << (P::MAX_LENGTH - next_index);
if self.prefix.bits() & mask == P::Bits::zero() {
Direction::Left
} else {
Direction::Right
}
}
pub fn ranges(&self) -> Ranges<P> {
self.into()
}
#[allow(clippy::needless_lifetimes, clippy::borrowed_box)]
pub fn children<'a>(self: &'a Box<Self>) -> Children<'a, P> {
self.into()
}
}
mod from;
mod gluemap;
mod iter;
mod ops;
#[cfg(test)]
mod tests;