use crate::difference::Semigroup;
pub fn consolidate<T: Ord, R: Semigroup>(vec: &mut Vec<(T, R)>) {
consolidate_from(vec, 0);
}
pub fn consolidate_from<T: Ord, R: Semigroup>(vec: &mut Vec<(T, R)>, offset: usize) {
let length = consolidate_slice(&mut vec[offset..]);
vec.truncate(offset + length);
}
pub fn consolidate_slice<T: Ord, R: Semigroup>(slice: &mut [(T, R)]) -> usize {
slice.sort_by(|x,y| x.0.cmp(&y.0));
let mut offset = 0;
for index in 1 .. slice.len() {
unsafe {
assert!(offset < index);
let ptr1 = slice.as_mut_ptr().offset(offset as isize);
let ptr2 = slice.as_mut_ptr().offset(index as isize);
if (*ptr1).0 == (*ptr2).0 {
(*ptr1).1 += &(*ptr2).1;
}
else {
if !(*ptr1).1.is_zero() {
offset += 1;
}
let ptr1 = slice.as_mut_ptr().offset(offset as isize);
std::mem::swap(&mut *ptr1, &mut *ptr2);
}
}
}
if offset < slice.len() && !slice[offset].1.is_zero() {
offset += 1;
}
offset
}
pub fn consolidate_updates<D: Ord, T: Ord, R: Semigroup>(vec: &mut Vec<(D, T, R)>) {
consolidate_updates_from(vec, 0);
}
pub fn consolidate_updates_from<D: Ord, T: Ord, R: Semigroup>(vec: &mut Vec<(D, T, R)>, offset: usize) {
let length = consolidate_updates_slice(&mut vec[offset..]);
vec.truncate(offset + length);
}
pub fn consolidate_updates_slice<D: Ord, T: Ord, R: Semigroup>(slice: &mut [(D, T, R)]) -> usize {
slice.sort_unstable_by(|x,y| (&x.0, &x.1).cmp(&(&y.0, &y.1)));
let mut offset = 0;
for index in 1 .. slice.len() {
unsafe {
let ptr1 = slice.as_mut_ptr().offset(offset as isize);
let ptr2 = slice.as_mut_ptr().offset(index as isize);
if (*ptr1).0 == (*ptr2).0 && (*ptr1).1 == (*ptr2).1 {
(*ptr1).2 += &(*ptr2).2;
}
else {
if !(*ptr1).2.is_zero() {
offset += 1;
}
let ptr1 = slice.as_mut_ptr().offset(offset as isize);
std::mem::swap(&mut *ptr1, &mut *ptr2);
}
}
}
if offset < slice.len() && !slice[offset].2.is_zero() {
offset += 1;
}
offset
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_consolidate() {
let test_cases = vec![
(
vec![("a", -1), ("b", -2), ("a", 1)],
vec![("b", -2)],
),
(
vec![("a", -1), ("b", 0), ("a", 1)],
vec![],
),
(
vec![("a", 0)],
vec![],
),
(
vec![("a", 0), ("b", 0)],
vec![],
),
];
for (mut input, output) in test_cases {
consolidate(&mut input);
assert_eq!(input, output);
}
}
#[test]
fn test_consolidate_updates() {
let test_cases = vec![
(
vec![("a", 1, -1), ("b", 1, -2), ("a", 1, 1)],
vec![("b", 1, -2)],
),
(
vec![("a", 1, -1), ("b", 1, 0), ("a", 1, 1)],
vec![],
),
(
vec![("a", 1, 0)],
vec![],
),
(
vec![("a", 1, 0), ("b", 1, 0)],
vec![],
),
];
for (mut input, output) in test_cases {
consolidate_updates(&mut input);
assert_eq!(input, output);
}
}
}