avl::bounds
This commit is contained in:
parent
4736d8d112
commit
d27a53bcb8
@ -1,3 +1,6 @@
|
||||
pub mod binary;
|
||||
pub mod bounds;
|
||||
|
||||
use std::{error::Error, fmt::Display, rc::Rc};
|
||||
|
||||
use crate::rcore::*;
|
||||
@ -8,27 +11,30 @@ use crate::rstd::{
|
||||
};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum TreeParseError<E> {
|
||||
pub enum AvlError<E> {
|
||||
Int(IntParseError),
|
||||
Point(PointParseError),
|
||||
Key(E),
|
||||
LeafHeight(u64),
|
||||
NodeHeight,
|
||||
Balance(u64, u64),
|
||||
HeightOverflow,
|
||||
HeightMismatch { child: (u64, u64), parent: u64 },
|
||||
}
|
||||
|
||||
impl<E> From<IntParseError> for TreeParseError<E> {
|
||||
impl<E> From<IntParseError> for AvlError<E> {
|
||||
fn from(value: IntParseError) -> Self {
|
||||
Self::Int(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl<E> From<PointParseError> for TreeParseError<E> {
|
||||
impl<E> From<PointParseError> for AvlError<E> {
|
||||
fn from(value: PointParseError) -> Self {
|
||||
Self::Point(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl<E: Display> Display for TreeParseError<E> {
|
||||
impl<E: Display> Display for AvlError<E> {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
Self::Int(int_error) => {
|
||||
@ -40,15 +46,20 @@ impl<E: Display> Display for TreeParseError<E> {
|
||||
Self::Key(key_error) => {
|
||||
f.write_fmt(format_args!("failed to parse AVL node key: {key_error}"))
|
||||
}
|
||||
Self::NodeHeight => f.write_fmt(format_args!("invalid AVL non-leaf height: 0.")),
|
||||
Self::LeafHeight(height) => {
|
||||
f.write_fmt(format_args!("invalid AVL leaf height: {height}!=0."))
|
||||
}
|
||||
Self::Balance(lh, rh) => f.write_fmt(format_args!("unbalanced AVL node: {lh} {rh}.")),
|
||||
Self::HeightOverflow => f.write_fmt(format_args!("AVL tree height overflow")),
|
||||
Self::HeightMismatch { child, parent } => f.write_fmt(format_args!(
|
||||
"AVL child-parent height mismatch: {child:?}, {parent}"
|
||||
)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<E: Error> Error for TreeParseError<E> {}
|
||||
impl<E: Error> Error for AvlError<E> {}
|
||||
|
||||
pub struct AvlNode<'a, Ctx: Context<'a>, A: Mentionable<'a, Ctx>> {
|
||||
l: AvlTree<'a, Ctx, A>,
|
||||
@ -108,10 +119,17 @@ impl<'a, Ctx: Context<'a>, A: Mentionable<'a, Ctx>> Mentionable<'a, Ctx> for Avl
|
||||
}
|
||||
}
|
||||
|
||||
fn balanced<E>(lh: u64, rh: u64) -> Result<(), AvlError<E>> {
|
||||
if std::cmp::max(lh, rh) - std::cmp::min(lh, rh) > 1 {
|
||||
return Err(AvlError::Balance(lh, rh));
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
impl<'a, Ctx: Context<'a>, F: Factory<'a, Ctx>> Factory<'a, Ctx> for AvlNodeFactory<F> {
|
||||
type Mtbl = AvlNode<'a, Ctx, F::Mtbl>;
|
||||
|
||||
type ParseError = TreeParseError<F::ParseError>;
|
||||
type ParseError = AvlError<F::ParseError>;
|
||||
|
||||
fn deserialize(
|
||||
&self,
|
||||
@ -122,26 +140,24 @@ impl<'a, Ctx: Context<'a>, F: Factory<'a, Ctx>> Factory<'a, Ctx> for AvlNodeFact
|
||||
let tree_factory = AvlTreeFactory(NullableFactory::new(self.clone()));
|
||||
let l = tree_factory.deserialize(deserializer, resolver.clone(), addresses)?;
|
||||
let r = tree_factory.deserialize(deserializer, resolver.clone(), addresses)?;
|
||||
if std::cmp::max(l.height, r.height) - std::cmp::min(l.height, r.height) > 1 {
|
||||
return Err(TreeParseError::Balance(l.height, r.height));
|
||||
}
|
||||
balanced(l.height, r.height)?;
|
||||
let key = self
|
||||
.0
|
||||
.deserialize(deserializer, resolver.clone(), addresses)
|
||||
.map_err(TreeParseError::Key)?
|
||||
.map_err(AvlError::Key)?
|
||||
.into();
|
||||
Ok(AvlNode { l, r, key })
|
||||
}
|
||||
|
||||
fn unexpected_tail(&self, tail: &[u8]) -> Self::ParseError {
|
||||
TreeParseError::Key(self.0.unexpected_tail(tail))
|
||||
AvlError::Key(self.0.unexpected_tail(tail))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, Ctx: Context<'a>, F: Factory<'a, Ctx>> Factory<'a, Ctx> for AvlTreeFactory<F> {
|
||||
type Mtbl = AvlTree<'a, Ctx, F::Mtbl>;
|
||||
|
||||
type ParseError = TreeParseError<F::ParseError>;
|
||||
type ParseError = AvlError<F::ParseError>;
|
||||
|
||||
fn deserialize(
|
||||
&self,
|
||||
@ -153,8 +169,10 @@ impl<'a, Ctx: Context<'a>, F: Factory<'a, Ctx>> Factory<'a, Ctx> for AvlTreeFact
|
||||
let height = u64::a_deserialize(deserializer)?;
|
||||
if let Nullable::Null(_) = node {
|
||||
if height != 0 {
|
||||
return Err(TreeParseError::LeafHeight(height));
|
||||
return Err(AvlError::LeafHeight(height));
|
||||
}
|
||||
} else if height == 0 {
|
||||
return Err(AvlError::NodeHeight);
|
||||
}
|
||||
Ok(AvlTree { node, height })
|
||||
}
|
||||
|
102
src/rstd/collections/avl/binary.rs
Normal file
102
src/rstd/collections/avl/binary.rs
Normal file
@ -0,0 +1,102 @@
|
||||
use crate::func::*;
|
||||
|
||||
use super::*;
|
||||
|
||||
pub struct AvlReference<'a, Ctx: Context<'a>, A: Mentionable<'a, Ctx>> {
|
||||
node: Point<'a, Ctx, AvlNode<'a, Ctx, A>>,
|
||||
parent_height: u64,
|
||||
}
|
||||
|
||||
pub type AvlResult<'a, Ctx, A, T> = Result<T, AvlError<ParseError<'a, Ctx, Fctr<'a, Ctx, A>>>>;
|
||||
|
||||
pub type AvlNodeResult<'a, Ctx, A> = AvlResult<'a, Ctx, A, AvlNode<'a, Ctx, A>>;
|
||||
|
||||
pub type AvlTreeResult<'a, Ctx, A> = AvlResult<'a, Ctx, A, AvlTree<'a, Ctx, A>>;
|
||||
|
||||
impl<'a, Ctx: Context<'a>, A: Mentionable<'a, Ctx>> AvlNode<'a, Ctx, A> {
|
||||
fn parent_height(&self) -> AvlResult<'a, Ctx, A, u64> {
|
||||
std::cmp::max(self.l.height, self.r.height)
|
||||
.checked_add(1)
|
||||
.ok_or(AvlError::HeightOverflow)
|
||||
}
|
||||
|
||||
pub fn into_tree(self) -> AvlTreeResult<'a, Ctx, A> {
|
||||
let height = self.parent_height()?;
|
||||
let node = self.into();
|
||||
Ok(AvlTree { node, height })
|
||||
}
|
||||
|
||||
pub fn new(
|
||||
l: AvlTree<'a, Ctx, A>,
|
||||
r: AvlTree<'a, Ctx, A>,
|
||||
key: Rc<A>,
|
||||
) -> AvlNodeResult<'a, Ctx, A> {
|
||||
balanced(l.height, r.height)?;
|
||||
Ok(Self { l, r, key })
|
||||
}
|
||||
|
||||
fn matches_height(&self, parent_height: u64) -> AvlResult<'a, Ctx, A, ()> {
|
||||
let expected = self.parent_height()?;
|
||||
if expected == parent_height {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(AvlError::HeightMismatch {
|
||||
child: (self.l.height, self.r.height),
|
||||
parent: parent_height,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, Ctx: Context<'a>, A: Mentionable<'a, Ctx>> AvlTree<'a, Ctx, A> {
|
||||
pub fn empty(factory: Fctr<'a, Ctx, A>) -> Self {
|
||||
Self {
|
||||
node: Nullable::Null(AvlNodeFactory(factory)),
|
||||
height: 0,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn reference(&self) -> Option<AvlReference<'a, Ctx, A>> {
|
||||
match self.node {
|
||||
Nullable::Null(_) => None,
|
||||
Nullable::NotNull(ref point) => Some(AvlReference {
|
||||
node: point.clone(),
|
||||
parent_height: self.height,
|
||||
}),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, Ctx: Context<'a>, A: Mentionable<'a, Ctx>> AvlReference<'a, Ctx, A> {
|
||||
pub fn resolve(&self) -> Resolution<'a, Ctx, AvlNode<'a, Ctx, A>> {
|
||||
let parent_height = self.parent_height;
|
||||
<Ctx::T as Functor>::fmap(
|
||||
move |resolution| {
|
||||
let node = resolution?;
|
||||
node.matches_height(parent_height)
|
||||
.map_err(ResolutionError::Parse)?;
|
||||
Ok(node)
|
||||
},
|
||||
self.node.resolve(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, Ctx: Context<'a>, A: Mentionable<'a, Ctx>> Clone for AvlTree<'a, Ctx, A> {
|
||||
fn clone(&self) -> Self {
|
||||
Self {
|
||||
node: self.node.clone(),
|
||||
height: self.height,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, Ctx: Context<'a>, A: Mentionable<'a, Ctx>> Clone for AvlNode<'a, Ctx, A> {
|
||||
fn clone(&self) -> Self {
|
||||
Self {
|
||||
l: self.l.clone(),
|
||||
r: self.r.clone(),
|
||||
key: self.key.clone(),
|
||||
}
|
||||
}
|
||||
}
|
200
src/rstd/collections/avl/bounds.rs
Normal file
200
src/rstd/collections/avl/bounds.rs
Normal file
@ -0,0 +1,200 @@
|
||||
use crate::{flow::comparator::*, func::*};
|
||||
|
||||
use super::{binary::*, *};
|
||||
|
||||
struct Bounds<A> {
|
||||
l: Option<Rc<A>>,
|
||||
r: Option<Rc<A>>,
|
||||
}
|
||||
|
||||
impl<A> Clone for Bounds<A> {
|
||||
fn clone(&self) -> Self {
|
||||
Self {
|
||||
l: self.l.clone(),
|
||||
r: self.r.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub enum BoundsError<A> {
|
||||
BoundsViolated { l: Rc<A>, r: Rc<A> },
|
||||
}
|
||||
|
||||
pub enum BoundError<A, E> {
|
||||
Avl(AvlError<E>),
|
||||
Bounds(BoundsError<A>),
|
||||
}
|
||||
|
||||
impl<A, E> From<AvlError<E>> for BoundError<A, E> {
|
||||
fn from(value: AvlError<E>) -> Self {
|
||||
Self::Avl(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl<A, E> From<BoundsError<A>> for BoundError<A, E> {
|
||||
fn from(value: BoundsError<A>) -> Self {
|
||||
Self::Bounds(value)
|
||||
}
|
||||
}
|
||||
|
||||
pub type BoundErrorA<'a, Ctx, A> = BoundError<A, ParseError<'a, Ctx, Fctr<'a, Ctx, A>>>;
|
||||
|
||||
pub type BoundResult<'a, Ctx, A, T> = Result<T, BoundErrorA<'a, Ctx, A>>;
|
||||
|
||||
pub type BoundNodeResult<'a, Ctx, A> = BoundResult<'a, Ctx, A, BoundNode<'a, Ctx, A>>;
|
||||
|
||||
pub type BoundTreeResult<'a, Ctx, A> = BoundResult<'a, Ctx, A, BoundTree<'a, Ctx, A>>;
|
||||
|
||||
pub struct BoundTree<'a, Ctx: Context<'a>, A: Mentionable<'a, Ctx>> {
|
||||
tree: AvlTree<'a, Ctx, A>,
|
||||
bounds: Bounds<A>,
|
||||
}
|
||||
|
||||
pub struct BoundNode<'a, Ctx: Context<'a>, A: Mentionable<'a, Ctx>> {
|
||||
node: AvlNode<'a, Ctx, A>,
|
||||
bounds: Bounds<A>,
|
||||
}
|
||||
|
||||
pub struct BoundReference<'a, Ctx: Context<'a>, A: Mentionable<'a, Ctx>> {
|
||||
reference: AvlReference<'a, Ctx, A>,
|
||||
bounds: Bounds<A>,
|
||||
}
|
||||
|
||||
impl<A> Bounds<A> {
|
||||
fn unbound() -> Self {
|
||||
Bounds { l: None, r: None }
|
||||
}
|
||||
|
||||
fn ordered(
|
||||
l: &Rc<A>,
|
||||
r: &Rc<A>,
|
||||
comparator: &impl Comparator<A>,
|
||||
) -> Result<(), BoundsError<A>> {
|
||||
if let Comparison::R = comparator.pick_smaller(l, r) {
|
||||
Err(BoundsError::BoundsViolated {
|
||||
l: l.clone(),
|
||||
r: r.clone(),
|
||||
})
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
fn new(
|
||||
l: Option<Rc<A>>,
|
||||
r: Option<Rc<A>>,
|
||||
comparator: &impl Comparator<A>,
|
||||
) -> Result<Self, BoundsError<A>> {
|
||||
if let (Some(kl), Some(kr)) = (&l, &r) {
|
||||
Self::ordered(kl, kr, comparator)?
|
||||
}
|
||||
Ok(Bounds { l, r })
|
||||
}
|
||||
|
||||
fn split(
|
||||
self,
|
||||
key: &Rc<A>,
|
||||
comparator: &impl Comparator<A>,
|
||||
) -> Result<(Self, Self), BoundsError<A>> {
|
||||
Ok((
|
||||
Self::new(self.l, Some(key.clone()), comparator)?,
|
||||
Self::new(Some(key.clone()), self.r, comparator)?,
|
||||
))
|
||||
}
|
||||
|
||||
fn join(
|
||||
l: Self,
|
||||
r: Self,
|
||||
key: &Rc<A>,
|
||||
comparator: &impl Comparator<A>,
|
||||
) -> Result<Self, BoundsError<A>> {
|
||||
if let Some(lr) = &l.r {
|
||||
Self::ordered(lr, key, comparator)?
|
||||
}
|
||||
if let Some(rl) = &r.l {
|
||||
Self::ordered(key, rl, comparator)?
|
||||
}
|
||||
Self::new(l.l, r.r, comparator)
|
||||
}
|
||||
}
|
||||
|
||||
pub type BoundSplit<'a, Ctx, A> = (BoundTree<'a, Ctx, A>, BoundTree<'a, Ctx, A>, Rc<A>);
|
||||
|
||||
impl<'a, Ctx: Context<'a>, A: Mentionable<'a, Ctx>> BoundNode<'a, Ctx, A> {
|
||||
pub fn into_tree(self) -> BoundTreeResult<'a, Ctx, A> {
|
||||
let tree = self.node.into_tree()?;
|
||||
let bounds = self.bounds;
|
||||
Ok(BoundTree { tree, bounds })
|
||||
}
|
||||
|
||||
pub fn new(
|
||||
l: BoundTree<'a, Ctx, A>,
|
||||
r: BoundTree<'a, Ctx, A>,
|
||||
key: Rc<A>,
|
||||
comparator: &impl Comparator<A>,
|
||||
) -> BoundNodeResult<'a, Ctx, A> {
|
||||
let bounds = Bounds::join(l.bounds, r.bounds, &key, comparator)?;
|
||||
let node = AvlNode::new(l.tree, r.tree, key)?;
|
||||
Ok(Self { node, bounds })
|
||||
}
|
||||
|
||||
pub fn split(
|
||||
&self,
|
||||
comparator: &impl Comparator<A>,
|
||||
) -> Result<BoundSplit<'a, Ctx, A>, BoundsError<A>> {
|
||||
let (bl, br) = self.bounds.clone().split(&self.node.key, comparator)?;
|
||||
Ok((
|
||||
BoundTree {
|
||||
tree: self.node.l.clone(),
|
||||
bounds: bl,
|
||||
},
|
||||
BoundTree {
|
||||
tree: self.node.r.clone(),
|
||||
bounds: br,
|
||||
},
|
||||
self.node.key.clone(),
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, Ctx: Context<'a>, A: Mentionable<'a, Ctx>> BoundTree<'a, Ctx, A> {
|
||||
pub fn empty(factory: Fctr<'a, Ctx, A>) -> Self {
|
||||
Self {
|
||||
tree: AvlTree::empty(factory),
|
||||
bounds: Bounds::unbound(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn reference(&self) -> Option<BoundReference<'a, Ctx, A>> {
|
||||
let reference = self.tree.reference()?;
|
||||
let bounds = self.bounds.clone();
|
||||
Some(BoundReference { reference, bounds })
|
||||
}
|
||||
}
|
||||
|
||||
type BoundResolutionError<'a, Ctx, A> =
|
||||
ResolutionError<<Ctx as Context<'a>>::LookupError, BoundErrorA<'a, Ctx, A>>;
|
||||
|
||||
type BoundResolutionResult<'a, Ctx, A> =
|
||||
Result<BoundNode<'a, Ctx, A>, BoundResolutionError<'a, Ctx, A>>;
|
||||
|
||||
type BoundResolution<'a, Ctx, A> = Wrapped<'a, Ctx, BoundResolutionResult<'a, Ctx, A>>;
|
||||
|
||||
impl<'a, Ctx: Context<'a>, A: Mentionable<'a, Ctx>> BoundReference<'a, Ctx, A> {
|
||||
pub fn resolve(&self) -> BoundResolution<'a, Ctx, A> {
|
||||
let bounds = self.bounds.clone();
|
||||
<Ctx::T as Functor>::fmap(
|
||||
move |resolution| {
|
||||
let node = resolution
|
||||
.map_err(|err| match err {
|
||||
ResolutionError::Lookup(lookup) => ResolutionError::Lookup(lookup),
|
||||
ResolutionError::Parse(avl) => ResolutionError::Parse(BoundError::Avl(avl)),
|
||||
})?
|
||||
.as_ref()
|
||||
.clone();
|
||||
Ok(BoundNode { node, bounds })
|
||||
},
|
||||
self.reference.resolve(),
|
||||
)
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user