Skip to content

Commit

Permalink
add slice_accum
Browse files Browse the repository at this point in the history
  • Loading branch information
ngtkana committed Dec 14, 2024
1 parent 4709928 commit e6373da
Show file tree
Hide file tree
Showing 4 changed files with 99 additions and 5 deletions.
6 changes: 4 additions & 2 deletions libs/riff/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,18 +1,20 @@
//! Future and otherworldly Rust features.
mod binary_search;
mod bitmask_iterators;
mod bitmask_operations;
mod change_min_max;
mod numeric_traits;
mod pop_if;
mod slice_accum;
mod slice_binary_search;
mod slice_chunks;

pub use binary_search::BinarySearch;
pub use bitmask_iterators::bitmask_combinations;
pub use bitmask_iterators::bitmask_subsets;
pub use bitmask_operations::i2powm1;
pub use change_min_max::ChangeMinMax;
pub use numeric_traits::Unsigned;
pub use pop_if::PopIf;
pub use slice_accum::SliceAccum;
pub use slice_binary_search::SliceBinarySearch;
pub use slice_chunks::SliceChunks;
92 changes: 92 additions & 0 deletions libs/riff/src/slice_accum.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
use std::ops::AddAssign;
use std::ops::SubAssign;

/// Prefix sum, suffix sum, etc.
pub trait SliceAccum<T> {
/// Apply $f$ to each adjacent pair from left to right.
fn for_each_forward<F>(&mut self, f: F)
where
F: FnMut(&mut T, &mut T);

/// Apply $f$ to each adjacent pair from right to left.
fn for_each_backward<F>(&mut self, f: F)
where
F: FnMut(&mut T, &mut T);

/// Replace $A_i$ with $\sum_{j=0}^{i} A_j$.
fn prefix_sum(&mut self)
where
for<'a> T: AddAssign<&'a T>,
{
self.for_each_forward(|x, y| *x += y);
}

/// Replace $A_i$ with $A_i - A_{i-1}$.
fn prefix_sum_inv(&mut self)
where
for<'a> T: SubAssign<&'a T>,
{
self.for_each_backward(|x, y| *y -= x);
}

/// Replace $A_i$ with $\sum_{j=i}^{n-1} A_j$.
fn suffix_sum(&mut self)
where
for<'a> T: AddAssign<&'a T>,
{
self.for_each_backward(|x, y| *x += y);
}

/// Replace $A_i$ with $A_i - A_{i+1}$.
fn suffix_sum_inv(&mut self)
where
for<'a> T: SubAssign<&'a T>,
{
self.for_each_forward(|x, y| *y -= x);
}
}

impl<T> SliceAccum<T> for [T] {
fn for_each_forward<F>(&mut self, mut f: F)
where
F: FnMut(&mut T, &mut T),
{
for i in 1..self.len() {
let (left, right) = self.split_at_mut(i);
f(&mut right[0], &mut left[i - 1]);
}
}

fn for_each_backward<F>(&mut self, mut f: F)
where
F: FnMut(&mut T, &mut T),
{
for i in (1..self.len()).rev() {
let (left, right) = self.split_at_mut(i);
f(&mut left[i - 1], &mut right[0]);
}
}
}

#[cfg(test)]
mod tests {
use super::*;

#[test]
fn test_prefix_sum_by() {
let mut a = [1, 2, 3, 4, 5];
a.prefix_sum();
assert_eq!(a, [1, 3, 6, 10, 15]);
a.prefix_sum_inv();
assert_eq!(a, [1, 2, 3, 4, 5]);
}

#[test]
fn test_suffix_sum_by_for_empty() {
let mut a: [i32; 0] = [];
a.prefix_sum();
assert_eq!(a, []);
a.prefix_sum_inv();
assert_eq!(a, []);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use std::cmp::Ordering::Greater;
use std::cmp::Ordering::Less;

/// `{lower,upper}_bound`, etc
pub trait BinarySearch<T> {
pub trait SliceBinarySearch<T> {
fn partition_point<F: FnMut(&T) -> bool>(&self, pred: F) -> usize;
fn partition_point_value<F: FnMut(&T) -> bool>(&self, pred: F) -> Option<&T>;
fn lower_bound_by<F: FnMut(&T) -> Ordering>(&self, mut f: F) -> usize {
Expand Down Expand Up @@ -57,7 +57,7 @@ pub trait BinarySearch<T> {
}
}

impl<T> BinarySearch<T> for [T] {
impl<T> SliceBinarySearch<T> for [T] {
fn partition_point<F: FnMut(&T) -> bool>(&self, mut pred: F) -> usize {
self.binary_search_by(|x| if pred(x) { Less } else { Greater })
.unwrap_err()
Expand Down
2 changes: 1 addition & 1 deletion libs/riff/src/slice_chunks.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
/// A trait for slices.
/// Chunk by predicate.
pub trait SliceChunks {
type Item;
/// Groups adjacent elements by a predicate.
Expand Down

0 comments on commit e6373da

Please sign in to comment.