// ets_tracing: off import "../../../Operator/index.js" import type { Equal } from "../../../Equal/index.js" import type { Predicate, Refinement } from "../../../Function/index.js" import { not } from "../../../Function/index.js" import type { Ord } from "../../../Ord/index.js" import * as St from "../../../Structural/index.js" import type { Next } from "../Map/index.js" import * as RB from "../RedBlackTree/index.js" import * as Tp from "../Tuple/index.js" export class SortedSet implements Iterable { constructor(readonly keyTree: RB.RedBlackTree) {} [Symbol.iterator](): Iterator { return RB.keys_(this.keyTree) } get [St.hashSym](): number { return this.keyTree[St.hashSym] } [St.equalsSym](that: unknown): boolean { return this.keyTree[St.equalsSym](that) } } export function make(K: Ord) { return new SortedSet(RB.make(K)) } export function add_(set: SortedSet, v: V) { return RB.has_(set.keyTree, v) ? set : new SortedSet(RB.insert_(set.keyTree, v, true)) } export function add(v: V) { return (set: SortedSet) => add_(set, v) } export function remove_(set: SortedSet, v: V) { return new SortedSet(RB.removeFirst_(set.keyTree, v)) } export function remove(v: V) { return (set: SortedSet) => remove_(set, v) } export function values(set: SortedSet) { return RB.keys_(set.keyTree) } export function has_(set: SortedSet, v: V) { return RB.has_(set.keyTree, v) } /** * Apply f to each element */ export function forEach_(map: SortedSet, f: (v: V) => void) { RB.forEach_(map.keyTree, (k) => { f(k) }) } /** * The set of elements which are in both the first and second set, * * the hash and equal of the 2 sets has to be the same */ export function intersection_(l: SortedSet, r: Iterable): SortedSet { let x = make(l.keyTree.ord) for (const k of r) { if (has_(l, k)) { x = add_(x, k) } } return x } /** * The set of elements which are in both the first and second set * * @ets_data_first intersection_ */ export function intersection(r: Iterable) { return (l: SortedSet) => intersection_(l, r) } /** * Projects a Set through a function */ export function map_( E: Ord ): (set: SortedSet, f: (x: A) => B) => SortedSet { return (set, f) => { let r = make(E) forEach_(set, (e) => { const v = f(e) if (!has_(r, v)) { r = add_(r, v) } }) return r } } /** * Projects a Set through a function * * @ets_data_first map_ */ export function map( E: Ord ): (f: (x: A) => B) => (set: SortedSet) => SortedSet { const m = map_(E) return (f) => (set) => m(set, f) } /** * true if one or more elements match predicate * * @ets_data_first some_ */ export function some(predicate: Predicate): (set: SortedSet) => boolean { return (set) => some_(set, predicate) } /** * true if one or more elements match predicate */ export function some_(set: SortedSet, predicate: Predicate): boolean { let found = false for (const e of set) { found = predicate(e) if (found) { break } } return found } /** * Calculate the number of keys pairs in a set */ export function size(set: SortedSet) { return RB.size(set.keyTree) } /** * Creates an equal for a set */ export function equal(): Equal> { return { equals: (x, y) => { if (y === x) { return true } if (size(x) !== size(y)) { return false } let eq = true for (const vx of x) { if (!has_(y, vx)) { eq = false break } } return eq } } } /** * true if all elements match predicate * * @ets_data_first every_ */ export function every(predicate: Predicate): (set: SortedSet) => boolean { return (set) => every_(set, predicate) } /** * true if all elements match predicate */ export function every_(set: SortedSet, predicate: Predicate): boolean { return not(some(not(predicate)))(set) } /** * Map + Flatten * * @ets_data_first chain_ */ export function chain( E: Ord ): (f: (x: A) => Iterable) => (set: SortedSet) => SortedSet { const c = chain_(E) return (f) => (set) => c(set, f) } /** * Map + Flatten */ export function chain_( E: Ord ): (set: SortedSet, f: (x: A) => Iterable) => SortedSet { return (set, f) => { let r = make(E) forEach_(set, (e) => { for (const a of f(e)) { if (!has_(r, a)) { r = add_(r, a) } } }) return r } } /** * `true` if and only if every element in the first set is an element of the second set, * * the hash and equal of the 2 sets has to be the same * * @ets_data_first isSubset_ */ export function isSubset(y: SortedSet): (x: SortedSet) => boolean { return (x) => isSubset_(y, x) } /** * `true` if and only if every element in the first set is an element of the second set, * * the hash and equal of the 2 sets has to be the same */ export function isSubset_(x: SortedSet, y: SortedSet): boolean { return every_(x, (a: A) => has_(y, a)) } /** * Filter set values using predicate * * @ets_data_first filter_ */ export function filter( refinement: Refinement ): (set: SortedSet) => SortedSet export function filter(predicate: Predicate): (set: SortedSet) => SortedSet export function filter( predicate: Predicate ): (set: SortedSet) => SortedSet { return (set) => filter_(set, predicate) } /** * Filter set values using predicate */ export function filter_( set: SortedSet, refinement: Refinement ): SortedSet export function filter_(set: SortedSet, predicate: Predicate): SortedSet export function filter_(set: SortedSet, predicate: Predicate): SortedSet { let r = make(set.keyTree.ord) const values_ = values(set) let e: Next while (!(e = values_.next()).done) { const value = e.value if (predicate(value)) { r = add_(r, value) } } return r } /** * Partition set values using predicate * * @ets_data_first partition_ */ export function partition( refinement: Refinement ): (set: SortedSet) => Tp.Tuple<[SortedSet, SortedSet]> export function partition( predicate: Predicate ): (set: SortedSet) => Tp.Tuple<[SortedSet, SortedSet]> export function partition( predicate: Predicate ): (set: SortedSet) => Tp.Tuple<[SortedSet, SortedSet]> { return (set) => partition_(set, predicate) } /** * Partition set values using predicate */ export function partition_( set: SortedSet, refinement: Refinement ): Tp.Tuple<[SortedSet, SortedSet]> export function partition_( set: SortedSet, predicate: Predicate ): Tp.Tuple<[SortedSet, SortedSet]> export function partition_( set: SortedSet, predicate: Predicate ): Tp.Tuple<[SortedSet, SortedSet]> { const values_ = values(set) let e: Next let right = make(set.keyTree.ord) let left = make(set.keyTree.ord) while (!(e = values_.next()).done) { const value = e.value if (predicate(value)) { right = add_(right, value) } else { left = add_(left, value) } } return Tp.tuple(left, right) } /** * Form the set difference (`x` - `y`) */ export function difference_(x: SortedSet, y: Iterable): SortedSet { let s = x for (const k of y) { s = remove_(s, k) } return s } /** * Form the set difference (`x` - `y`) * * @ets_data_first difference_ */ export function difference(y: Iterable): (x: SortedSet) => SortedSet { return (x) => difference_(x, y) } /** * Reduce a state over the map entries */ export function reduce_(set: SortedSet, z: Z, f: (z: Z, v: V) => Z): Z { return RB.reduceWithIndex_(set.keyTree, z, (z, v) => f(z, v)) } /** * Reduce a state over the map entries * * @ets_data_first reduce_ */ export function reduce(z: Z, f: (z: Z, v: V) => Z) { return (set: SortedSet) => reduce_(set, z, f) } /** * If element is present remove it, if not add it * * @ets_data_first toggle_ */ export function toggle(a: A): (set: SortedSet) => SortedSet { return (set) => toggle_(set, a) } /** * If element is present remove it, if not add it */ export function toggle_(set: SortedSet, a: A): SortedSet { return (has_(set, a) ? remove : add)(a)(set) } /** * Form the union of two sets, * * the hash and equal of the 2 sets has to be the same */ export function union_(l: SortedSet, r: Iterable): SortedSet { let x = make(l.keyTree.ord) forEach_(l, (a) => { x = add_(x, a) }) for (const a of r) { x = add_(x, a) } return x } /** * Form the union of two sets, * * the hash and equal of the 2 sets has to be the same * * @ets_data_first union_ */ export function union(y: Iterable): (x: SortedSet) => SortedSet { return (x) => union_(x, y) }