transfer commit

This commit is contained in:
2023-02-03 14:40:34 +00:00
parent a500f8b87a
commit 3c63cae242
63 changed files with 3227 additions and 2850 deletions

View File

@@ -17,27 +17,27 @@ use crate::utils::BoxedIter;
pub fn bfs<T, F, I>(init: T, neighbors: F)
-> impl Iterator<Item = T>
where T: Eq + Hash + Clone + std::fmt::Debug,
F: Fn(T) -> I, I: Iterator<Item = T>
F: Fn(T) -> I, I: Iterator<Item = T>
{
let mut visited: HashSet<T> = HashSet::new();
let mut visit_queue: VecDeque<T> = VecDeque::from([init]);
let mut unpack_queue: VecDeque<T> = VecDeque::new();
iter::from_fn(move || {
let next = {loop {
let next = unwrap_or!(visit_queue.pop_front(); break None);
if !visited.contains(&next) { break Some(next) }
}}.or_else(|| loop {
let unpacked = unwrap_or!(unpack_queue.pop_front(); break None);
let mut nbv = neighbors(unpacked).filter(|t| !visited.contains(t));
if let Some(next) = nbv.next() {
visit_queue.extend(nbv);
break Some(next)
}
})?;
visited.insert(next.clone());
unpack_queue.push_back(next.clone());
Some(next)
})
let mut visited: HashSet<T> = HashSet::new();
let mut visit_queue: VecDeque<T> = VecDeque::from([init]);
let mut unpack_queue: VecDeque<T> = VecDeque::new();
iter::from_fn(move || {
let next = {loop {
let next = unwrap_or!(visit_queue.pop_front(); break None);
if !visited.contains(&next) { break Some(next) }
}}.or_else(|| loop {
let unpacked = unwrap_or!(unpack_queue.pop_front(); break None);
let mut nbv = neighbors(unpacked).filter(|t| !visited.contains(t));
if let Some(next) = nbv.next() {
visit_queue.extend(nbv);
break Some(next)
}
})?;
visited.insert(next.clone());
unpack_queue.push_back(next.clone());
Some(next)
})
}
/// Same as [bfs] but with a recursion depth limit
@@ -48,66 +48,66 @@ where T: Eq + Hash + Clone + std::fmt::Debug,
pub fn bfs_upto<'a, T: 'a, F: 'a, I: 'a>(init: T, neighbors: F, limit: usize)
-> impl Iterator<Item = T> + 'a
where T: Eq + Hash + Clone + std::fmt::Debug,
F: Fn(T) -> I, I: Iterator<Item = T>
F: Fn(T) -> I, I: Iterator<Item = T>
{
/// Newtype to store the recursion depth but exclude it from equality comparisons
/// Because BFS visits nodes in increasing distance order, when a node is visited for the
/// second time it will never override the earlier version of itself. This is not the case
/// with Djikstra's algorithm, which can be conceptualised as a "weighted BFS".
#[derive(Eq, Clone, Debug)]
struct Wrap<U>(usize, U);
impl<U: PartialEq> PartialEq for Wrap<U> {
fn eq(&self, other: &Self) -> bool { self.1.eq(&other.1) }
}
impl<U: Hash> Hash for Wrap<U> {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) { self.1.hash(state) }
}
bfs(Wrap(0, init), move |Wrap(dist, t)| -> BoxedIter<Wrap<T>> { // boxed because we branch
if dist == limit {Box::new(iter::empty())}
else {Box::new(neighbors(t).map(move |t| Wrap(dist + 1, t)))}
}).map(|Wrap(_, t)| t)
/// Newtype to store the recursion depth but exclude it from equality comparisons
/// Because BFS visits nodes in increasing distance order, when a node is visited for the
/// second time it will never override the earlier version of itself. This is not the case
/// with Djikstra's algorithm, which can be conceptualised as a "weighted BFS".
#[derive(Eq, Clone, Debug)]
struct Wrap<U>(usize, U);
impl<U: PartialEq> PartialEq for Wrap<U> {
fn eq(&self, other: &Self) -> bool { self.1.eq(&other.1) }
}
impl<U: Hash> Hash for Wrap<U> {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) { self.1.hash(state) }
}
bfs(Wrap(0, init), move |Wrap(dist, t)| -> BoxedIter<Wrap<T>> { // boxed because we branch
if dist == limit {Box::new(iter::empty())}
else {Box::new(neighbors(t).map(move |t| Wrap(dist + 1, t)))}
}).map(|Wrap(_, t)| t)
}
#[cfg(test)]
mod tests {
use itertools::Itertools;
use itertools::Itertools;
use super::*;
use super::*;
type Graph = Vec<Vec<usize>>;
fn neighbors(graph: &Graph, pt: usize) -> impl Iterator<Item = usize> + '_ {
graph[pt].iter().copied()
}
fn from_neighborhood_matrix(matrix: Vec<Vec<usize>>) -> Graph {
matrix.into_iter().map(|v| {
v.into_iter().enumerate().filter_map(|(i, ent)| {
if ent > 1 {panic!("Neighborhood matrices must contain binary values")}
else if ent == 1 {Some(i)}
else {None}
}).collect()
}).collect()
}
type Graph = Vec<Vec<usize>>;
fn neighbors(graph: &Graph, pt: usize) -> impl Iterator<Item = usize> + '_ {
graph[pt].iter().copied()
}
fn from_neighborhood_matrix(matrix: Vec<Vec<usize>>) -> Graph {
matrix.into_iter().map(|v| {
v.into_iter().enumerate().filter_map(|(i, ent)| {
if ent > 1 {panic!("Neighborhood matrices must contain binary values")}
else if ent == 1 {Some(i)}
else {None}
}).collect()
}).collect()
}
#[test]
fn test_square() {
let simple_graph = from_neighborhood_matrix(vec![
vec![0,1,0,1,1,0,0,0],
vec![1,0,1,0,0,1,0,0],
vec![0,1,0,1,0,0,1,0],
vec![1,0,1,0,0,0,0,1],
vec![1,0,0,0,0,1,0,1],
vec![0,1,0,0,1,0,1,0],
vec![0,0,1,0,0,1,0,1],
vec![0,0,0,1,1,0,1,0],
]);
let scan = bfs(0, |n| neighbors(&simple_graph, n)).collect_vec();
assert_eq!(scan, vec![0, 1, 3, 4, 2, 5, 7, 6])
}
#[test]
fn test_stringbuilder() {
let scan = bfs("".to_string(), |s| {
vec![s.clone()+";", s.clone()+"a", s+"aaa"].into_iter()
}).take(30).collect_vec();
println!("{scan:?}")
}
#[test]
fn test_square() {
let simple_graph = from_neighborhood_matrix(vec![
vec![0,1,0,1,1,0,0,0],
vec![1,0,1,0,0,1,0,0],
vec![0,1,0,1,0,0,1,0],
vec![1,0,1,0,0,0,0,1],
vec![1,0,0,0,0,1,0,1],
vec![0,1,0,0,1,0,1,0],
vec![0,0,1,0,0,1,0,1],
vec![0,0,0,1,1,0,1,0],
]);
let scan = bfs(0, |n| neighbors(&simple_graph, n)).collect_vec();
assert_eq!(scan, vec![0, 1, 3, 4, 2, 5, 7, 6])
}
#[test]
fn test_stringbuilder() {
let scan = bfs("".to_string(), |s| {
vec![s.clone()+";", s.clone()+"a", s+"aaa"].into_iter()
}).take(30).collect_vec();
println!("{scan:?}")
}
}

View File

@@ -4,93 +4,93 @@ use mappable_rc::Mrc;
/// Convenience trait for overriding Mrc's strange cloning logic
pub trait MyClone {
fn my_clone(&self) -> Self;
fn my_clone(&self) -> Self;
}
impl<T> MyClone for T where T: Clone {
default fn my_clone(&self) -> Self { self.clone() }
default fn my_clone(&self) -> Self { self.clone() }
}
impl<T: ?Sized> MyClone for Rc<T> {
fn my_clone(&self) -> Self { Rc::clone(self) }
fn my_clone(&self) -> Self { Rc::clone(self) }
}
impl<T: ?Sized> MyClone for Mrc<T> {
fn my_clone(&self) -> Self { Mrc::clone(self) }
fn my_clone(&self) -> Self { Mrc::clone(self) }
}
/// Cache the return values of an effectless closure in a hashmap
/// Inspired by the closure_cacher crate.
pub struct Cache<'a, I, O: 'static> {
store: RefCell<HashMap<I, Mrc<O>>>,
closure: Box<dyn Fn (I, &Self) -> Mrc<O> + 'a>
store: RefCell<HashMap<I, Mrc<O>>>,
closure: Box<dyn Fn (I, &Self) -> Mrc<O> + 'a>
}
impl<'a, I, O> Cache<'a, I, O> where
I: Eq + Hash + MyClone
I: Eq + Hash + MyClone
{
pub fn new<F: 'a>(closure: F) -> Self where F: Fn(I, &Self) -> O {
Self::new_raw(move |o, s| Mrc::new(closure(o, s)))
}
pub fn new<F: 'a>(closure: F) -> Self where F: Fn(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: Fn(I, &Self) -> Mrc<O> {
Self {
store: RefCell::new(HashMap::new()),
closure: Box::new(closure)
}
/// 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: Fn(I, &Self) -> Mrc<O> {
Self {
store: RefCell::new(HashMap::new()),
closure: Box::new(closure)
}
}
/// Produce and cache a result by cloning I if necessary
pub fn find(&self, i: &I) -> Mrc<O> {
let closure = &self.closure;
if let Some(v) = self.store.borrow().get(i) {
return Mrc::clone(v)
}
// In the moment of invocation the refcell is on immutable
// this is important for recursive calculations
let result = closure(i.my_clone(), self);
let mut store = self.store.borrow_mut();
Mrc::clone(store.raw_entry_mut().from_key(i)
.or_insert_with(|| (i.my_clone(), result)).1)
/// Produce and cache a result by cloning I if necessary
pub fn find(&self, i: &I) -> Mrc<O> {
let closure = &self.closure;
if let Some(v) = self.store.borrow().get(i) {
return Mrc::clone(v)
}
// In the moment of invocation the refcell is on immutable
// this is important for recursive calculations
let result = closure(i.my_clone(), self);
let mut store = self.store.borrow_mut();
Mrc::clone(store.raw_entry_mut().from_key(i)
.or_insert_with(|| (i.my_clone(), result)).1)
}
#[allow(dead_code)]
/// Return the result if it has already been computed
pub fn known(&self, i: &I) -> Option<Mrc<O>> {
let store = self.store.borrow();
store.get(i).map(Mrc::clone)
}
#[allow(dead_code)]
/// Forget the output for the given input
pub fn drop(&self, i: &I) -> bool {
self.store.borrow_mut().remove(i).is_some()
}
#[allow(dead_code)]
/// Return the result if it has already been computed
pub fn known(&self, i: &I) -> Option<Mrc<O>> {
let store = self.store.borrow();
store.get(i).map(Mrc::clone)
}
#[allow(dead_code)]
/// Forget the output for the given input
pub fn drop(&self, i: &I) -> bool {
self.store.borrow_mut().remove(i).is_some()
}
}
impl<'a, I, O, E> Cache<'a, I, Result<O, E>> where
I: Eq + Hash + MyClone,
// O: Clone,
E: Clone
I: Eq + Hash + MyClone,
// O: Clone,
E: Clone
{
/// Sink the ref from a Result into the Ok value, such that cloning only occurs on the sad path
/// but the return value can be short-circuited
pub fn try_find(&self, i: &I) -> Result<Mrc<O>, E> {
let ent = self.find(i);
Mrc::try_map(ent, |t| t.as_ref().ok())
.map_err(|res| Result::as_ref(&res).err().unwrap().to_owned())
}
/// Sink the ref from a Result into the Ok value, such that cloning only occurs on the sad path
/// but the return value can be short-circuited
pub fn try_find(&self, i: &I) -> Result<Mrc<O>, E> {
let ent = self.find(i);
Mrc::try_map(ent, |t| t.as_ref().ok())
.map_err(|res| Result::as_ref(&res).err().unwrap().to_owned())
}
}
impl<'a, I, O> Cache<'a, I, Option<O>> where
I: Eq + Hash + MyClone,
// O: Clone
I: Eq + Hash + MyClone,
// O: Clone
{
#[allow(dead_code)]
/// Sink the ref from an Option into the Some value such that the return value can be
/// short-circuited
pub fn try_find(&self, i: &I) -> Option<Mrc<O>> where I: Clone {
let ent = self.find(i);
Mrc::try_map(ent, |o| o.as_ref()).ok()
}
#[allow(dead_code)]
/// Sink the ref from an Option into the Some value such that the return value can be
/// short-circuited
pub fn try_find(&self, i: &I) -> Option<Mrc<O>> where I: Clone {
let ent = self.find(i);
Mrc::try_map(ent, |o| o.as_ref()).ok()
}
}

View File

@@ -11,10 +11,10 @@
///
/// ```
/// xloop!(for i in 0..10; {
/// connection.try_connect()
/// if connection.ready() {
/// break Some(connection)
/// }
/// connection.try_connect()
/// if connection.ready() {
/// break Some(connection)
/// }
/// }; None)
/// ```
///
@@ -22,17 +22,17 @@
///
/// ```
/// xloop!(while socket.is_open(); {
/// let (data, is_end) = socket.read();
/// all_data.append(data)
/// if is_end { break Ok(all_data) }
/// let (data, is_end) = socket.read();
/// all_data.append(data)
/// if is_end { break Ok(all_data) }
/// }; {
/// if let Ok(new_sock) = open_socket(socket.position()) {
/// new_sock.set_position(socket.position());
/// socket = new_sock;
/// continue
/// } else {
/// Err(DownloadError::ConnectionLost)
/// }
/// if let Ok(new_sock) = open_socket(socket.position()) {
/// new_sock.set_position(socket.position());
/// socket = new_sock;
/// continue
/// } else {
/// Err(DownloadError::ConnectionLost)
/// }
/// })
/// ```
///
@@ -40,7 +40,7 @@
///
/// ```
/// xloop!(let mut leap = 1; own_id*2 + leap < batch_size; leap *= 2; {
/// batch[own_id*2] += batch[own_id*2 + leap]
/// batch[own_id*2] += batch[own_id*2 + leap]
/// })
/// ```
///
@@ -51,41 +51,41 @@
/// **todo** find a valid use case for While let for a demo
#[macro_export]
macro_rules! xloop {
(for $p:pat in $it:expr; $body:stmt) => {
xloop!(for $p in $it; $body; ())
};
(for $p:pat in $it:expr; $body:stmt; $exit:stmt) => {
{
let mut __xloop__ = $it.into_iter();
xloop!(let Some($p) = __xloop__.next(); $body; $exit)
}
};
(let $p:pat = $e:expr; $body:stmt) => {
xloop!(let $p = $e; $body; ())
};
(let $p:pat = $e:expr; $body:stmt; $exit:stmt) => {
{
loop {
if let $p = $e { $body }
else { break { $exit } }
}
}
};
(while $cond:expr; $body:stmt) => {
xloop!($cond; $body; ())
};
(while $cond:expr; $body:stmt; $exit:stmt) => {
{
loop {
if $cond { break { $exit } }
else { $body }
}
}
};
($init:stmt; $cond:expr; $step:stmt; $body:stmt) => {
xloop!(for ( $init; $cond; $step ) $body; ())
};
($init:stmt; $cond:expr; $step:stmt; $body:stmt; $exit:stmt) => {
{ $init; xloop!(while !($cond); { $body; $step }; $exit) }
};
(for $p:pat in $it:expr; $body:stmt) => {
xloop!(for $p in $it; $body; ())
};
(for $p:pat in $it:expr; $body:stmt; $exit:stmt) => {
{
let mut __xloop__ = $it.into_iter();
xloop!(let Some($p) = __xloop__.next(); $body; $exit)
}
};
(let $p:pat = $e:expr; $body:stmt) => {
xloop!(let $p = $e; $body; ())
};
(let $p:pat = $e:expr; $body:stmt; $exit:stmt) => {
{
loop {
if let $p = $e { $body }
else { break { $exit } }
}
}
};
(while $cond:expr; $body:stmt) => {
xloop!($cond; $body; ())
};
(while $cond:expr; $body:stmt; $exit:stmt) => {
{
loop {
if $cond { break { $exit } }
else { $body }
}
}
};
($init:stmt; $cond:expr; $step:stmt; $body:stmt) => {
xloop!(for ( $init; $cond; $step ) $body; ())
};
($init:stmt; $cond:expr; $step:stmt; $body:stmt; $exit:stmt) => {
{ $init; xloop!(while !($cond); { $body; $step }; $exit) }
};
}

View File

@@ -6,31 +6,31 @@ pub type BoxedIter<'a, T> = Box<dyn Iterator<Item = T> + 'a>;
pub type BoxedIterIter<'a, T> = BoxedIter<'a, BoxedIter<'a, T>>;
/// BoxedIter of a single element
pub fn box_once<'a, T: 'a>(t: T) -> BoxedIter<'a, T> {
Box::new(iter::once(t))
Box::new(iter::once(t))
}
/// BoxedIter of no elements
pub fn box_empty<'a, T: 'a>() -> BoxedIter<'a, T> {
Box::new(iter::empty())
Box::new(iter::empty())
}
#[macro_export]
macro_rules! box_chain {
($curr:expr) => {
Box::new($curr) as BoxedIter<_>
};
($curr:expr, $($rest:expr),*) => {
Box::new($curr$(.chain($rest))*) as $crate::utils::iter::BoxedIter<_>
};
($curr:expr) => {
Box::new($curr) as BoxedIter<_>
};
($curr:expr, $($rest:expr),*) => {
Box::new($curr$(.chain($rest))*) as $crate::utils::iter::BoxedIter<_>
};
}
pub fn box_flatten<'a, T: 'a, I: 'a, J: 'a>(i: I) -> BoxedIter<'a, T>
where
J: Iterator<Item = T>,
I: Iterator<Item = J>,
J: Iterator<Item = T>,
I: Iterator<Item = J>,
{
Box::new(i.flatten())
Box::new(i.flatten())
}
pub fn into_boxed_iter<'a, T: 'a>(t: T) -> BoxedIter<'a, <T as IntoIterator>::Item>
where T: IntoIterator {
Box::new(t.into_iter())
Box::new(t.into_iter())
}

View File

@@ -5,23 +5,23 @@ use std::mem;
/// 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,
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))
})
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))
})
}

View File

@@ -1,78 +1,85 @@
mod cache;
pub mod translate;
pub use cache::Cache;
mod substack;
pub use substack::Stackframe;
mod side;
pub use side::Side;
mod merge_sorted;
pub use merge_sorted::merge_sorted;
mod unwrap_or;
pub mod iter;
pub use iter::BoxedIter;
mod bfs;
mod unless_let;
mod string_from_charset;
pub use string_from_charset::string_from_charset;
mod for_loop;
mod protomap;
pub use cache::Cache;
use mappable_rc::Mrc;
pub use substack::Stackframe;
pub use side::Side;
pub use merge_sorted::merge_sorted;
pub use iter::BoxedIter;
pub use string_from_charset::string_from_charset;
pub use protomap::ProtoMap;
mod product2;
pub use product2::Product2;
use mappable_rc::Mrc;
pub fn mrc_derive<T: ?Sized, P, U: ?Sized>(m: &Mrc<T>, p: P) -> Mrc<U>
where P: for<'a> FnOnce(&'a T) -> &'a U {
Mrc::map(Mrc::clone(m), p)
Mrc::map(Mrc::clone(m), p)
}
pub fn mrc_try_derive<T: ?Sized, P, U: ?Sized>(m: &Mrc<T>, p: P) -> Option<Mrc<U>>
where P: for<'a> FnOnce(&'a T) -> Option<&'a U> {
Mrc::try_map(Mrc::clone(m), p).ok()
Mrc::try_map(Mrc::clone(m), p).ok()
}
pub fn mrc_empty_slice<T>() -> Mrc<[T]> {
mrc_derive_slice(&Mrc::new(Vec::new()))
mrc_derive_slice(&Mrc::new(Vec::new()))
}
pub fn to_mrc_slice<T>(v: Vec<T>) -> Mrc<[T]> {
Mrc::map(Mrc::new(v), |v| v.as_slice())
Mrc::map(Mrc::new(v), |v| v.as_slice())
}
pub fn collect_to_mrc<I>(iter: I) -> Mrc<[I::Item]> where I: Iterator {
to_mrc_slice(iter.collect())
to_mrc_slice(iter.collect())
}
pub fn mrc_derive_slice<T>(mv: &Mrc<Vec<T>>) -> Mrc<[T]> {
mrc_derive(mv, |v| v.as_slice())
mrc_derive(mv, |v| v.as_slice())
}
pub fn one_mrc_slice<T>(t: T) -> Mrc<[T]> {
Mrc::map(Mrc::new([t; 1]), |v| v.as_slice())
Mrc::map(Mrc::new([t; 1]), |v| v.as_slice())
}
pub fn mrc_to_iter<T>(ms: Mrc<[T]>) -> impl Iterator<Item = Mrc<T>> {
let mut i = 0;
std::iter::from_fn(move || if i < ms.len() {
let out = Some(mrc_derive(&ms, |s| &s[i]));
i += 1;
out
} else {None})
let mut i = 0;
std::iter::from_fn(move || if i < ms.len() {
let out = Some(mrc_derive(&ms, |s| &s[i]));
i += 1;
out
} else {None})
}
pub fn mrc_unnest<T>(m: &Mrc<Mrc<T>>) -> Mrc<T> {
Mrc::clone(m.as_ref())
Mrc::clone(m.as_ref())
}
pub fn mrc_slice_to_only<T>(m: Mrc<[T]>) -> Result<Mrc<T>, ()> {
Mrc::try_map(m, |slice| {
if slice.len() != 1 {None}
else {Some(&slice[0])}
}).map_err(|_| ())
Mrc::try_map(m, |slice| {
if slice.len() != 1 {None}
else {Some(&slice[0])}
}).map_err(|_| ())
}
pub fn mrc_slice_to_only_option<T>(m: Mrc<[T]>) -> Result<Option<Mrc<T>>, ()> {
if m.len() > 1 {return Err(())}
Ok(Mrc::try_map(m, |slice| {
if slice.len() == 0 {None}
else {Some(&slice[0])}
}).ok())
if m.len() > 1 {return Err(())}
Ok(Mrc::try_map(m, |slice| {
if slice.len() == 0 {None}
else {Some(&slice[0])}
}).ok())
}
pub fn mrc_concat<T: Clone>(a: &Mrc<[T]>, b: &Mrc<[T]>) -> Mrc<[T]> {
collect_to_mrc(a.iter().chain(b.iter()).cloned())
}

53
src/utils/product2.rs Normal file
View File

@@ -0,0 +1,53 @@
use super::Side;
/// The output of a two-part algorithm. The values are
///
/// - [Product2::Left] or [Product2::Right] if one of the arguments is the product
/// - [Product2::Either] if the arguments are identical
/// - [Product2::New] if the product is a different value from either
pub enum Product2<T> {
Left,
Right,
Either,
New(T)
}
impl<T> Product2<T> {
/// Convert the product into a concrete value by providing the original arguments
pub fn pick(self, left: T, right: T) -> T {
match self {
Self::Left | Self::Either => left,
Self::Right => right,
Self::New(t) => t
}
}
/// Combine some subresults into a tuple representing a greater result
pub fn join<U>(
self, (lt, rt): (T, T),
second: Product2<U>, (lu, ru): (U, U)
) -> Product2<(T, U)> {
match (self, second) {
(Self::Either, Product2::Either) => Product2::Either,
(Self::Left | Self::Either, Product2::Left | Product2::Either) => Product2::Left,
(Self::Right | Self::Either, Product2::Right | Product2::Either) => Product2::Right,
(t, u) => Product2::New((t.pick(lt, rt), u.pick(lu, ru)))
}
}
/// Translate results back into the type of the original problem.
pub fn map<A, F: FnOnce(T) -> A>(self, f: F) -> Product2<A> {
match self {
Product2::Left => Product2::Left, Product2::Right => Product2::Right,
Product2::Either => Product2::Either,
Product2::New(t) => Product2::New(f(t))
}
}
}
/// Technically very different but sometimes neecessary to translate
impl<T> From<Side> for Product2<T> {
fn from(value: Side) -> Self {match value {
Side::Left => Self::Left,
Side::Right => Self::Right
}}
}

View File

@@ -13,152 +13,152 @@ const INLINE_ENTRIES: usize = 2;
/// plus wasted stack space which is likely wasted L1 as well. The cost of underruns is wasted stack
/// space.
pub struct ProtoMap<'a, K, V, const STACK_COUNT: usize = 2> {
entries: SmallVec<[(K, Option<V>); STACK_COUNT]>,
prototype: Option<&'a ProtoMap<'a, K, V, STACK_COUNT>>
entries: SmallVec<[(K, Option<V>); STACK_COUNT]>,
prototype: Option<&'a ProtoMap<'a, K, V, STACK_COUNT>>
}
impl<'a, K, V, const STACK_COUNT: usize> ProtoMap<'a, K, V, STACK_COUNT> {
pub fn new() -> Self {
Self {
entries: SmallVec::new(),
prototype: None
}
pub fn new() -> Self {
Self {
entries: SmallVec::new(),
prototype: None
}
}
/// Mutable reference to entry without checking proto in O(m)
fn local_entry_mut<'b, Q: ?Sized>(&'b mut self, query: &Q)
-> Option<(usize, &'b mut K, &'b mut Option<V>)>
where K: Borrow<Q>, Q: Eq
{
self.entries.iter_mut().enumerate().find_map(|(i, (k, v))| {
if query.eq((*k).borrow()) { Some((i, k, v)) } else { None }
})
}
/// Mutable reference to entry without checking proto in O(m)
fn local_entry_mut<'b, Q: ?Sized>(&'b mut self, query: &Q)
-> Option<(usize, &'b mut K, &'b mut Option<V>)>
where K: Borrow<Q>, Q: Eq
{
self.entries.iter_mut().enumerate().find_map(|(i, (k, v))| {
if query.eq((*k).borrow()) { Some((i, k, v)) } else { None }
})
}
/// Entry without checking proto in O(m)
fn local_entry<'b, Q: ?Sized>(&'b self, query: &Q)
-> Option<(usize, &'b K, &'b Option<V>)>
where K: Borrow<Q>, Q: Eq
{
self.entries.iter().enumerate().find_map(|(i, (k, v))| {
if query.eq((*k).borrow()) { Some((i, k, v)) } else { None }
})
}
/// Entry without checking proto in O(m)
fn local_entry<'b, Q: ?Sized>(&'b self, query: &Q)
-> Option<(usize, &'b K, &'b Option<V>)>
where K: Borrow<Q>, Q: Eq
{
self.entries.iter().enumerate().find_map(|(i, (k, v))| {
if query.eq((*k).borrow()) { Some((i, k, v)) } else { None }
})
}
/// Find entry in prototype chain in O(n)
pub fn get<'b, Q: ?Sized>(&'b self, query: &Q) -> Option<&'b V>
where K: Borrow<Q>, Q: Eq
{
if let Some((_, _, v)) = self.local_entry(query) {
v.as_ref()
} else {
self.prototype?.get(query)
}
/// Find entry in prototype chain in O(n)
pub fn get<'b, Q: ?Sized>(&'b self, query: &Q) -> Option<&'b V>
where K: Borrow<Q>, Q: Eq
{
if let Some((_, _, v)) = self.local_entry(query) {
v.as_ref()
} else {
self.prototype?.get(query)
}
}
/// Record a value for the given key in O(m)
pub fn set(&mut self, key: &K, value: V) where K: Eq + Clone {
if let Some((_, _, v)) = self.local_entry_mut(key) {
*v = Some(value);
} else {
self.entries.push((key.clone(), Some(value)))
}
/// Record a value for the given key in O(m)
pub fn set(&mut self, key: &K, value: V) where K: Eq + Clone {
if let Some((_, _, v)) = self.local_entry_mut(key) {
*v = Some(value);
} else {
self.entries.push((key.clone(), Some(value)))
}
}
/// Delete in a memory-efficient way in O(n)
pub fn delete_small(&mut self, key: &K) where K: Eq + Clone {
let exists_up = self.prototype.and_then(|p| p.get(key)).is_some();
let local_entry = self.local_entry_mut(key);
match (exists_up, local_entry) {
(false, None) => (), // nothing to do
(false, Some((i, _, _))) => { self.entries.remove(i); }, // forget locally
(true, Some((_, _, v))) => *v = None, // update local override to cover
(true, None) => self.entries.push((key.clone(), None)), // create new
}
/// Delete in a memory-efficient way in O(n)
pub fn delete_small(&mut self, key: &K) where K: Eq + Clone {
let exists_up = self.prototype.and_then(|p| p.get(key)).is_some();
let local_entry = self.local_entry_mut(key);
match (exists_up, local_entry) {
(false, None) => (), // nothing to do
(false, Some((i, _, _))) => { self.entries.remove(i); }, // forget locally
(true, Some((_, _, v))) => *v = None, // update local override to cover
(true, None) => self.entries.push((key.clone(), None)), // create new
}
}
/// Delete in O(m) without checking the prototype chain
/// May produce unnecessary cover over previously unknown key
pub fn delete_fast(&mut self, key: &K) where K: Eq + Clone {
if let Some((_, _, v)) = self.local_entry_mut(key) {
*v = None
} else {
self.entries.push((key.clone(), None))
}
/// Delete in O(m) without checking the prototype chain
/// May produce unnecessary cover over previously unknown key
pub fn delete_fast(&mut self, key: &K) where K: Eq + Clone {
if let Some((_, _, v)) = self.local_entry_mut(key) {
*v = None
} else {
self.entries.push((key.clone(), None))
}
}
/// Iterate over the values defined herein and on the prototype chain
/// Note that this will visit keys multiple times
pub fn iter(&self) -> impl Iterator<Item = &(K, Option<V>)> {
let mut map = self;
iter::from_fn(move || {
let pairs = map.entries.iter();
map = map.prototype?;
Some(pairs)
}).flatten()
}
/// Iterate over the values defined herein and on the prototype chain
/// Note that this will visit keys multiple times
pub fn iter(&self) -> impl Iterator<Item = &(K, Option<V>)> {
let mut map = self;
iter::from_fn(move || {
let pairs = map.entries.iter();
map = map.prototype?;
Some(pairs)
}).flatten()
}
/// Visit the keys in an unsafe random order, repeated arbitrarily many times
pub fn keys(&self) -> impl Iterator<Item = &K> {
self.iter().map(|(k, _)| k)
}
/// Visit the keys in an unsafe random order, repeated arbitrarily many times
pub fn keys(&self) -> impl Iterator<Item = &K> {
self.iter().map(|(k, _)| k)
}
/// Visit the values in random order
pub fn values(&self) -> impl Iterator<Item = &V> {
self.iter().filter_map(|(_, v)| v.as_ref())
}
/// Visit the values in random order
pub fn values(&self) -> impl Iterator<Item = &V> {
self.iter().filter_map(|(_, v)| v.as_ref())
}
/// Update the prototype, and correspondingly the lifetime of the map
pub fn set_proto<'b>(self, proto: &'b ProtoMap<'b, K, V, STACK_COUNT>)
-> ProtoMap<'b, K, V, STACK_COUNT> {
ProtoMap {
entries: self.entries,
prototype: Some(proto)
}
/// Update the prototype, and correspondingly the lifetime of the map
pub fn set_proto<'b>(self, proto: &'b ProtoMap<'b, K, V, STACK_COUNT>)
-> ProtoMap<'b, K, V, STACK_COUNT> {
ProtoMap {
entries: self.entries,
prototype: Some(proto)
}
}
}
impl<T, K, V, const STACK_COUNT: usize>
From<T> for ProtoMap<'_, K, V, STACK_COUNT>
where T: IntoIterator<Item = (K, V)> {
fn from(value: T) -> Self {
Self {
entries: value.into_iter().map(|(k, v)| (k, Some(v))).collect(),
prototype: None
}
fn from(value: T) -> Self {
Self {
entries: value.into_iter().map(|(k, v)| (k, Some(v))).collect(),
prototype: None
}
}
}
impl<Q: ?Sized, K, V, const STACK_COUNT: usize>
Index<&Q> for ProtoMap<'_, K, V, STACK_COUNT>
where K: Borrow<Q>, Q: Eq {
type Output = V;
fn index(&self, index: &Q) -> &Self::Output {
self.get(index).expect("Index not found in map")
}
type Output = V;
fn index(&self, index: &Q) -> &Self::Output {
self.get(index).expect("Index not found in map")
}
}
impl<K: Clone, V: Clone, const STACK_COUNT: usize>
Clone for ProtoMap<'_, K, V, STACK_COUNT> {
fn clone(&self) -> Self {
Self {
entries: self.entries.clone(),
prototype: self.prototype
}
fn clone(&self) -> Self {
Self {
entries: self.entries.clone(),
prototype: self.prototype
}
}
}
impl<'a, K: 'a, V: 'a, const STACK_COUNT: usize>
Add<(K, V)> for &'a ProtoMap<'a, K, V, STACK_COUNT> {
type Output = ProtoMap<'a, K, V, STACK_COUNT>;
fn add(self, rhs: (K, V)) -> Self::Output {
ProtoMap::from([rhs]).set_proto(self)
}
type Output = ProtoMap<'a, K, V, STACK_COUNT>;
fn add(self, rhs: (K, V)) -> Self::Output {
ProtoMap::from([rhs]).set_proto(self)
}
}
#[macro_export]
macro_rules! protomap {
($($ent:expr),*) => {
ProtoMap::from([$($ent:expr),*])
};
($($ent:expr),*) => {
ProtoMap::from([$($ent:expr),*])
};
}

View File

@@ -4,50 +4,50 @@ use std::fmt::Display;
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"),
}
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
}
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..]
}
}
/// 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 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
}
/// 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)
}
}
/// 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)
}
}
}

View File

@@ -1,14 +1,14 @@
fn string_from_charset_rec(val: u64, digits: &str) -> String {
let radix = digits.len() as u64;
let mut prefix = if val > radix {
string_from_charset_rec(val / radix, digits)
} else {String::new()};
prefix.push(digits.chars().nth(val as usize - 1).unwrap_or_else(
|| panic!("Overindexed digit set \"{}\" with {}", digits, val - 1)
));
prefix
let radix = digits.len() as u64;
let mut prefix = if val > radix {
string_from_charset_rec(val / radix, digits)
} else {String::new()};
prefix.push(digits.chars().nth(val as usize - 1).unwrap_or_else(
|| panic!("Overindexed digit set \"{}\" with {}", digits, val - 1)
));
prefix
}
pub fn string_from_charset(val: u64, digits: &str) -> String {
string_from_charset_rec(val + 1, digits)
string_from_charset_rec(val + 1, digits)
}

View File

@@ -5,70 +5,84 @@ use std::fmt::Debug;
/// deep enough to warrant a heap-allocated set
#[derive(Clone, Copy)]
pub struct Stackframe<'a, T> {
pub item: T,
pub prev: Option<&'a Stackframe<'a, T>>,
pub len: usize
pub item: T,
pub prev: Option<&'a Stackframe<'a, T>>,
pub len: usize
}
impl<'a, T: 'a> Stackframe<'a, T> {
pub fn new(item: T) -> Self {
Self {
item,
prev: None,
len: 1
}
pub fn new(item: T) -> Self {
Self {
item,
prev: None,
len: 1
}
/// 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) }
}
/// 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),
len: self.len + 1
}
pub fn push(&self, item: T) -> Stackframe<'_, T> {
Stackframe {
item,
prev: Some(self),
len: self.len + 1
}
}
pub fn opush(prev: Option<&Self>, item: T) -> Self {
Self {
item,
prev,
len: prev.map_or(1, |s| s.len)
}
}
pub fn len(&self) -> usize { self.len }
pub fn pop(&self, count: usize) -> Option<&Self> {
if count == 0 {Some(self)}
else {self.prev.expect("Index out of range").pop(count - 1)}
}
pub fn opop(cur: Option<&Self>, count: usize) -> Option<&Self> {
if count == 0 {cur}
else {Self::opop(cur.expect("Index out of range").prev, count - 1)}
}
pub fn opush(prev: Option<&'a Self>, item: T) -> Self {
Self {
item,
prev,
len: prev.map_or(1, |s| s.len)
}
}
pub fn len(&self) -> usize { self.len }
pub fn pop(&self, count: usize) -> Option<&Self> {
if count == 0 {Some(self)}
else {self.prev.expect("Index out of range").pop(count - 1)}
}
pub fn opop(cur: Option<&Self>, count: usize) -> Option<&Self> {
if count == 0 {cur}
else {Self::opop(cur.expect("Index out of range").prev, count - 1)}
}
pub fn o_into_iter(curr: Option<&Self>) -> StackframeIterator<T> {
StackframeIterator { curr }
}
}
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()
}
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "Substack")?;
f.debug_list().entries(self.iter()).finish()
}
}
pub struct StackframeIterator<'a, T> {
curr: Option<&'a Stackframe<'a, T>>
curr: Option<&'a Stackframe<'a, T>>
}
impl<'a, T> StackframeIterator<'a, T> {
pub fn first_some<U, F: Fn(&T) -> Option<U>>(&mut self, f: F) -> Option<U> {
while let Some(x) = self.next() {
if let Some(result) = f(x) {
return Some(result)
}
}
None
}
}
impl<'a, T> Iterator for StackframeIterator<'a, T> {
type Item = &'a T;
fn next(&mut self) -> Option<&'a T> {
let curr = self.curr?;
let item = curr.item();
let prev = curr.prev();
self.curr = prev;
Some(item)
}
type Item = &'a T;
fn next(&mut self) -> Option<&'a T> {
let curr = self.curr?;
let item = curr.item();
let prev = curr.prev();
self.curr = prev;
Some(item)
}
}

22
src/utils/translate.rs Normal file
View File

@@ -0,0 +1,22 @@
use std::mem;
pub fn translate<T, F: FnOnce(T) -> T>(data: &mut T, f: F) {
unsafe {
let mut acc = mem::MaybeUninit::<T>::uninit().assume_init();
mem::swap(&mut acc, data);
let mut new = f(acc);
mem::swap(&mut new, data);
mem::forget(new);
}
}
pub fn process<T, U, F: FnOnce(T) -> (T, U)>(data: &mut T, f: F) -> U {
unsafe {
let mut acc = mem::MaybeUninit::<T>::uninit().assume_init();
mem::swap(&mut acc, data);
let (mut new, ret) = f(acc);
mem::swap(&mut new, data);
mem::forget(new);
ret
}
}

View File

@@ -1,6 +1,6 @@
#[macro_export]
macro_rules! unless_let {
($m:pat_param = $expr:tt) => {
if let $m = $expr {} else
}
($m:pat_param = $expr:tt) => {
if let $m = $expr {} else
}
}

View File

@@ -1,6 +1,6 @@
#[macro_export]
macro_rules! unwrap_or {
($m:expr; $fail:expr) => {
{ if let Some(res) = ($m) {res} else {$fail} }
}
($m:expr; $fail:expr) => {
{ if let Some(res) = ($m) {res} else {$fail} }
}
}