Skip to content

Commit

Permalink
Rename items in fold APIs.
Browse files Browse the repository at this point in the history
  • Loading branch information
olson-sean-k committed Jan 26, 2024
1 parent d8086b0 commit 0e5e266
Show file tree
Hide file tree
Showing 2 changed files with 64 additions and 92 deletions.
125 changes: 60 additions & 65 deletions src/token/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -212,13 +212,10 @@ impl<'t, A> TokenTree<'t> for Tokenized<'t, A> {
}
}

// NOTE: Fold APIs are batched. They accept a complete sequence of terms rather than an accumulator
// and a single term. This incurs a performance penalty, but more easily supports
// aggregations that must consider the complete sequence of terms. While not yet implemented,
// this includes bounds in variance, in particular the variant bounds of breadth, where the
// terms must be partitioned to determine the bounds (they are disjunctive). This can be
// implemented using an accumulator, but requires additional state in either the `Fold` type,
// the `Term` type, or both.
// Fold APIs are batched: folds operate against a complete and ordered sequence of terms rather
// than an accumulator and a single subsequent term. This incurs a performance penalty, but
// supports aggregations that must consider the complete sequence of terms without the need for
// additional state in `Fold` implementers or `Term`s.
pub trait Fold<'t, A> {
type Term;

Expand All @@ -228,8 +225,8 @@ pub trait Fold<'t, A> {

fn fold(&mut self, branch: &BranchKind<'t, A>, terms: Vec<Self::Term>) -> Option<Self::Term>;

fn finalize(&mut self, _branch: &BranchKind<'t, A>, accumulator: Self::Term) -> Self::Term {
accumulator
fn finalize(&mut self, _branch: &BranchKind<'t, A>, term: Self::Term) -> Self::Term {
term
}

fn term(&mut self, leaf: &LeafKind<'t>) -> Self::Term;
Expand Down Expand Up @@ -294,8 +291,8 @@ impl<'t, A> Token<'t, A> {

// TODO: Implement this iteratively. Unfortunately, `fold_map` only maps annotations. This is
// in some part a consequence of using an intrusive tree structure: it is difficult to
// expose a general mapping API over any and all data in nodes, because nodes also
// describe their topology (i.e., may directly contain children).
// expose a general mapping API over any and all data in nodes, because the inputs and
// outputs must be expressed in terms of `Token`.
pub fn into_owned(self) -> Token<'static, A> {
let Token {
topology,
Expand Down Expand Up @@ -348,23 +345,19 @@ impl<'t, A> Token<'t, A> {
}
}

// TODO: Reverse the iterator over child nodes when extending buffers rather than using
// `VecDeque` to maintain ordering in path node types here and in `fold_map`.
// TODO: The use of terms like "fold", "accumulate", "summand", "sum", and "term" are unclear
// and maybe inconsistent here (and elsewhere). Revisit such names.
pub fn fold<F>(&self, f: F) -> Option<F::Term>
where
F: Fold<'t, A>,
{
struct Path<'i, 't, A, F>
struct TokenPath<'i, 't, A, F>
where
F: Fold<'t, A>,
{
summands: Vec<Summand<'i, 't, A, F>>,
branches: Vec<TokenBranch<'i, 't, A, F>>,
f: F,
}

impl<'i, 't, A, F> Path<'i, 't, A, F>
impl<'i, 't, A, F> TokenPath<'i, 't, A, F>
where
F: Fold<'t, A>,
{
Expand All @@ -373,51 +366,53 @@ impl<'t, A> Token<'t, A> {
if let Some(term) = self.f.initialize(branch) {
terms.push_front(term);
}
self.summands.push(Summand { branch, terms });
self.branches.push(TokenBranch { branch, terms });
}

pub fn pop(&mut self, depth: usize) {
if let Some(n) = self.summands.len().checked_sub(depth) {
if let Some(n) = self.branches.len().checked_sub(depth) {
self.fold_n(n);
}
}

pub fn fold(mut self) -> Option<F::Term> {
self.fold_n(usize::MAX);
self.summands
self.branches
.pop()
.and_then(|summand| summand.fold(&mut self.f))
.and_then(|branch| branch.fold(&mut self.f))
}

pub fn accumulate(&mut self, leaf: &'i LeafKind<'t>) -> Result<(), F::Term> {
let term = self.f.term(leaf);
match self.summands.last_mut() {
Some(summand) => {
summand.push(term);
match self.branches.last_mut() {
Some(branch) => {
branch.push(term);
Ok(())
},
None => Err(term),
}
}

fn fold_n(&mut self, n: usize) {
for _ in 0..cmp::min(n, self.summands.len().saturating_sub(1)) {
if let Some(term) = self.summands.pop().unwrap().fold(&mut self.f) {
self.summands.last_mut().unwrap().push(term);
for _ in 0..cmp::min(n, self.branches.len().saturating_sub(1)) {
if let Some(term) = self.branches.pop().unwrap().fold(&mut self.f) {
self.branches.last_mut().unwrap().push(term);
}
}
}
}

struct Summand<'i, 't, A, F>
struct TokenBranch<'i, 't, A, F>
where
F: Fold<'t, A>,
{
branch: &'i BranchKind<'t, A>,
// A queue is used to preserve the order of terms w.r.t. to the token tree and, more
// subtly, any initializer terms.
terms: VecDeque<F::Term>,
}

impl<'i, 't, A, F> Summand<'i, 't, A, F>
impl<'i, 't, A, F> TokenBranch<'i, 't, A, F>
where
F: Fold<'t, A>,
{
Expand All @@ -426,14 +421,14 @@ impl<'t, A> Token<'t, A> {
}

fn fold(self, f: &mut F) -> Option<F::Term> {
let Summand { branch, terms } = self;
let TokenBranch { branch, terms } = self;
f.fold(branch, terms.into())
.map(|accumulator| f.finalize(branch, accumulator))
.map(|term| f.finalize(branch, term))
}
}

let mut path = Path {
summands: vec![],
let mut path = TokenPath {
branches: vec![],
f,
};
let mut tokens = vec![(self, 0usize)];
Expand Down Expand Up @@ -464,25 +459,25 @@ impl<'t, A> Token<'t, A> {
where
F: FoldMap<'t, A>,
{
struct Path<'t, A, F>
struct TokenPath<'t, A, F>
where
F: FoldMap<'t, A>,
{
branches: Vec<BranchNode<'t, A, F>>,
branches: Vec<TokenBranch<'t, A, F>>,
f: F,
}

impl<'t, A, F> Path<'t, A, F>
impl<'t, A, F> TokenPath<'t, A, F>
where
F: FoldMap<'t, A>,
{
pub fn push(&mut self, annotation: A, branch: BranchFold, hint: Option<usize>) {
self.branches.push(BranchNode {
self.branches.push(TokenBranch {
annotation,
branch,
tokens: match hint {
Some(hint) => VecDeque::with_capacity(hint),
_ => VecDeque::new(),
Some(hint) => Vec::with_capacity(hint),
_ => vec![],
},
});
}
Expand Down Expand Up @@ -524,34 +519,34 @@ impl<'t, A> Token<'t, A> {
}
}

struct BranchNode<'t, A, F>
struct TokenBranch<'t, A, F>
where
F: FoldMap<'t, A>,
{
annotation: A,
branch: BranchFold,
tokens: VecDeque<Token<'t, F::Annotation>>,
tokens: Vec<Token<'t, F::Annotation>>,
}

impl<'t, A, F> BranchNode<'t, A, F>
impl<'t, A, F> TokenBranch<'t, A, F>
where
F: FoldMap<'t, A>,
{
fn push(&mut self, token: Token<'t, F::Annotation>) {
self.tokens.push_front(token)
self.tokens.push(token)
}

fn fold(self, f: &mut F) -> Option<Token<'t, F::Annotation>> {
let BranchNode {
let TokenBranch {
annotation,
branch,
tokens,
} = self;
f.fold(annotation, branch, tokens.into())
f.fold(annotation, branch, tokens)
}
}

let mut path = Path {
let mut path = TokenPath {
branches: vec![],
f,
};
Expand All @@ -562,7 +557,7 @@ impl<'t, A> Token<'t, A> {
Topology::Branch(branch) => {
let (branch, children) = branch.decompose();
let n = children.len();
tokens.extend(children.into_iter().map(|token| (token, depth + 1)));
tokens.extend(children.into_iter().rev().map(|token| (token, depth + 1)));
path.push(token.annotation, branch, Some(n));
},
Topology::Leaf(leaf) => {
Expand Down Expand Up @@ -1128,13 +1123,13 @@ where
}
}

fn finalize(&self, accumulator: Variance<T>) -> Variance<T> {
fn finalize(&self, term: Variance<T>) -> Variance<T> {
use BranchKind::{Alternation, Concatenation, Repetition};

match self {
Alternation(ref alternation) => alternation.finalize(accumulator),
Concatenation(ref concatenation) => concatenation.finalize(accumulator),
Repetition(ref repetition) => repetition.finalize(accumulator),
Alternation(ref alternation) => alternation.finalize(term),
Concatenation(ref concatenation) => concatenation.finalize(term),
Repetition(ref repetition) => repetition.finalize(term),
}
}
}
Expand Down Expand Up @@ -1595,14 +1590,14 @@ impl<'t, A> Repetition<'t, A> {
))
}

fn repeat_or_union<T>(&self, accumulator: Variance<T>) -> Variance<T>
fn repeat_or_union<T>(&self, term: Variance<T>) -> Variance<T>
where
T: Invariant,
{
self.repeat_or_else(accumulator, variance::union)
self.repeat_or_else(term, variance::union)
}

fn repeat_or_else<T, F>(&self, accumulator: Variance<T>, f: F) -> Variance<T>
fn repeat_or_else<T, F>(&self, term: Variance<T>, f: F) -> Variance<T>
where
T: Invariant,
F: FnOnce(Variance<T>, Variance<T>) -> Variance<T>,
Expand All @@ -1614,10 +1609,10 @@ impl<'t, A> Repetition<'t, A> {
// both `encode::compile` and `rule::check` (in distinct but similar ways). Querying
// token trees for an invariant must be done with care (after using these functions) to
// avoid expanding pathological invariant expressions like `<long:9999999999999>`.
accumulator.map_invariant(|text| text * n)
term.map_invariant(|text| text * n)
}
else {
f(accumulator, variance.map_invariant(|_| T::identity()))
f(term, variance.map_invariant(|_| T::identity()))
}
}
}
Expand Down Expand Up @@ -1657,10 +1652,10 @@ impl<'t, A> VarianceFold<Depth> for Repetition<'t, A> {
terms.into_iter().reduce(variance::union)
}

fn finalize(&self, accumulator: Variance<Depth>) -> Variance<Depth> {
match accumulator {
Variance::Invariant(depth) if depth == 0 => accumulator,
_ => self.repeat_or_union(accumulator),
fn finalize(&self, term: Variance<Depth>) -> Variance<Depth> {
match term {
Variance::Invariant(depth) if depth == 0 => term,
_ => self.repeat_or_union(term),
}
}
}
Expand All @@ -1670,8 +1665,8 @@ impl<'t, A> VarianceFold<Size> for Repetition<'t, A> {
terms.into_iter().reduce(variance::conjunction)
}

fn finalize(&self, accumulator: Variance<Size>) -> Variance<Size> {
self.repeat_or_union(accumulator)
fn finalize(&self, term: Variance<Size>) -> Variance<Size> {
self.repeat_or_union(term)
}
}

Expand All @@ -1680,8 +1675,8 @@ impl<'t, A> VarianceFold<Text<'t>> for Repetition<'t, A> {
terms.into_iter().reduce(variance::conjunction)
}

fn finalize(&self, accumulator: Variance<Text<'t>>) -> Variance<Text<'t>> {
self.repeat_or_union(accumulator)
fn finalize(&self, term: Variance<Text<'t>>) -> Variance<Text<'t>> {
self.repeat_or_union(term)
}
}

Expand Down
31 changes: 4 additions & 27 deletions src/token/variance/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@ pub trait VarianceTerm<T> {
pub trait VarianceFold<T> {
fn fold(&self, terms: Vec<Variance<T>>) -> Option<Variance<T>>;

fn finalize(&self, accumulator: Variance<T>) -> Variance<T> {
accumulator
fn finalize(&self, term: Variance<T>) -> Variance<T> {
term
}
}

Expand Down Expand Up @@ -290,38 +290,15 @@ where
branch.fold(terms)
}

fn finalize(&mut self, branch: &BranchKind<'t, A>, accumulator: Self::Term) -> Self::Term {
branch.finalize(accumulator)
fn finalize(&mut self, branch: &BranchKind<'t, A>, term: Self::Term) -> Self::Term {
branch.finalize(term)
}

fn term(&mut self, leaf: &LeafKind<'t>) -> Self::Term {
leaf.term()
}
}

// TODO: Replace and remove this.
/// Returns `true` if the token tree is exhaustive.
///
/// A glob expression and its token tree are exhaustive if the terminal component has unbounded
/// depth and unbounded variance.
//pub fn is_exhaustive<'i, 't, A, I>(tokens: I) -> bool
//where
// 't: 'i,
// A: 't,
// I: IntoIterator<Item = &'i Token<'t, A>>,
//{
// let component = token::components(tokens).last();
// matches!(
// component.map(|component| {
// (
// component.depth(),
// component.variance::<InvariantText>().bound(),
// )
// }),
// Some((Bound::Unbounded, Bound::Unbounded)),
// )
//}

pub fn conjunction<T>(lhs: Variance<T>, rhs: Variance<T>) -> Variance<T>
where
T: Invariant,
Expand Down

0 comments on commit 0e5e266

Please sign in to comment.