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 slice_ptr = slice.as_mut_ptr();
let mut offset = 0;
for index in 1 .. slice.len() {
unsafe {
assert!(offset < index);
let ptr1 = slice_ptr.add(offset);
let ptr2 = slice_ptr.add(index);
if (*ptr1).0 == (*ptr2).0 {
(*ptr1).1.plus_equals(&(*ptr2).1);
}
else {
if !(*ptr1).1.is_zero() {
offset += 1;
}
let ptr1 = slice_ptr.add(offset);
std::ptr::swap(ptr1, 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 slice_ptr = slice.as_mut_ptr();
let mut offset = 0;
for index in 1 .. slice.len() {
unsafe {
let ptr1 = slice_ptr.add(offset);
let ptr2 = slice_ptr.add(index);
if (*ptr1).0 == (*ptr2).0 && (*ptr1).1 == (*ptr2).1 {
(*ptr1).2.plus_equals(&(*ptr2).2);
}
else {
if !(*ptr1).2.is_zero() {
offset += 1;
}
let ptr1 = slice_ptr.add(offset);
std::ptr::swap(ptr1, 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![],
),
(
vec![("a", 1), ("b", 1)],
vec![("a", 1), ("b", 1)],
),
];
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![],
),
(
vec![("a", 1, 1), ("b", 2, 1)],
vec![("a", 1, 1), ("b", 2, 1)],
),
];
for (mut input, output) in test_cases {
consolidate_updates(&mut input);
assert_eq!(input, output);
}
}
}