import type { Eq } from "@principia/prelude/Eq";
import { empty } from "./constructors";
import { filter_ } from "./filterable";
import { elem, elem_ } from "./guards";
/**
* Form the union of two sets
*
* @category Combinators
* @since 1.0.0
*/
export const union_ = (E: Eq) => {
const elemE = elem(E);
return (me: ReadonlySet, that: ReadonlySet) => {
if (me === empty) {
return that;
}
if (that === empty) {
return me;
}
const r = new Set(me);
that.forEach((e) => {
if (!elemE(e)(r)) {
r.add(e);
}
});
return r;
};
};
/**
* Form the union of two sets
*
* @category Combinators
* @since 1.0.0
*/
export const union = (E: Eq) => {
const unionE_ = union_(E);
return (that: ReadonlySet) => (me: ReadonlySet) => unionE_(me, that);
};
/**
* The set of elements which are in both the first and second set
*
* @category Combinators
* @since 1.0.0
*/
export const intersection_ = (E: Eq) => {
const elemE = elem(E);
return (me: ReadonlySet, that: ReadonlySet) => {
if (me === empty || that === empty) {
return empty;
}
const r = new Set();
me.forEach((e) => {
if (elemE(e)(that)) {
r.add(e);
}
});
return r;
};
};
/**
* The set of elements which are in both the first and second set
*
* @category Combinators
* @since 1.0.0
*/
export const intersection = (E: Eq) => {
const intersectionE_ = intersection_(E);
return (that: ReadonlySet) => (me: ReadonlySet) => intersectionE_(me, that);
};
export const difference_ = (E: Eq) => {
const elemE_ = elem_(E);
return (me: ReadonlySet, that: ReadonlySet) => filter_(me, (a) => !elemE_(that, a));
};
export const difference = (E: Eq) => {
const differenceE_ = difference_(E);
return (that: ReadonlySet) => (me: ReadonlySet) => differenceE_(me, that);
};
export const insert_ = (E: Eq) => {
const elemE_ = elem_(E);
return (set: ReadonlySet, a: A) => {
if (!elemE_(set, a)) {
const r = new Set(set);
r.add(a);
return r;
} else {
return set;
}
};
};
export const insert = (E: Eq) => {
const insertE_ = insert_(E);
return (a: A) => (set: ReadonlySet) => insertE_(set, a);
};
export const remove_ = (E: Eq) => (set: ReadonlySet, a: A) => filter_(set, (ax) => !E.equals(a)(ax));
export const remove = (E: Eq) => (a: A) => (set: ReadonlySet) => remove_(E)(set, a);