From d27a53bcb85682a179fc40b4399779e808f18772 Mon Sep 17 00:00:00 2001 From: timofey Date: Mon, 29 May 2023 16:31:06 +0000 Subject: [PATCH] `avl::bounds` --- src/rstd/collections/avl.rs | 44 +++++-- src/rstd/collections/avl/binary.rs | 102 +++++++++++++++ src/rstd/collections/avl/bounds.rs | 200 +++++++++++++++++++++++++++++ 3 files changed, 333 insertions(+), 13 deletions(-) create mode 100644 src/rstd/collections/avl/binary.rs create mode 100644 src/rstd/collections/avl/bounds.rs diff --git a/src/rstd/collections/avl.rs b/src/rstd/collections/avl.rs index f4a9b3d..a3f7009 100644 --- a/src/rstd/collections/avl.rs +++ b/src/rstd/collections/avl.rs @@ -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 { +pub enum AvlError { Int(IntParseError), Point(PointParseError), Key(E), LeafHeight(u64), + NodeHeight, Balance(u64, u64), + HeightOverflow, + HeightMismatch { child: (u64, u64), parent: u64 }, } -impl From for TreeParseError { +impl From for AvlError { fn from(value: IntParseError) -> Self { Self::Int(value) } } -impl From for TreeParseError { +impl From for AvlError { fn from(value: PointParseError) -> Self { Self::Point(value) } } -impl Display for TreeParseError { +impl Display for AvlError { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { Self::Int(int_error) => { @@ -40,15 +46,20 @@ impl Display for TreeParseError { 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 Error for TreeParseError {} +impl Error for AvlError {} 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(lh: u64, rh: u64) -> Result<(), AvlError> { + 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 { type Mtbl = AvlNode<'a, Ctx, F::Mtbl>; - type ParseError = TreeParseError; + type ParseError = AvlError; 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 { type Mtbl = AvlTree<'a, Ctx, F::Mtbl>; - type ParseError = TreeParseError; + type ParseError = AvlError; 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 }) } diff --git a/src/rstd/collections/avl/binary.rs b/src/rstd/collections/avl/binary.rs new file mode 100644 index 0000000..5f87af8 --- /dev/null +++ b/src/rstd/collections/avl/binary.rs @@ -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>>>; + +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, + ) -> 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> { + 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; + ::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(), + } + } +} diff --git a/src/rstd/collections/avl/bounds.rs b/src/rstd/collections/avl/bounds.rs new file mode 100644 index 0000000..6f7bad1 --- /dev/null +++ b/src/rstd/collections/avl/bounds.rs @@ -0,0 +1,200 @@ +use crate::{flow::comparator::*, func::*}; + +use super::{binary::*, *}; + +struct Bounds { + l: Option>, + r: Option>, +} + +impl Clone for Bounds { + fn clone(&self) -> Self { + Self { + l: self.l.clone(), + r: self.r.clone(), + } + } +} + +pub enum BoundsError { + BoundsViolated { l: Rc, r: Rc }, +} + +pub enum BoundError { + Avl(AvlError), + Bounds(BoundsError), +} + +impl From> for BoundError { + fn from(value: AvlError) -> Self { + Self::Avl(value) + } +} + +impl From> for BoundError { + fn from(value: BoundsError) -> Self { + Self::Bounds(value) + } +} + +pub type BoundErrorA<'a, Ctx, A> = BoundError>>; + +pub type BoundResult<'a, Ctx, A, T> = Result>; + +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, +} + +pub struct BoundNode<'a, Ctx: Context<'a>, A: Mentionable<'a, Ctx>> { + node: AvlNode<'a, Ctx, A>, + bounds: Bounds, +} + +pub struct BoundReference<'a, Ctx: Context<'a>, A: Mentionable<'a, Ctx>> { + reference: AvlReference<'a, Ctx, A>, + bounds: Bounds, +} + +impl Bounds { + fn unbound() -> Self { + Bounds { l: None, r: None } + } + + fn ordered( + l: &Rc, + r: &Rc, + comparator: &impl Comparator, + ) -> Result<(), BoundsError> { + if let Comparison::R = comparator.pick_smaller(l, r) { + Err(BoundsError::BoundsViolated { + l: l.clone(), + r: r.clone(), + }) + } else { + Ok(()) + } + } + + fn new( + l: Option>, + r: Option>, + comparator: &impl Comparator, + ) -> Result> { + if let (Some(kl), Some(kr)) = (&l, &r) { + Self::ordered(kl, kr, comparator)? + } + Ok(Bounds { l, r }) + } + + fn split( + self, + key: &Rc, + comparator: &impl Comparator, + ) -> Result<(Self, Self), BoundsError> { + 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, + comparator: &impl Comparator, + ) -> Result> { + 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); + +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, + comparator: &impl Comparator, + ) -> 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, + ) -> Result, BoundsError> { + 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> { + let reference = self.tree.reference()?; + let bounds = self.bounds.clone(); + Some(BoundReference { reference, bounds }) + } +} + +type BoundResolutionError<'a, Ctx, A> = + ResolutionError<>::LookupError, BoundErrorA<'a, Ctx, A>>; + +type BoundResolutionResult<'a, Ctx, A> = + Result, 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(); + ::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(), + ) + } +}