/* * Copyright 2017 Liam Palmer, Esben Bjerre * * Use of this source code is governed by the Apache 2.0 license * that can be found in the LICENSE.md file. */pubmod Set {////// The Set type.////// A set is currently represented internally as a red-black tree.///pubenumSet[t] {case Set(RedBlackTree[t, Unit]) }instanceEq[Set[a]] withEq[a] {pubdefeq(s1: Set[a], s2: Set[a]): Bool =Set.toList(s1) ==Set.toList(s2) }instanceOrder[Set[a]] withOrder[a] {pubdefcompare(s1: Set[a], s2: Set[a]): Comparison =Set.toList(s1) <=>Set.toList(s2) }instanceHash[Set[a]] withHash[a] {pubdefhash(s: Set[a]): Int32 =Set.foldLeft((acc, x) -> acc`Hash.combine`Hash.hash(x), Hash.magic(), s) }instanceFormattable[Set[a]] withFormattable[a] {typeAef = Formattable.Aef[a]pubdefformat(x: Set[a]): RichString \ Formattable.Aef[a] =RichString.fromString("Set#{") +RichString.joinWith(Formattable.format, RichString.fromString(", "), Set.toList(x)) +RichString.fromString("}") }instanceToString[Set[a]] withToString[a] {pubdeftoString(s: Set[a]): String = Set.toString(s) }instanceLowerBound[Set[a]] {pubdefminValue(): Set[a] = Set.empty() }instancePartialOrder[Set[a]] withOrder[a] {pubdeflessEqual(s1: Set[a], s2: Set[a]): Bool = s1`Set.isSubsetOf`s2 }instanceJoinLattice[Set[a]] withOrder[a] {pubdefleastUpperBound(s1: Set[a], s2: Set[a]): Set[a] = s1`Set.union`s2 }instanceMeetLattice[Set[a]] withOrder[a] {pubdefgreatestLowerBound(s1: Set[a], s2: Set[a]): Set[a] = s1`Set.intersection`s2 }instanceFoldable[Set] {pubdeffoldLeft(f: (b, a) -> b \ ef, s: b, s1: Set[a]): b \ ef = Set.foldLeft(f, s, s1)pubdeffoldRight(f: (a, b) -> b \ ef, s: b, s1: Set[a]): b \ ef = Set.foldRight(f, s, s1) redef isEmpty(s: Set[a]): Bool = Set.isEmpty(s) redef forAll(f: a -> Bool \ ef, s: Set[a]): Bool \ ef = Set.forAll(f, s) redef exists(f: a -> Bool \ ef, s: Set[a]): Bool \ ef = Set.exists(f, s) }instanceUnorderedFoldable[Set] {pubdeffoldMap(f: a -> b \ ef, s: Set[a]): b \ efwithCommutativeMonoid[b] = Set.foldMap(f, s) redef isEmpty(s: Set[a]): Bool = Set.isEmpty(s) redef exists(f: a -> Bool \ ef, s: Set[a]): Bool \ ef = Set.exists(f, s) redef forAll(f: a -> Bool \ ef, s: Set[a]): Bool \ ef = Set.forAll(f, s)@ParallelWhenPure redef count(f: a -> Bool \ ef, s: Set[a]): Int32 \ ef = Set.count(f, s) }instanceSemiGroup[Set[a]] withOrder[a] {pubdefcombine(x: Set[a], y: Set[a]): Set[a] = Set.union(x, y) }instanceCommutativeSemiGroup[Set[a]] withOrder[a]instanceMonoid[Set[a]] withOrder[a] {pubdefempty(): Set[a] = Set.empty() }instanceCommutativeMonoid[Set[a]] withOrder[a]instanceCollectable[Set[a]] withOrder[a] {typeElm = apubdefcollect(iter: Iterator[a, ef, r]): Set[a] \ { ef, r } = Iterator.toSet(iter) }instanceIterable[Set[a]] {typeElm = apubdefiterator(rc: Region[r], s: Set[a]): Iterator[a, r, r] \ r = Set.iterator(rc, s) }instanceForEach[Set[a]] {typeElm = apubdefforEach(f: a -> Unit \ ef, s: Set[a]): Unit \ ef = Set.forEach(f, s) }////// Returns a string representation of the given set `s`.///pubdeftoString(s: Set[a]): StringwithToString[a] = regionrc {"Set#{"+ (Set.iterator(rc, s) |> Iterator.join(", ")) +"}" }////// Determines whether to use parallel evaluation.////// By default we only enable parallel evaluation if the set has a certain size.///defuseParallelEvaluation(s: Set[a]): Bool =let Set(t) = s;letminSize = Int32.pow(base = 2, RedBlackTree.blackHeight(t));minSize>=1024////// Returns the number of elements in `s`.///pubdefsize(s: Set[a]): Int32 =let Set(t) = s;RedBlackTree.size(t)////// Returns the empty set.////// `Set#{}` is syntactic sugar for `empty` i.e. `Set#{} == empty()`.///pubdefempty(): Set[a] = Set(RedBlackTree.empty())////// Adds `x` to `s`.///pubdefinsert(x: a, s: Set[a]): Set[a] withOrder[a] =let Set(t) = s; Set(RedBlackTree.insert(x, (), t))////// Removes `x` from `s`.///pubdefremove(x: a, s: Set[a]): Set[a] withOrder[a] =let Set(t) = s; Set(RedBlackTree.remove(x, t))////// Returns true if and only if `s` is the empty set.///pubdefisEmpty(s: Set[a]): Bool =let Set(t) = s;RedBlackTree.isEmpty(t)////// Returns true if and only if `s` is a non-empty set.///pubdefnonEmpty(s: Set[a]): Bool = notisEmpty(s)////// Returns the singleton set containing `x`.////// `Set#{x}` is syntactic sugar for `singleton` i.e. `Set#{x} == singleton(x)`.///pubdefsingleton(x: a): Set[a] withOrder[a] = insert(x, empty())////// Returns a set of all integers between `b` (inclusive) and `e` (exclusive).////// Returns `empty()` if `b >= e`.///pubdefrange(b: Int32, e: Int32): Set[Int32] =defloop(i, s) = {if (i>=e)selseloop(i+1, insert(i, s)) };loop(b, empty())////// Returns true if and only if `x` is a member of `s`.///pubdefmemberOf(x: a, s: Set[a]): BoolwithOrder[a] =let Set(t) = s;RedBlackTree.memberOf(x, t)////// Optionally finds the smallest element of `s` according to the `Order` on `a`.////// Returns `None` if `s` is empty.///pubdefminimum(s: Set[a]): Option[a] =let Set(t) = s;RedBlackTree.minimumKey(t) |> Option.map(fst)////// Optionally finds the smallest element of `s` according to the given comparator `cmp`.////// Returns `None` if `s` is empty.////// Purity reflective: Runs in parallel when given a pure function `f`.///@ParallelWhenPurepubdefminimumBy(cmp: (a, a) -> Comparison \ ef, s: Set[a]): Option[a] \ ef =defmin() = reduceLeft((x, y) -> if (cmp(x, y) == Comparison.LessThan) xelsey, s);matchpurityOf2(cmp) {case Purity2.Pure(g) =>if (useParallelEvaluation(s))leth = (kl, _, kr, _) -> g(kl, kr);let Set(t) = s;leto = RedBlackTree.parMinimumBy(h, t);Option.map(fst, o)elsemin()case Purity2.Impure(_) => min() }////// Optionally finds the largest element of `s` according to the `Order` on `a`.////// Returns `None` if `s` is empty.///pubdefmaximum(s: Set[a]): Option[a] =let Set(t) = s;RedBlackTree.maximumKey(t) |> Option.map(fst)////// Optionally finds the largest element of `s` according to the given comparator `cmp`.////// Returns `None` if `s` is empty.////// Purity reflective: Runs in parallel when given a pure function `f`.///@ParallelWhenPurepubdefmaximumBy(cmp: (a, a) -> Comparison \ ef, s: Set[a]): Option[a] \ ef =defmax() = reduceLeft((x, y) -> if (cmp(x, y) == Comparison.GreaterThan) xelsey, s);matchpurityOf2(cmp) {case Purity2.Pure(g) =>if (useParallelEvaluation(s))leth = (kl, _, kr, _) -> g(kl, kr);let Set(t) = s;leto = RedBlackTree.parMaximumBy(h, t);Option.map(fst, o)elsemax()case Purity2.Impure(_) => max() }////// Returns true if and only if every element in `s1` appears in `s2`.///pubdefisSubsetOf(s1: Set[a], s2: Set[a]): BoolwithOrder[a] = forAll(x -> memberOf(x, s2), s1)////// Returns true if and only if every element in `s1` appears in `s2` and `s != s2`.///pubdefisProperSubsetOf(s1: Set[a], s2: Set[a]): BoolwithOrder[a] = size(s1) !=size(s2) andisSubsetOf(s1, s2)////// Alias for `findLeft`.///pubdeffind(f: a -> Bool \ ef, s: Set[a]): Option[a] \ ef = findLeft(f, s)////// Optionally returns the first element of `s` that satisfies the predicate `f` when searching from left to right.///pubdeffindLeft(f: a -> Bool \ ef, s: Set[a]): Option[a] \ ef =let Set(t) = s;RedBlackTree.findLeft((x, _) -> f(x), t) |> Option.map(fst)////// Optionally returns the first element of `s` that satisfies the predicate `f` when searching from right to left.///pubdeffindRight(f: a -> Bool \ ef, s: Set[a]): Option[a] \ ef =let Set(t) = s;RedBlackTree.findRight((x, _) -> f(x), t) |> Option.map(fst)////// Returns the result of applying `combine` to all the elements in `s`, using `empty` as the initial value.///pubdeffold(s: Set[a]): awithMonoid[a] = Foldable.fold(s)////// Applies `f` to a start value `s` and all elements in `s` going from left to right.////// That is, the result is of the form: `f(...f(f(s, x1), x2)..., xn)`.///pubdeffoldLeft(f: (b, a) -> b \ ef, s: b, s1: Set[a]): b \ ef =let Set(t) = s1;RedBlackTree.foldLeft((acc, k, _) -> f(acc, k), s, t)////// Applies `f` to a start value `s` and all elements in `s1` going from right to left.////// That is, the result is of the form: `f(x1, ...f(xn-1, f(xn, s))...)`.///pubdeffoldRight(f: (a, b) -> b \ ef, s: b, s1: Set[a]): b \ ef =let Set(t) = s1;RedBlackTree.foldRight((k, _, c) -> f(k, c), s, t)////// Returns the result of mapping each element and combining the results.///pubdeffoldMap(f: a -> b \ ef, s: Set[a]): b \ efwithMonoid[b] =foldLeft((acc, x) -> Monoid.combine(acc, f(x)), Monoid.empty(), s)////// Applies `f` to all elements in `s` going from left to right until a single value `v` is obtained. Returns `Some(v)`./// That is, the result is of the form: `Some(f(...f(f(x1, x2), x3)..., xn))`/// Returns `None` if `s` is the empty set.///pubdefreduceLeft(f: (a, a) -> a \ ef, s: Set[a]): Option[a] \ ef =let Set(t) = s;RedBlackTree.reduceLeft((x, _, y, _) -> (f(x, y), ()), t) |> Option.map(fst)////// Applies `f` to all elements in `s` going from right to left until a single value `v` is obtained. Returns `Some(v)`./// That is, the result is of the form: `Some(f(x1, ...f(xn-2, f(xn-1, xn))...))`/// Returns `None` if `s` is the empty set.///pubdefreduceRight(f: (a, a) -> a \ ef, s: Set[a]): Option[a] \ ef =let Set(t) = s;RedBlackTree.reduceRight((x, _, y, _) -> (f(x, y), ()), t) |> Option.map(fst)////// Returns the number of elements in `s` that satisfy the predicate `f`.////// Purity reflective: Runs in parallel when given a pure function `f`.///@ParallelWhenPurepubdefcount(f: a -> Bool \ ef, s: Set[a]): Int32 \ ef =matchpurityOf(f) {case Purity.Pure(g) =>if (useParallelEvaluation(s))leth = (k, _) -> g(k);let Set(t) = s;RedBlackTree.parCount(h, t)elsefoldLeft((b, k) -> if (f(k)) b+1elseb, 0, s)case Purity.Impure(g) => foldLeft((b, k) -> if (g(k)) b+1elseb, 0, s) }////// Returns the union of the elements in `s`.///pubdefflatten(s: Set[Set[a]]): Set[a] withOrder[a] =foldLeft((acc, x) -> union(acc, x), empty(), s)////// Returns `true` if and only if at least one element in `s` satisfies the predicate `f`.////// Returns `false` if `s` is the empty set.///pubdefexists(f: a -> Bool \ ef, s: Set[a]): Bool \ ef =let Set(t) = s;RedBlackTree.exists((x, _) -> f(x), t)////// Returns `true` if and only if all elements in `s` satisfy the predicate `f`.////// Returns `true` if `s` is the empty set.///pubdefforAll(f: a -> Bool \ ef, s: Set[a]): Bool \ ef =let Set(t) = s;RedBlackTree.forAll((x, _) -> f(x), t)////// Returns the union of `s1` and `s2`.///pubdefunion(s1: Set[a], s2: Set[a]): Set[a] withOrder[a] =use RedBlackTree.{blackHeight, foldLeft, insert};let Set(t1) = s1;let Set(t2) = s2;if (blackHeight(t1) <blackHeight(t2)) Set(foldLeft((acc, x, _) -> insert(x, (), acc), t2, t1))else Set(foldLeft((acc, y, _) -> insert(y, (), acc), t1, t2))////// Returns the intersection of `s1` and `s2`.///pubdefintersection(s1: Set[a], s2: Set[a]): Set[a] withOrder[a] =foldLeft((acc, x) -> if (memberOf(x, s1)) insert(x, acc) elseacc, empty(), s2)////// Returns the difference of `s1` and `s2`, i.e. `s1 - s2`.///pubdefdifference(s1: Set[a], s2: Set[a]): Set[a] withOrder[a] =foldLeft((acc, x) -> if (notmemberOf(x, s2)) insert(x, acc) elseacc, empty(), s1)////// Returns all subsets of `s`.///pubdefsubsets(s: Set[a]): Set[Set[a]] withOrder[a] =foldLeft((acc, x) -> union(map(y -> insert(x, y), acc), acc), insert(empty(), empty()), s)////// Returns the set of all elements of `s` that satisfy the predicate `f`.///pubdeffilter(f: a -> Bool \ ef, s: Set[a]): Set[a] \ efwithOrder[a] =foldLeft((acc, x) -> if (f(x)) insert(x, acc) elseacc, empty(), s)////// Returns the result of applying `f` to every element in `s`.////// Note: The returned set may be smaller than `s`.///pubdefmap(f: a -> b \ ef, s: Set[a]): Set[b] \ efwithOrder[b] =foldLeft((acc, x) -> insert(f(x), acc), empty(), s)////// Returns the result of applying `f` to every element in `s` and taking the union.///pubdefflatMap(f: a -> Set[b] \ ef, s: Set[a]): Set[b] \ efwithOrder[b] =foldLeft((acc, x) -> union(acc, f(x)), empty(), s)////// Collects the results of applying the partial function `f` to every element in `s`.///pubdeffilterMap(f: a -> Option[b] \ ef, s: Set[a]): Set[b] \ efwithOrder[b] =letstep = (acc, x) -> matchf(x) {case None => acccase Some(v) => insert(v, acc) };foldLeft(step, empty(), s)////// Replaces the element `src` with `dst` if `src` is in `s`. Otherwise, returns `s`.////// Note: The returned set may be smaller than `s`.///pubdefreplace(src: {src = a}, dst: {dst = a}, s: Set[a]): Set[a] withOrder[a] =if (memberOf(src#src, s)) insert(dst#dst, remove(src#src, s)) elses////// Returns a pair of sets `(s1, s2)`.////// `s1` contains all elements of `s` that satisfy the predicate `f`./// `s2` contains all elements of `s` that do not satisfy the predicate `f`.///pubdefpartition(f: a -> Bool \ ef, s: Set[a]): (Set[a], Set[a]) \ efwithOrder[a] =foldLeft( (acc, x) ->let (a, b) = acc;if (f(x)) (insert(x, a), b)else (a, insert(x, b)), (empty(), empty()),s )////// Returns the set `s` as a list.///pubdeftoList(s: Set[a]): List[a] =foldRight((x, acc) -> x :: acc, Nil, s)////// Returns the set `s` as an array.///pubdeftoArray(rc: Region[r], s: Set[a]): Array[a, r] \ r = matchsize(s) {case 0 => Array#{} @ rccasesz =>leta = Array.empty(rc, sz);Iterator.forEachWithIndex((i, b) -> Array.put(b, i, a), iterator(rc, s));a }////// Returns the set `s` as a vector.///pubdeftoVector(s: Set[a]): Vector[a] = regionrc {letarr = Array.empty(rc, size(s));Iterator.forEachWithIndex((i, x) -> Array.put(x, i, arr), iterator(rc, s));Array.toVector(arr) }////// Returns the set `s` as a chain.///pubdeftoChain(s: Set[a]): Chain[a] =foldLeft(Chain.snoc, Chain.empty(), s)////// Returns the association set `s` as a map.////// If `s` contains multiple mappings with the same key, `toMap` does not/// make any guarantees about which mapping will be in the resulting map.///pubdeftoMap(s: Set[(a, b)]): Map[a, b] withOrder[a] =foldRight((x, acc) -> let (k, v) = x; Map.insert(k, v, acc), Map#{}, s)////// Returns a map with elements of `s` as keys and `f` applied as values.///pubdeftoMapWith(f: a -> b, s: Set[a]): Map[a, b] withOrder[a] =Set.foldRight((x, acc) -> Map.insert(x, f(x), acc), Map.empty(), s)////// Applies `f` to every element of `s`.///pubdefforEach(f: a -> Unit \ ef, s: Set[a]): Unit \ ef =let Set(t) = s;RedBlackTree.forEach((x, _) -> f(x), t)////// Applies `f` to every element of `s` along with that element's index.///pubdefforEachWithIndex(f: (Int32, a) -> Unit \ ef, s: Set[a]): Unit \ ef =let Set(t) = s;RedBlackTree.forEachWithIndex((i, x, _) -> f(i, x), t)////// Build a set by applying `f` to the seed value `st`.////// `f` should return `Some(a,st1)` to signal a new set element `a` and a new seed value `st1`.////// `f` should return `None` to signal the end of building the set.///pubdefunfold(f: s -> Option[(a, s)] \ ef, st: s): Set[a] \ efwithOrder[a] =defloop(sst, s) = matchf(sst) {case None => scase Some((a, st1)) => loop(st1, insert(a, s)) };loop(st, empty())////// Build a set by applying the function `next` to `()`. `next` is expected to encapsulate/// a stateful resource such as a file handle that can be iterated.////// `next` should return `Some(a)` to signal a value pair `a`.////// `next` should return `None` to signal the end of building the set.///pubdefunfoldWithIter(next: Unit -> Option[a] \ ef): Set[a] \ efwithOrder[a] =defloop(s) = matchnext() {case None => scase Some(a) => loop(insert(a, s)) };loop(empty())////// Build a set by applying `f` to the initial value `x`.////// `f` should return `Some(a1)` to signal a new set element `a1` (which also becomes the next input to `f`).////// `f` should return `None` to signal the end of building the set.///pubdefiterate(f: a -> Option[a] \ ef, x: a): Set[a] \ efwithOrder[a] =defloop(st, s) = matchf(st) {case None => scase Some(a1) => loop(a1, insert(a1, s)) };loop(x, empty())////// Returns an iterator over `s`.///pubdefiterator(rc: Region[r], s: Set[a]): Iterator[a, r, r] \ r =let Set(t) = s;RedBlackTree.iterator(rc, t) |> Iterator.map(fst)////// Returns the concatenation of the string representation/// of each element in `s` with `sep` inserted between each element.///pubdefjoin(sep: String, s: Set[a]): StringwithToString[a] =Foldable.join(sep, s)////// Returns the concatenation of the string representation/// of each element in `s` according to `f` with `sep` inserted between each element.///pubdefjoinWith(f: a -> String \ ef, sep: String, s: Set[a]): String \ ef =Foldable.joinWith(f, sep, s)}