Mainly worked on the rule matcher
Also fixed the name collector, and lambda parameters are no longer resolved at parsing to support planned macro-based pattern matching. The rule matcher clones a lot, the number of clones could be zero.
This commit is contained in:
@@ -4,16 +4,21 @@ use mappable_rc::Mrc;
|
||||
|
||||
/// Cache the return values of an effectless closure in a hashmap
|
||||
/// Inspired by the closure_cacher crate.
|
||||
pub struct Cache<I, O: 'static> where O: Clone {
|
||||
pub struct Cache<'a, I, O: 'static> /*where O: Clone*/ {
|
||||
store: RefCell<HashMap<I, Mrc<O>>>,
|
||||
closure: RefCell<Box<dyn FnMut (I) -> O + 'static>>
|
||||
closure: RefCell<Box<dyn FnMut (I, &Self) -> Mrc<O> + 'a>>
|
||||
}
|
||||
|
||||
impl<I, O> Cache<I, O> where
|
||||
I: Eq + Hash + Clone,
|
||||
O: Clone
|
||||
impl<'a, I, O> Cache<'a, I, O> where
|
||||
I: Eq + Hash + Clone
|
||||
{
|
||||
pub fn new<F: 'static>(closure: F) -> Self where F: FnMut(I) -> O {
|
||||
pub fn new<F: 'a>(mut closure: F) -> Self where F: FnMut(I, &Self) -> O {
|
||||
Self::new_raw(move |o, s| Mrc::new(closure(o, s)))
|
||||
}
|
||||
|
||||
/// Take an Mrc<O> closure rather than an O closure
|
||||
/// Used internally to derive caches from other systems working with Mrc-s
|
||||
pub fn new_raw<F: 'a>(closure: F) -> Self where F: FnMut(I, &Self) -> Mrc<O> {
|
||||
Self {
|
||||
store: RefCell::new(HashMap::new()),
|
||||
closure: RefCell::new(Box::new(closure))
|
||||
@@ -25,7 +30,7 @@ impl<I, O> Cache<I, O> where
|
||||
let mut closure = self.closure.borrow_mut();
|
||||
let mut store = self.store.borrow_mut();
|
||||
Mrc::clone(store.raw_entry_mut().from_key(i)
|
||||
.or_insert_with(|| (i.clone(), Mrc::new(closure(i.clone())))).1)
|
||||
.or_insert_with(|| (i.clone(), closure(i.clone(), self))).1)
|
||||
}
|
||||
#[allow(dead_code)]
|
||||
/// Return the result if it has already been computed
|
||||
@@ -40,9 +45,9 @@ impl<I, O> Cache<I, O> where
|
||||
}
|
||||
}
|
||||
|
||||
impl<I, O, E> Cache<I, Result<O, E>> where
|
||||
impl<'a, I, O, E> Cache<'a, I, Result<O, E>> where
|
||||
I: Eq + Hash + Clone,
|
||||
O: Clone,
|
||||
// O: Clone,
|
||||
E: Clone
|
||||
{
|
||||
/// Sink the ref from a Result into the Ok value, such that cloning only occurs on the sad path
|
||||
@@ -54,9 +59,9 @@ impl<I, O, E> Cache<I, Result<O, E>> where
|
||||
}
|
||||
}
|
||||
|
||||
impl<I, O> Cache<I, Option<O>> where
|
||||
impl<'a, I, O> Cache<'a, I, Option<O>> where
|
||||
I: Eq + Hash + Clone,
|
||||
O: Clone
|
||||
// O: Clone
|
||||
{
|
||||
#[allow(dead_code)]
|
||||
/// Sink the ref from an Option into the Some value such that the return value can be
|
||||
@@ -65,4 +70,4 @@ impl<I, O> Cache<I, Option<O>> where
|
||||
let ent = self.find(i);
|
||||
Mrc::try_map(ent, |o| o.as_ref()).ok()
|
||||
}
|
||||
}
|
||||
}
|
||||
27
src/utils/merge_sorted.rs
Normal file
27
src/utils/merge_sorted.rs
Normal file
@@ -0,0 +1,27 @@
|
||||
use std::mem;
|
||||
|
||||
// use itertools::Itertools;
|
||||
|
||||
/// Merge two sorted iterators into a sorted iterator.
|
||||
pub fn merge_sorted<T, I, J, F, O>(mut i: I, mut j: J, mut f: F) -> impl Iterator<Item = T>
|
||||
where
|
||||
I: Iterator<Item = T>, J: Iterator<Item = T>,
|
||||
F: FnMut(&T) -> O, O: Ord,
|
||||
{
|
||||
let mut i_item: Option<T> = None;
|
||||
let mut j_item: Option<T> = None;
|
||||
std::iter::from_fn(move || {
|
||||
match (&mut i_item, &mut j_item) {
|
||||
(&mut None, &mut None) => None,
|
||||
(&mut None, j_item @ &mut Some(_)) => Some((j_item, None)),
|
||||
(i_item @ &mut Some(_), &mut None) => Some((i_item, i.next())),
|
||||
(Some(i_val), Some(j_val)) => Some(
|
||||
if f(i_val) < f(j_val) {
|
||||
(&mut i_item, i.next())
|
||||
} else {
|
||||
(&mut j_item, j.next())
|
||||
}
|
||||
)
|
||||
}.and_then(|(dest, value)| mem::replace(dest, value))
|
||||
})
|
||||
}
|
||||
@@ -1,6 +1,12 @@
|
||||
mod cache;
|
||||
mod substack;
|
||||
mod side;
|
||||
mod merge_sorted;
|
||||
mod sorted_pairs;
|
||||
mod unwrap_or_continue;
|
||||
pub use cache::Cache;
|
||||
pub use substack::Substack;
|
||||
pub use substack::Stackframe;
|
||||
pub use side::Side;
|
||||
pub use merge_sorted::merge_sorted;
|
||||
|
||||
pub type BoxedIter<'a, T> = Box<dyn Iterator<Item = T> + 'a>;
|
||||
53
src/utils/side.rs
Normal file
53
src/utils/side.rs
Normal file
@@ -0,0 +1,53 @@
|
||||
use std::fmt::Display;
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||
pub enum Side {Left, Right}
|
||||
|
||||
impl Display for Side {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
Self::Left => write!(f, "Left"),
|
||||
Self::Right => write!(f, "Right"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Side {
|
||||
pub fn opposite(&self) -> Self {
|
||||
match self {
|
||||
Self::Left => Self::Right,
|
||||
Self::Right => Self::Left
|
||||
}
|
||||
}
|
||||
/// Shorthand for opposite
|
||||
pub fn inv(&self) -> Self { self.opposite() }
|
||||
/// take N elements from this end of a slice
|
||||
pub fn slice<'a, T>(&self, size: usize, slice: &'a [T]) -> &'a [T] {
|
||||
match self {
|
||||
Side::Left => &slice[..size],
|
||||
Side::Right => &slice[slice.len() - size..]
|
||||
}
|
||||
}
|
||||
/// ignore N elements from this end of a slice
|
||||
pub fn crop<'a, T>(&self, margin: usize, slice: &'a [T]) -> &'a [T] {
|
||||
self.opposite().slice(slice.len() - margin, slice)
|
||||
}
|
||||
/// ignore N elements from this end and M elements from the other end of a slice
|
||||
pub fn crop_both<'a, T>(&self, margin: usize, opposite: usize, slice: &'a [T]) -> &'a [T] {
|
||||
self.crop(margin, self.opposite().crop(opposite, slice))
|
||||
}
|
||||
/// Pick this side from a pair of things
|
||||
pub fn pick<T>(&self, pair: (T, T)) -> T {
|
||||
match self {
|
||||
Side::Left => pair.0,
|
||||
Side::Right => pair.1
|
||||
}
|
||||
}
|
||||
/// Make a pair with the first element on this side
|
||||
pub fn pair<T>(&self, this: T, opposite: T) -> (T, T) {
|
||||
match self {
|
||||
Side::Left => (this, opposite),
|
||||
Side::Right => (opposite, this)
|
||||
}
|
||||
}
|
||||
}
|
||||
35
src/utils/sorted_pairs.rs
Normal file
35
src/utils/sorted_pairs.rs
Normal file
@@ -0,0 +1,35 @@
|
||||
use std::ops::Add;
|
||||
|
||||
/// Combine two sorted iterators with their mapper function into a sorted iterator of pairs
|
||||
pub struct SortedPairs<L, R, IL, IR, ML, MR, O> {
|
||||
left: IL, right: IR,
|
||||
left_map: ML, right_map: MR,
|
||||
left_buf: Vec<(L, O)>, right_buf: Vec<(R, O)>
|
||||
}
|
||||
|
||||
impl<L, R, IL, IR, ML, MR, O> SortedPairs<L, R, IL, IR, ML, MR, O>
|
||||
where IL: Iterator<Item = L>, IR: Iterator<Item = R>,
|
||||
ML: Fn(L) -> O, MR: Fn(R) -> O,
|
||||
O: Ord + Add + Clone
|
||||
{
|
||||
pub fn new(left: IL, right: IR, left_map: ML, right_map: MR) -> Self {
|
||||
Self {
|
||||
left, right, left_map, right_map,
|
||||
left_buf: Vec::new(),
|
||||
right_buf: Vec::new()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, L: 'a, R: 'a, IL: 'a, IR: 'a, ML: 'a, MR: 'a, O: 'a> Iterator
|
||||
for &'a mut SortedPairs<L, R, IL, IR, ML, MR, O>
|
||||
where IL: Iterator<Item = L>, IR: Iterator<Item = R>,
|
||||
ML: Fn(L) -> O, MR: Fn(R) -> O,
|
||||
O: Ord + Add + Clone,
|
||||
{
|
||||
type Item = (&'a L, &'a R);
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
@@ -1,45 +1,55 @@
|
||||
use std::fmt::Debug;
|
||||
|
||||
/// Implement a FILO stack that lives on the regular call stack as a linked list.
|
||||
/// Mainly useful to detect loops in recursive algorithms where the recursion isn't
|
||||
/// deep enough to warrant a heap-allocated set
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct Substack<'a, T> {
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct Stackframe<'a, T> {
|
||||
pub item: T,
|
||||
pub prev: Option<&'a Self>
|
||||
pub prev: Option<&'a Stackframe<'a, T>>
|
||||
}
|
||||
|
||||
impl<'a, T> Substack<'a, T> {
|
||||
#[allow(dead_code)]
|
||||
pub fn item(&self) -> &T { &self.item }
|
||||
#[allow(dead_code)]
|
||||
pub fn prev(&self) -> Option<&'a Substack<'a, T>> { self.prev }
|
||||
|
||||
impl<'a, T: 'a> Stackframe<'a, T> {
|
||||
pub fn new(item: T) -> Self {
|
||||
Self {
|
||||
item,
|
||||
prev: None
|
||||
}
|
||||
}
|
||||
pub fn push(&'a self, item: T) -> Self {
|
||||
Self {
|
||||
/// Get the item owned by this listlike, very fast O(1)
|
||||
pub fn item(&self) -> &T { &self.item }
|
||||
/// Get the next link in the list, very fast O(1)
|
||||
pub fn prev(&self) -> Option<&'a Stackframe<T>> { self.prev }
|
||||
/// Construct an iterator over the listlike, very fast O(1)
|
||||
pub fn iter(&self) -> StackframeIterator<T> {
|
||||
StackframeIterator { curr: Some(self) }
|
||||
}
|
||||
pub fn push(&self, item: T) -> Stackframe<'_, T> {
|
||||
Stackframe {
|
||||
item,
|
||||
prev: Some(self)
|
||||
}
|
||||
}
|
||||
pub fn iter(&'a self) -> SubstackIterator<'a, T> {
|
||||
SubstackIterator { curr: Some(self) }
|
||||
}
|
||||
|
||||
impl<'a, T> Debug for Stackframe<'a, T> where T: Debug {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "Substack")?;
|
||||
f.debug_list().entries(self.iter()).finish()
|
||||
}
|
||||
}
|
||||
|
||||
pub struct SubstackIterator<'a, T> {
|
||||
curr: Option<&'a Substack<'a, T>>
|
||||
pub struct StackframeIterator<'a, T> {
|
||||
curr: Option<&'a Stackframe<'a, T>>
|
||||
}
|
||||
|
||||
impl<'a, T> Iterator for SubstackIterator<'a, T> {
|
||||
impl<'a, T> Iterator for StackframeIterator<'a, T> {
|
||||
type Item = &'a T;
|
||||
fn next(&mut self) -> Option<&'a T> {
|
||||
let Substack{ item, prev } = self.curr?;
|
||||
self.curr = *prev;
|
||||
let curr = self.curr?;
|
||||
let item = curr.item();
|
||||
let prev = curr.prev();
|
||||
self.curr = prev;
|
||||
Some(item)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
6
src/utils/unwrap_or_continue.rs
Normal file
6
src/utils/unwrap_or_continue.rs
Normal file
@@ -0,0 +1,6 @@
|
||||
#[macro_export]
|
||||
macro_rules! unwrap_or_continue {
|
||||
($m:expr) => {
|
||||
{ if let Some(res) = ($m) {res} else {continue} }
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user