// ets_tracing: off
import "../../../Operator/index.js"
import type { Option } from "@effect-ts/system/Option"
import type { MutableSet } from "@effect-ts/system/Support/Mutable"
import type { Associative } from "../../../Associative/index.js"
import { makeAssociative } from "../../../Associative/index.js"
import type { Either } from "../../../Either/index.js"
import type { Equal } from "../../../Equal/index.js"
import { makeEqual } from "../../../Equal/index.js"
import type { Predicate, Refinement } from "../../../Function/index.js"
import { identity, not } from "../../../Function/index.js"
import type { Identity } from "../../../Identity/index.js"
import { makeIdentity } from "../../../Identity/index.js"
import type { Ord } from "../../../Ord/index.js"
import type { Show } from "../../../Show/index.js"
import * as Tp from "../Tuple/index.js"
export type Set = ReadonlySet
export const empty: Set = new Set()
/**
* Get an Associative that performs Set intersection
*/
export function getIntersectionAssociative(E: Equal): Associative> {
return makeAssociative(intersection_(E))
}
/**
* Get an Identity that performs Set union
*/
export function getUnionIdentity(E: Equal): Identity> {
return makeIdentity(empty as Set, union_(E))
}
/**
* The set of elements which are in both the first and second set
*/
export function intersection_(E: Equal): (l: Set, r: Set) => Set {
const elemE = elem_(E)
return (x, y) => {
if (x === empty || y === empty) {
return empty
}
const r = new Set()
x.forEach((e) => {
if (elemE(y, e)) {
r.add(e)
}
})
return r
}
}
/**
* The set of elements which are in both the first and second set
*/
export function intersection(E: Equal): (r: Set) => (l: Set) => Set {
const i = intersection_(E)
return (x) => (y) => i(x, y)
}
/**
* Convert a mutable set to a readonly one
*/
export function fromMutable(s: MutableSet): Set {
return new Set(s)
}
/**
* Convert a set to a mutable one
*/
export function toMutable(s: Set): MutableSet {
return new Set(s)
}
/**
* get Show for set given Show for values
*/
export function getShow(S: Show): Show> {
return {
show: (s) => {
let elements = ""
s.forEach((a) => {
elements += S.show(a) + ", "
})
if (elements !== "") {
elements = elements.substring(0, elements.length - 2)
}
return `new Set([${elements}])`
}
}
}
/**
* Convert a set to an Array
*/
export function toArray(O: Ord): (set: Set) => ReadonlyArray {
return (x) => {
const r: Array = []
x.forEach((e) => r.push(e))
return r.sort(O.compare)
}
}
/**
* Convert a set to an Array
*/
export function toArray_(x: Set, O: Ord): ReadonlyArray {
return toArray(O)(x)
}
/**
* Get Equal for Setgiven Equal for element
*/
export function getEqual(E: Equal): Equal> {
const subsetE = isSubset_(E)
return makeEqual((x, y) => subsetE(x, y) && subsetE(y, x))
}
interface Next {
readonly done?: boolean
readonly value: A
}
/**
* true if one or more elements match predicate
*/
export function some(predicate: Predicate): (set: Set) => boolean {
return (set) => {
const values = set.values()
let e: Next
let found = false
while (!found && !(e = values.next()).done) {
found = predicate(e.value)
}
return found
}
}
/**
* true if one or more elements match predicate
*/
export function some_(set: Set, predicate: Predicate): boolean {
return some(predicate)(set)
}
/**
* Projects a Set through a function
*/
export function map(E: Equal): (f: (x: A) => B) => (set: Set) => Set {
const m = map_(E)
return (f) => (set) => m(set, f)
}
/**
* Projects a Set through a function
*/
export function map_(E: Equal): (set: Set, f: (x: A) => B) => Set {
const elemE = elem_(E)
return (set, f) => {
const r = new Set()
set.forEach((e) => {
const v = f(e)
if (!elemE(r, v)) {
r.add(v)
}
})
return r
}
}
/**
* true if all elements match predicate
*/
export function every(predicate: Predicate): (set: Set) => boolean {
return (set) => every_(set, predicate)
}
/**
* true if all elements match predicate
*/
export function every_(set: Set, predicate: Predicate): boolean {
return not(some(not(predicate)))(set)
}
/**
* Map + Flatten
*/
export function chain(
E: Equal
): (f: (x: A) => Set) => (set: Set) => Set {
const c = chain_(E)
return (f) => (set) => c(set, f)
}
/**
* Map + Flatten
*/
export function chain_(
E: Equal
): (set: Set, f: (x: A) => Set) => Set {
const elemE = elem_(E)
return (set, f) => {
const r = new Set()
set.forEach((e) => {
f(e).forEach((e) => {
if (!elemE(r, e)) {
r.add(e)
}
})
})
return r
}
}
/**
* `true` if and only if every element in the first set is an element of the second set
*/
export function isSubset(E: Equal): (y: Set) => (x: Set) => boolean {
const i = isSubset_(E)
return (y) => (x) => i(y, x)
}
/**
* `true` if and only if every element in the first set is an element of the second set
*/
export function isSubset_(E: Equal): (x: Set, y: Set) => boolean {
const elemE = elem_(E)
return (x, y) => every((a: A) => elemE(y, a))(x)
}
/**
* Filter set values using predicate
*/
export function filter(
refinement: Refinement
): (set: Set) => Set
export function filter(predicate: Predicate): (set: Set) => Set
export function filter(predicate: Predicate): (set: Set) => Set {
return (set) => filter_(set, predicate)
}
/**
* Filter set values using predicate
*/
export function filter_(
set: Set,
refinement: Refinement
): Set
export function filter_(set: Set, predicate: Predicate): Set
export function filter_(set: Set, predicate: Predicate): Set {
const values = set.values()
let e: Next
const r = new Set()
while (!(e = values.next()).done) {
const value = e.value
if (predicate(value)) {
r.add(value)
}
}
return r
}
/**
* Partition set values using predicate
*/
export function partition(
refinement: Refinement
): (set: Set) => Tp.Tuple<[Set, Set]>
export function partition(
predicate: Predicate
): (set: Set) => Tp.Tuple<[Set, Set]>
export function partition(
predicate: Predicate
): (set: Set) => Tp.Tuple<[Set, Set]> {
return (set) => partition_(set, predicate)
}
/**
* Partition set values using predicate
*/
export function partition_(
set: Set,
refinement: Refinement
): Tp.Tuple<[Set, Set]>
export function partition_(
set: Set,
predicate: Predicate
): Tp.Tuple<[Set, Set]>
export function partition_(
set: Set,
predicate: Predicate
): Tp.Tuple<[Set, Set]> {
const values = set.values()
let e: Next
const right = new Set()
const left = new Set()
while (!(e = values.next()).done) {
const value = e.value
if (predicate(value)) {
right.add(value)
} else {
left.add(value)
}
}
return Tp.tuple(left, right)
}
/**
* Test if a value is a member of a set
*/
export function elem_(E: Equal): (set: Set, a: A) => boolean {
return (set, a) => {
const values = set.values()
let e: Next
let found = false
while (!found && !(e = values.next()).done) {
found = E.equals(a, e.value)
}
return found
}
}
/**
* Test if a value is a member of a set
*/
export function elem(E: Equal): (a: A) => (set: Set) => boolean {
const e = elem_(E)
return (a) => (set) => e(set, a)
}
/**
* Partition elements according to f
*/
export function partitionMap(
EB: Equal,
EC: Equal
): (f: (a: A) => Either) => (set: Set) => Tp.Tuple<[Set, Set]> {
const pm = partitionMap_(EB, EC)
return (f: (a: A) => Either) =>
(set: Set) =>
pm(set, f)
}
/**
* Partition elements according to f
*/
export function partitionMap_(
EB: Equal,
EC: Equal
): (set: Set, f: (a: A) => Either) => Tp.Tuple<[Set, Set]> {
return (set: Set, f: (a: A) => Either) => {
const values = set.values()
let e: Next
const left = new Set()
const right = new Set()
const hasB = elem_(EB)
const hasC = elem_(EC)
while (!(e = values.next()).done) {
const v = f(e.value)
switch (v._tag) {
case "Left":
if (!hasB(left, v.left)) {
left.add(v.left)
}
break
case "Right":
if (!hasC(right, v.right)) {
right.add(v.right)
}
break
}
}
return Tp.tuple(left, right)
}
}
/**
* Form the set difference (`x` - `y`)
*/
export function difference_(E: Equal): (l: Set, r: Set) => Set {
const elemE = elem_(E)
return (x, y) => filter((a: A) => !elemE(y, a))(x)
}
/**
* Form the set difference (`x` - `y`)
*/
export function difference(E: Equal): (y: Set) => (x: Set) => Set {
const diff = difference_(E)
return (y) => (x) => diff(x, y)
}
/**
* Reduce over the set values
*/
export function reduce(
O: Ord
): (b: B, f: (b: B, a: A) => B) => (fa: Set) => B {
const red = reduce_(O)
return (b, f) => (fa) => red(fa, b, f)
}
/**
* Reduce over the set values
*/
export function reduce_(
O: Ord
): (fa: Set, b: B, f: (b: B, a: A) => B) => B {
const toArrayO = toArray(O)
return (fa, b, f) => toArrayO(fa).reduce(f, b)
}
/**
* Fold + Map
*/
export function foldMap(
O: Ord,
M: Identity
): (f: (a: A) => M) => (fa: Set) => M {
const fm = foldMap_(O, M)
return (f) => (fa) => fm(fa, f)
}
/**
* Fold + Map
*/
export function foldMap_(
O: Ord,
M: Identity
): (fa: Set, f: (a: A) => M) => M {
const toArrayO = toArray(O)
return (fa, f) => toArrayO(fa).reduce((b, a) => M.combine(b, f(a)), M.identity)
}
/**
* Create a set with one element
*/
export function singleton(a: A): Set {
return new Set([a])
}
/**
* Insert a value into a set
*/
export function insert(E: Equal): (a: A) => (set: Set) => Set {
const i = insert_(E)
return (a) => (set) => i(set, a)
}
/**
* Insert a value into a set
*/
export function insert_(E: Equal): (set: Set, a: A) => Set {
const elemE = elem_(E)
return (set, a) => {
if (!elemE(set, a)) {
const r = new Set(set)
r.add(a)
return r
} else {
return set
}
}
}
/**
* Delete a value from a set
*/
export function remove(E: Equal): (a: A) => (set: Set) => Set {
const rem = remove_(E)
return (a) => (set) => rem(set, a)
}
/**
* Delete a value from a set
*/
export function remove_(E: Equal): (set: Set, a: A) => Set {
return (set, a) => filter((ax: A) => !E.equals(a, ax))(set)
}
/**
* If element is present remove it, if not add it
*/
export function toggle(E: Equal): (a: A) => (set: Set) => Set {
const t = toggle_(E)
return (a) => (set) => t(set, a)
}
/**
* If element is present remove it, if not add it
*/
export function toggle_(E: Equal): (set: Set, a: A) => Set {
const elemE = elem_(E)
const removeE = remove(E)
const insertE = insert(E)
return (set, a) => (elemE(set, a) ? removeE : insertE)(a)(set)
}
/**
* Create a set from an array
*/
export function fromArray(E: Equal): (as: ReadonlyArray) => Set {
return (as) => {
const len = as.length
const r = new Set()
const has = elem_(E)
for (let i = 0; i < len; i++) {
const a = as[i]!
if (!has(r, a)) {
r.add(a)
}
}
return r
}
}
/**
* Set compaction, remove none
*/
export function compact(E: Equal): (fa: Set