use std::collections::{BTreeMap, BTreeSet, HashMap, HashSet};
use std::hash::Hash;
pub trait Semigroup: Sized {
fn combine(&self, other: &Self) -> Self;
fn combine_owned(self, other: Self) -> Self;
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct SemigroupExtAdapter<T>(T);
pub trait SemigroupExt: Semigroup {
#[inline]
fn combine_all<I>(self, others: I) -> Self
where
I: IntoIterator<Item = Self>,
Self: Sized,
{
others.into_iter().fold(self, |acc, x| acc.combine_owned(x))
}
#[inline]
fn combine_all_owned<I>(vals: I) -> Self
where
I: IntoIterator<Item = Self>,
Self: Sized,
{
let mut iter = vals.into_iter();
let first = iter.next().expect("at least one element required");
iter.fold(first, |acc, x| acc.combine_owned(x))
}
#[inline]
fn combine_n(&self, n: &usize) -> Self
where
Self: Clone,
{
if *n == 0 {
return self.clone();
}
let mut acc = self.clone();
for _ in 1..*n {
acc = acc.combine(self);
}
acc
}
#[inline]
fn combine_n_owned(self, n: usize) -> Self
where
Self: Clone,
{
if n == 0 {
return self;
}
let mut acc = self;
for _ in 1..n {
acc = acc.clone().combine_owned(acc);
}
acc
}
}
impl<T: Semigroup> SemigroupExt for T {}
impl<T: Semigroup> SemigroupExtAdapter<T> {
pub fn combine_all<I>(self, others: I) -> T
where
I: IntoIterator<Item = T>,
{
self.0.combine_all(others)
}
pub fn combine_n_owned(self, n: usize) -> T
where
T: Clone,
{
self.0.combine_n_owned(n)
}
pub fn combine_n(&self, n: &usize) -> T
where
T: Clone,
{
self.0.combine_n(n)
}
}
impl Semigroup for String {
#[inline]
fn combine(&self, other: &Self) -> Self {
self.clone() + other
}
#[inline]
fn combine_owned(self, other: Self) -> Self {
self + &other
}
}
impl<T: Clone> Semigroup for Vec<T> {
#[inline]
fn combine(&self, other: &Self) -> Self {
let mut result = self.clone();
result.extend(other.iter().cloned());
result
}
#[inline]
fn combine_owned(self, other: Self) -> Self {
let mut result = self;
result.extend(other);
result
}
}
impl<K: Eq + Hash + Clone, V: Semigroup + Clone> Semigroup for HashMap<K, V> {
#[inline]
fn combine(&self, other: &Self) -> Self {
let mut result = self.clone();
for (k, v) in other {
result
.entry(k.clone())
.and_modify(|e| *e = e.combine(v))
.or_insert(v.clone());
}
result
}
#[inline]
fn combine_owned(self, other: Self) -> Self {
let mut result = self;
for (k, v) in other {
match result.get_mut(&k) {
Some(existing) => {
let combined = existing.clone().combine_owned(v);
*existing = combined;
},
None => {
result.insert(k, v);
},
}
}
result
}
}
impl<T: Eq + Hash + Clone> Semigroup for HashSet<T> {
#[inline]
fn combine(&self, other: &Self) -> Self {
let mut result = self.clone();
result.extend(other.iter().cloned());
result
}
fn combine_owned(self, other: Self) -> Self {
let mut result = self;
result.extend(other);
result
}
}
impl<K: Ord + Clone, V: Semigroup + Clone> Semigroup for BTreeMap<K, V> {
#[inline]
fn combine(&self, other: &Self) -> Self {
let mut result = self.clone();
for (k, v) in other {
result
.entry(k.clone())
.and_modify(|e| *e = e.combine(v))
.or_insert(v.clone());
}
result
}
#[inline]
fn combine_owned(self, other: Self) -> Self {
let mut result = self;
for (k, v) in other {
match result.get_mut(&k) {
Some(existing) => {
let combined = existing.clone().combine_owned(v);
*existing = combined;
},
None => {
result.insert(k, v);
},
}
}
result
}
}
impl<T: Ord + Clone> Semigroup for BTreeSet<T> {
#[inline]
fn combine(&self, other: &Self) -> Self {
let mut result = self.clone();
result.extend(other.iter().cloned());
result
}
#[inline]
fn combine_owned(self, other: Self) -> Self {
let mut result = self;
result.extend(other);
result
}
}
impl<A: Semigroup, B: Semigroup> Semigroup for (A, B) {
#[inline]
fn combine(&self, other: &Self) -> Self {
(self.0.combine(&other.0), self.1.combine(&other.1))
}
#[inline]
fn combine_owned(self, other: Self) -> Self {
(self.0.combine_owned(other.0), self.1.combine_owned(other.1))
}
}
impl<A: Semigroup, B: Semigroup, C: Semigroup> Semigroup for (A, B, C) {
#[inline]
fn combine(&self, other: &Self) -> Self {
(
self.0.combine(&other.0),
self.1.combine(&other.1),
self.2.combine(&other.2),
)
}
#[inline]
fn combine_owned(self, other: Self) -> Self {
(
self.0.combine_owned(other.0),
self.1.combine_owned(other.1),
self.2.combine_owned(other.2),
)
}
}
impl<A: Semigroup, B: Semigroup, C: Semigroup, D: Semigroup> Semigroup for (A, B, C, D) {
#[inline]
fn combine(&self, other: &Self) -> Self {
(
self.0.combine(&other.0),
self.1.combine(&other.1),
self.2.combine(&other.2),
self.3.combine(&other.3),
)
}
#[inline]
fn combine_owned(self, other: Self) -> Self {
(
self.0.combine_owned(other.0),
self.1.combine_owned(other.1),
self.2.combine_owned(other.2),
self.3.combine_owned(other.3),
)
}
}
impl<T: Semigroup + Clone> Semigroup for Option<T> {
#[inline]
fn combine(&self, other: &Self) -> Self {
match (self, other) {
(Some(a), Some(b)) => Some(a.combine(b)),
(Some(a), None) => Some(a.clone()),
(None, Some(b)) => Some(b.clone()),
(None, None) => None,
}
}
#[inline]
fn combine_owned(self, other: Self) -> Self {
match (self, other) {
(Some(a), Some(b)) => Some(a.combine_owned(b)),
(Some(a), None) => Some(a),
(None, Some(b)) => Some(b),
(None, None) => None,
}
}
}
#[inline]
pub fn combine_all_values<T, I>(values: I) -> Option<T>
where
T: Semigroup,
I: IntoIterator<Item = T>,
{
let mut iter = values.into_iter();
let first = iter.next()?;
Some(iter.fold(first, |acc, x| acc.combine_owned(x)))
}
#[inline]
pub fn combine_values<T, I>(initial: T, values: I) -> T
where
T: Semigroup,
I: IntoIterator<Item = T>,
{
values
.into_iter()
.fold(initial, |acc, x| acc.combine_owned(x))
}