Skip to content

Commit

Permalink
Remove accumulator fold (all folds are batching).
Browse files Browse the repository at this point in the history
  • Loading branch information
olson-sean-k committed Jan 17, 2024
1 parent 926b684 commit 5d737b9
Show file tree
Hide file tree
Showing 2 changed files with 18 additions and 166 deletions.
180 changes: 16 additions & 164 deletions src/token/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -204,7 +204,9 @@ where
} = self;

let (n, text) = token.invariant_text_prefix();
let (popped, token) = token.pop_prefix_tokens(n);
let (popped, token) = token.pop_prefix_tokens_with(n, |first| {
first.unroot_boundary_component();
});
let mut offset: usize = popped
.into_iter()
.map(|token| *token.annotation().span())
Expand Down Expand Up @@ -239,34 +241,20 @@ 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.
pub trait Fold<'t, A> {
type Term;

fn initialize(&mut self, _branch: &BranchKind<'t, A>) -> Option<Self::Term> {
None
}

fn accumulate(
&mut self,
branch: &BranchKind<'t, A>,
accumulator: Self::Term,
term: Self::Term,
) -> Self::Term;

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

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

pub trait FoldBatch<'t, A> {
type Term;

fn initialize(&mut self, _branch: &BranchKind<'t, A>) -> Option<Self::Term> {
None
}

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 {
Expand Down Expand Up @@ -345,15 +333,6 @@ impl<'t, A> Token<'t, A> {
(vec![self], None)
}

fn pop_prefix_tokens(mut self, n: usize) -> (Vec<Self>, Option<Self>)
where
LeafKind<'t>: Unroot<A>,
{
self.pop_prefix_tokens_with(n, |first| {
first.unroot_boundary_component();
})
}

fn unroot_boundary_component(&mut self) -> bool
where
LeafKind<'t>: Unroot<A>,
Expand All @@ -367,6 +346,7 @@ impl<'t, A> Token<'t, A> {
where
F: Fold<'t, A>,
{
#[derive(Debug)]
struct Path<'i, 't, A, F>
where
F: Fold<'t, A>,
Expand All @@ -378,117 +358,6 @@ impl<'t, A> Token<'t, A> {
impl<'i, 't, A, F> Path<'i, 't, A, F>
where
F: Fold<'t, A>,
{
pub fn push(&mut self, branch: &'i BranchKind<'t, A>) {
self.summands.push(Summand {
branch,
accumulator: self.f.initialize(branch),
});
}

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

pub fn fold(mut self) -> Option<F::Term> {
self.fold_n(usize::MAX);
self.summands.pop().and_then(
|Summand {
branch,
accumulator,
}| self.f.finalize(branch, accumulator),
)
}

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.accumulate(term, &mut self.f);
Ok(())
},
None => Err(term),
}
}

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

struct Summand<'i, 't, A, F>
where
F: Fold<'t, A>,
{
branch: &'i BranchKind<'t, A>,
accumulator: Option<F::Term>,
}

impl<'i, 't, A, F> Summand<'i, 't, A, F>
where
F: Fold<'t, A>,
{
fn accumulate(&mut self, term: F::Term, f: &mut F) {
self.accumulator = Some(match self.accumulator.take() {
Some(accumulator) => f.accumulate(self.branch, accumulator, term),
_ => term,
});
}
}

let mut path = Path {
summands: vec![],
f,
};
let mut tokens = vec![(self, 0usize)];
while let Some((token, depth)) = tokens.pop() {
path.pop(depth);
match token.topology() {
Topology::Branch(ref branch) => {
tokens.extend(branch.tokens().map(|token| (token, depth + 1)));
path.push(branch);
},
Topology::Leaf(ref leaf) => {
if let Err(term) = path.accumulate(leaf) {
return Some(term);
}
},
}
}
path.fold()
}

pub fn fold_batch<F>(&self, f: F) -> Option<F::Term>
where
F: FoldBatch<'t, A>,
{
#[derive(Debug)]
struct Path<'i, 't, A, F>
where
F: FoldBatch<'t, A>,
{
summands: Vec<Summand<'i, 't, A, F>>,
f: F,
}

impl<'i, 't, A, F> Path<'i, 't, A, F>
where
F: FoldBatch<'t, A>,
{
pub fn push(&mut self, branch: &'i BranchKind<'t, A>) {
let mut terms = Vec::with_capacity(branch.tokens().len());
Expand Down Expand Up @@ -532,15 +401,15 @@ impl<'t, A> Token<'t, A> {
#[derive(Debug)]
struct Summand<'i, 't, A, F>
where
F: FoldBatch<'t, A>,
F: Fold<'t, A>,
{
branch: &'i BranchKind<'t, A>,
terms: Vec<F::Term>,
}

impl<'i, 't, A, F> Summand<'i, 't, A, F>
where
F: FoldBatch<'t, A>,
F: Fold<'t, A>,
{
fn push(&mut self, term: F::Term) {
self.terms.push(term)
Expand Down Expand Up @@ -591,7 +460,7 @@ impl<'t, A> Token<'t, A> {
}

pub fn components(&self) -> impl Iterator<Item = Component<'_, 't, A>> {
self.conjunction()
self.concatenation()
.into_iter()
.peekable()
.batching(|tokens| {
Expand Down Expand Up @@ -649,10 +518,10 @@ impl<'t, A> Token<'t, A> {

pub fn variance<T>(&self) -> Variance<T>
where
TreeVariance<T>: FoldBatch<'t, A, Term = Variance<T>>,
TreeVariance<T>: Fold<'t, A, Term = Variance<T>>,
T: Invariant,
{
self.fold_batch(TreeVariance::default())
self.fold(TreeVariance::default())
.unwrap_or_else(|| Variance::identity())
.map_invariant(|invariant| T::once() + invariant)
}
Expand Down Expand Up @@ -1733,23 +1602,6 @@ impl<'i, 't, A> Component<'i, 't, A> {
})
}
}

pub fn variance<T>(&self) -> Variance<T>
where
TreeVariance<T>: FoldBatch<'t, A, Term = Variance<T>>,
T: Invariant,
{
// TODO: While components are formed from the conjunction of a token, not all invariants
// can be properly summed this way, even in this context. For example, depth must sum via
// `union`.
//
// Note too that this is only used for text in `invariant_text_prefix`.
self.tokens()
.iter()
.copied()
.map(Token::variance::<T>)
.reduce(variance::conjunction)
}
}

impl<'i, 't, A> Clone for Component<'i, 't, A> {
Expand Down
4 changes: 2 additions & 2 deletions src/token/variance/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use std::marker::PhantomData;
use std::ops::Add;

use crate::token::variance::invariant::{Invariant, Text};

Check warning on line 9 in src/token/variance/mod.rs

View workflow job for this annotation

GitHub Actions / Lint

unused import: `Text`
use crate::token::{self, BranchKind, FoldBatch, LeafKind, Separator, Token};
use crate::token::{self, BranchKind, Fold, LeafKind, Separator, Token};

Check warning on line 10 in src/token/variance/mod.rs

View workflow job for this annotation

GitHub Actions / Lint

unused imports: `Separator`, `Token`, `self`

pub trait VarianceTerm<T> {
fn term(&self) -> Variance<T>;
Expand Down Expand Up @@ -239,7 +239,7 @@ impl<T> Default for TreeVariance<T> {
}
}

impl<'t, A, T> FoldBatch<'t, A> for TreeVariance<T>
impl<'t, A, T> Fold<'t, A> for TreeVariance<T>
where
BranchKind<'t, A>: VarianceFold<T>,
LeafKind<'t>: VarianceTerm<T>,
Expand Down

0 comments on commit 5d737b9

Please sign in to comment.