/* * Copyright 2020 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 RedBlackTree {import java.lang.Runtime////// An immutable red-black tree implementation with keys/// of type `k` and values of type `v`.////// A red-black tree is a self-balancing binary search tree./// Each node is either red or black, although a transitory/// color double-black is allowed during deletion./// The red-black tree satisfy the following invariants.////// 1. For all nodes with key `x`,/// the left subtree contains only nodes with keys `y` < `x` and/// the right subtree contains only nodes with keys `z` > `x`./// 2. No red node has a red parent./// 3. Every path from the root to a leaf contains the same/// number of black nodes.///pubenumRedBlackTree[k, v] {////// A black leaf.///case Leaf////// A double-black leaf.///case DoubleBlackLeaf////// A tree node consists of a color, left subtree, key, value and right subtree.///case Node(RedBlackTree.Color, RedBlackTree[k, v], k, v, RedBlackTree[k, v]) }instanceEq[RedBlackTree[k, v]] withEq[k], Eq[v] {pubdefeq(t1: RedBlackTree[k, v], t2: RedBlackTree[k, v]): Bool =RedBlackTree.toList(t1) ==RedBlackTree.toList(t2) }instanceFunctor[RedBlackTree[k]] {pubdefmap(f: a -> b \ ef, t: RedBlackTree[k, a]): RedBlackTree[k, b] \ ef = RedBlackTree.mapWithKey((_, v) -> f(v), t) }instanceFoldable[RedBlackTree[k]] {pubdeffoldLeft(f: (b, v) -> b \ ef, s: b, t: RedBlackTree[k, v]): b \ ef = RedBlackTree.foldLeft((acc, _, v) -> f(acc, v), s, t)pubdeffoldRight(f: (v, b) -> b \ ef, s: b, t: RedBlackTree[k, v]): b \ ef = RedBlackTree.foldRight((_, v, acc) -> f(v, acc), s, t) redef isEmpty(t: RedBlackTree[k, v]): Bool = RedBlackTree.isEmpty(t) }instanceUnorderedFoldable[RedBlackTree[k]] {pubdeffoldMap(f: v -> b \ ef, t: RedBlackTree[k, v]): b \ efwithCommutativeMonoid[b] = RedBlackTree.foldMap(_ -> f, t) redef isEmpty(t: RedBlackTree[k, v]): Bool = RedBlackTree.isEmpty(t) redef exists(f: v -> Bool \ ef, t: RedBlackTree[k, v]): Bool \ ef = RedBlackTree.exists(_ -> f, t) redef forAll(f: v -> Bool \ ef, t: RedBlackTree[k, v]): Bool \ ef = RedBlackTree.forAll(_ -> f, t) }instanceTraversable[RedBlackTree[k]] {pubdeftraverse(f: a -> m[b] \ ef, t: RedBlackTree[k, a]): m[RedBlackTree[k, b]] \ efwithApplicative[m] =RedBlackTree.mapAWithKey((_, v) -> f(v), t) redef sequence(t: RedBlackTree[k, m[a]]): m[RedBlackTree[k, a]] withApplicative[m] =RedBlackTree.mapAWithKey((_, v) -> v, t) }instanceFilterable[RedBlackTree[k]] withOrder[k] {pubdeffilterMap(f: a -> Option[b] \ ef, t: RedBlackTree[k, a]): RedBlackTree[k, b] \ ef = RedBlackTree.filterMap(f, t) redef filter(f: a -> Bool \ ef, t: RedBlackTree[k, a]): RedBlackTree[k, a] \ ef = RedBlackTree.filter(f, t) }instanceWitherable[RedBlackTree[k]] withOrder[k]instanceIterable[RedBlackTree[k, v]] {typeElm = (k, v)pubdefiterator(rc: Region[r], t: RedBlackTree[k, v]): Iterator[(k, v), r, r] \ r =RedBlackTree.iterator(rc, t) }instanceForEach[RedBlackTree[k, v]] {typeElm = (k, v)pubdefforEach(f: ((k, v)) -> Unit \ ef, t: RedBlackTree[k, v]): Unit \ ef = RedBlackTree.forEach(k -> v -> f((k, v)), t) }////// The color of a red-black tree node.///pubenumColor {case Redcase Black////// The special color double-black is allowed temporarily during deletion.///case DoubleBlack }////// Returns the number of threads to use for parallel evaluation.////// # SAFETY:/// This accesses the runtime environment, which is an effect./// It is assumed that this function is only used in contexts/// where this effect is not observable outside of the RedBlackTree module.///defthreads(): Int32 = {// Note: We use a multiple of the number of physical cores for better performance.letmultiplier = 4;multiplier* Runtime.getRuntime().availableProcessors() }////// Determines whether to use parallel evaluation.////// By default we only enable parallel evaluation if the tree has a certain size.///defuseParallelEvaluation(t: RedBlackTree[k, v]): Bool =letminSize = Int32.pow(base = 2, RedBlackTree.blackHeight(t));minSize>=1024////// Returns the number of nodes in `t`.///pubdefsize(t: RedBlackTree[k, v]): Int32 = matcht {case Node(_, a, _, _, b) => size(a) +1+size(b)case_ => 0 }////// Returns the empty tree.///pubdefempty(): RedBlackTree[k, v] = Leaf////// Returns `true` if and only if `t` is the empty tree.///pubdefisEmpty(t: RedBlackTree[k, v]): Bool = matcht {case Leaf => truecase_ => false }////// Returns `true` if and only if `t` is a non-empty tree.///pubdefnonEmpty(t: RedBlackTree[k, v]): Bool = notisEmpty(t)////// Updates `t` with `k => v` if `k => v1` is in `t`.////// Otherwise, updates `t` with `k => v`.///pubdefinsert(k: k, v: v, t: RedBlackTree[k, v]): RedBlackTree[k, v] withOrder[k] =defloop(tt) = matchtt {case Leaf => Node(Color.Red, Leaf, k, v, Leaf)case Node(c, a, k1, v1, b) => matchk<=>k1 {case Comparison.LessThan => balance(Node(c, loop(a), k1, v1, b))case Comparison.EqualTo => Node(c, a, k, v, b)case Comparison.GreaterThan => balance(Node(c, a, k1, v1, loop(b))) }case_ => unreachable!() };blacken(loop(t))////// Updates `t` with `k => f(k, v, v1)` if `k => v1` is in `t`.////// Otherwise, updates `t` with `k => v`.///pubdefinsertWith(f: (k, v, v) -> v \ ef, k: k, v: v, t: RedBlackTree[k, v]): RedBlackTree[k, v] \ efwithOrder[k] =defloop(tt) = matchtt {case Leaf => Node(Color.Red, Leaf, k, v, Leaf)case Node(c, a, k1, v1, b) => matchk<=>k1 {case Comparison.LessThan => balance(Node(c, loop(a), k1, v1, b))case Comparison.EqualTo => Node(c, a, k, f(k, v, v1), b)case Comparison.GreaterThan => balance(Node(c, a, k1, v1, loop(b))) }case_ => unreachable!() };blacken(loop(t))////// Updates `t` with `k => v1` if `k => v` is in `t` and `f(k, v) = Some(v1)`.////// Otherwise, returns `t`.///pubdefupdateWith(f: (k, v) -> Option[v] \ ef, k: k, t: RedBlackTree[k, v]): RedBlackTree[k, v] \ efwithOrder[k] =defloop(tt) = matchtt {case Leaf => Leafcase Node(c, a, k1, v1, b) => matchk<=>k1 {case Comparison.LessThan => balance(Node(c, loop(a), k1, v1, b))case Comparison.EqualTo => matchf(k1, v1) {case None => ttcase Some(v) => Node(c, a, k, v, b) }case Comparison.GreaterThan => balance(Node(c, a, k1, v1, loop(b))) }case_ => unreachable!() };blacken(loop(t))////// Removes `k => v` from `t` if `t` contains the key `k`.////// Otherwise, returns `t`.///pubdefremove(k: k, t: RedBlackTree[k, v]): RedBlackTree[k, v] withOrder[k] =defloop(tt) = matchtt {case Node(Color.Red, Leaf, k1, _, Leaf) => if ((k<=>k1) == Comparison.EqualTo) Leaf elsettcase Node(Color.Black, Leaf, k1, _, Leaf) => if ((k<=>k1) == Comparison.EqualTo) DoubleBlackLeaf elsettcase Node(Color.Black, Node(Color.Red, Leaf, k1, v1, Leaf), k2, v2, Leaf) =>matchk<=>k2 {case Comparison.LessThan => Node(Color.Black, loop(Node(Color.Red, Leaf, k1, v1, Leaf)), k2, v2, Leaf)case Comparison.EqualTo => Node(Color.Black, Leaf, k1, v1, Leaf)case Comparison.GreaterThan => Node(Color.Black, Node(Color.Red, Leaf, k1, v1, Leaf), k2, v2, Leaf) }case Node(c, a, k1, v1, b) =>matchk<=>k1 {case Comparison.LessThan => rotate(Node(c, loop(a), k1, v1, b))case Comparison.EqualTo =>let (k2, v2, e) = minDelete(b);rotate(Node(c, a, k2, v2, e))case Comparison.GreaterThan => rotate(Node(c, a, k1, v1, loop(b))) }case_ => tt };redden(loop(t))////// Returns `Some(v)` if `k => v` is in `t`.////// Otherwise returns `None`.///pubdefget(k: k, t: RedBlackTree[k, v]): Option[v] withOrder[k] = matcht {case Node(_, a, k1, v, b) => matchk<=>k1 {case Comparison.LessThan => get(k, a)case Comparison.EqualTo => Some(v)case Comparison.GreaterThan => get(k, b) }case_ => None }////// Returns `true` if and only if `t` contains the key `k`.///pubdefmemberOf(k: k, t: RedBlackTree[k, v]): BoolwithOrder[k] = matcht {case Node(_, a, k1, _, b) => matchk<=>k1 {case Comparison.LessThan => memberOf(k, a)case Comparison.EqualTo => truecase Comparison.GreaterThan => memberOf(k, b) }case_ => false }////// Optionally returns the first key-value pair in `t` that satisfies the predicate `f` when searching from left to right.///pubdeffindLeft(f: (k, v) -> Bool \ ef, t: RedBlackTree[k, v]): Option[(k, v)] \ ef = matcht {case Leaf => Nonecase DoubleBlackLeaf => Nonecase Node(_, a, k, v, b) => matchfindLeft(f, a) {case Some((ka, va)) => Some((ka, va))case None =>if (f(k, v)) Some((k, v))elsefindLeft(f, b) } }////// Optionally returns the first key-value pair in `t` that satisfies the predicate `f` when searching from right to left.///pubdeffindRight(f: (k, v) -> Bool \ ef, t: RedBlackTree[k, v]): Option[(k, v)] \ ef = matcht {case Leaf => Nonecase DoubleBlackLeaf => Nonecase Node(_, a, k, v, b) => matchfindRight(f, b) {case Some((kb, vb)) => Some((kb, vb))case None =>if (f(k, v)) Some((k, v))elsefindRight(f, a) } }////// Applies `f` to a start value `s` and all key-value pairs in `t` going from left to right.////// That is, the result is of the form: `f(...f(f(s, k1, v1), k2, v2)..., vn)`.///pubdeffoldLeft(f: (b, k, v) -> b \ ef, s: b, t: RedBlackTree[k, v]): b \ ef = matcht {case Node(_, a, k, v, b) => foldLeft(f, f(foldLeft(f, s, a), k, v), b)case_ => s }////// Applies `f` to a start value `s` and all key-value pairs in `tree` going from right to left.////// That is, the result is of the form: `f(k1, v1, ...f(kn-1, vn-1, f(kn, vn, s)))`.///pubdeffoldRight(f: (k, v, b) -> b \ ef, s: b, t: RedBlackTree[k, v]): b \ ef = matcht {case Node(_, a, k, v, b) => foldRight(f, f(k, v, foldRight(f, s, b)), a)case_ => s }////// Returns the result of mapping each key-value pair and combining the results.///pubdeffoldMap(f: (k, v) -> b \ ef, t: RedBlackTree[k, v]): b \ efwithMonoid[b] =foldLeft((acc, k, v) -> Monoid.combine(acc, f(k, v)), Monoid.empty(), t)////// Applies `f` to all key-value pairs in `tree` going from left to right until a single pair `(k, v)` is obtained.////// That is, the result is of the form: `Some(f(...f(f(k1, v1, k2, v2), k3, v3)..., kn, vn))`////// Returns `None` if `t` is the empty tree.///pubdefreduceLeft(f: (k, v, k, v) -> (k, v) \ ef, t: RedBlackTree[k, v]): Option[(k, v)] \ ef =foldLeft( (x, k1, v1) -> matchx {case Some((k2, v2)) => Some(f(k2, v2, k1, v1))case None => Some((k1, v1)) }, None,t )////// Applies `f` to all key-value pairs in `t` going from right to left until a single pair `(k, v)` is obtained.////// That is, the result is of the form: `Some(f(k1, v1, ...f(kn-2, vn-2, f(kn-1, vn-1, kn, vn))...))`.////// Returns `None` if `t` is the empty tree.///pubdefreduceRight(f: (k, v, k, v) -> (k, v) \ ef, t: RedBlackTree[k, v]): Option[(k, v)] \ ef =foldRight( (k1, v1, acc) -> matchacc {case Some((k2, v2)) => Some(f(k1, v1, k2, v2))case None => Some((k1, v1)) }, None,t )////// Returns `true` if and only if at least one key-value pair in `t` satisfies the predicate `f`.////// Returns `false` if `t` is the empty tree.///pubdefexists(f: (k, v) -> Bool \ ef, t: RedBlackTree[k, v]): Bool \ ef = matcht {case Node(_, a, k, v, b) => if (f(k, v)) trueelseexists(f, a) orexists(f, b)case_ => false }////// Returns `true` if and only if at least one key-value pair in `t` satisfies the predicate `f`.////// Returns `false` if `t` is the empty tree.////// The function `f` must be pure.////// Traverses the tree `t` in parallel.///@ParallelpubdefparExists(f: (k, v) -> Bool, t: RedBlackTree[k, v]): Bool = {defvisitSubtree(n, st) = {if (n<=1)seqExists(f, st)elsematchst {case Node(_, a, k, v, b) =>if (f(k, v))trueelsepar (// We divide the rest of the threads as follows:// We spawn two new threads leaving us with n - 2// that we distribute over the two spanned threads.l <- visitSubtree((n-2) /2, a);r <- visitSubtree((n-2) /2, b) ) yieldlorrcase_ => false } };visitSubtree(threads()-1, t) }////// Returns `true` if and only if at least one key-value pair in `t` satisfies the predicate `f`.////// Returns `false` if `t` is the empty tree.////// The function `f` must be pure.////// Note that this is equivalent to `exists` but for performance reasons -- to avoid/// megamorphic calls -- we use a copy here.///defseqExists(f: (k, v) -> Bool, t: RedBlackTree[k, v]): Bool = matcht {case Node(_, a, k, v, b) => if (f(k, v)) trueelseseqExists(f, a) orseqExists(f, b)case_ => false }////// Returns `true` if and only if all key-value pairs in `t` satisfy the predicate `f`.////// Returns `true` if `t` is the empty tree.///pubdefforAll(f: (k, v) -> Bool \ ef, t: RedBlackTree[k, v]): Bool \ ef = matcht {case Node(_, a, k, v, b) => if (f(k, v)) forAll(f, a) andforAll(f, b) elsefalsecase_ => true }////// Returns `true` if and only if all key-value pairs in `t` satisfy the predicate `f`.////// Returns `true` if `t` is the empty tree.////// The function `f` must be pure.////// Traverses the tree `t` in parallel.///@ParallelpubdefparForAll(f: (k, v) -> Bool, t: RedBlackTree[k, v]): Bool = {defvisitSubtree(n, st) = {if (n<=1)seqForAll(f, st)elsematchst {case Node(_, a, k, v, b) =>if (notf(k, v))falseelsepar (// We divide the rest of the threads as follows:// We spawn two new threads leaving us with n - 2// that we distribute over the two spanned threads.l <- visitSubtree((n-2) /2, a);r <- visitSubtree((n-2) /2, b) ) yieldlandrcase_ => false } };visitSubtree(threads()-1, t) }////// Returns `true` if and only if all key-value pairs in `t` satisfy the predicate `f`.////// Returns `true` if `t` is the empty tree.////// The function `f` must be pure.////// Note that this is equivalent to `exists` but for performance reasons -- to avoid/// megamorphic calls -- we use a copy here.///defseqForAll(f: (k, v) -> Bool, t: RedBlackTree[k, v]): Bool = matcht {case Node(_, a, k, v, b) => if (f(k, v)) seqForAll(f, a) andseqForAll(f, b) elsefalsecase_ => true }////// Applies `f` to every key-value pair of `t`.///pubdefforEach(f: (k, v) -> Unit \ ef, t: RedBlackTree[k, v]): Unit \ ef = matcht {case Node(_, a, k, v, b) => forEach(f, a); f(k, v); forEach(f, b)case_ => () }////// Applies `f` to every key-value pair of `t` along with that element's index.///pubdefforEachWithIndex(f: (Int32, k, v) -> Unit \ ef, t: RedBlackTree[k, v]): Unit \ ef = regionrc {letix = Ref.fresh(rc, 0);defloop(tt) = matchtt {case Node(_, a, k, v, b) =>loop(a);leti = Ref.get(ix);f(i, k, v);Ref.put(i+1, ix); loop(b)case_ => () };loop(t) }////// Helper function for `insert` and `delete`.///defbalance(t: RedBlackTree[k, v]): RedBlackTree[k, v] = matcht {case Node(Color.Black, left, k1, v1, right) =>balanceBlack(t, left, k1, v1, right)case Node(Color.DoubleBlack, left, k1, v1, right) =>balanceDoubleBlack(t, left, k1, v1, right)case_ => t }////// Helper function for `balance`. Handles the black node cases.///defbalanceBlack(t: RedBlackTree[k, v], left: RedBlackTree[k, v], k1: k, v1: v, right: RedBlackTree[k, v]): RedBlackTree[k, v] =matchleft {case Node(Color.Red, Node(Color.Red, a, k2, v2, b), k3, v3, c) => Node(Color.Red, Node(Color.Black, a, k2, v2, b), k3, v3, Node(Color.Black, c, k1, v1, right))case Node(Color.Red, a, k2, v2, Node(Color.Red, b, k3, v3, c)) => Node(Color.Red, Node(Color.Black, a, k2, v2, b), k3, v3, Node(Color.Black, c, k1, v1, right))case_ => matchright {case Node(Color.Red, Node(Color.Red, b, k2, v2, c), k3, v3, d) => Node(Color.Red, Node(Color.Black, left, k1, v1, b), k2, v2, Node(Color.Black, c, k3, v3, d))case Node(Color.Red, b, k2, v2, Node(Color.Red, c, k3, v3, d)) => Node(Color.Red, Node(Color.Black, left, k1, v1, b), k2, v2, Node(Color.Black, c, k3, v3, d))case_ => t } }////// Helper function for `balance`. Handles the double-black node cases.///defbalanceDoubleBlack(t: RedBlackTree[k, v], left: RedBlackTree[k, v], k1: k, v1: v, right: RedBlackTree[k, v]): RedBlackTree[k, v] =matchright {case Node(Color.Red, Node(Color.Red, b, k2, v2, c), k3, v3, d) => Node(Color.Black, Node(Color.Black, left, k1, v1, b), k2, v2, Node(Color.Black, c, k3, v3, d))case_ => matchleft {case Node(Color.Red, a, k2, v2, Node(Color.Red, b, k3, v3, c)) => Node(Color.Black, Node(Color.Black, a, k2, v2, b), k3, v3, Node(Color.Black, c, k1, v1, right))case_ => t } }////// Helper function for `insert`.///defblacken(t: RedBlackTree[k, v]): RedBlackTree[k, v] = matcht {case Node(Color.Red, Node(Color.Red, a, k1, v1, b), k2, v2, c) => Node(Color.Black, Node(Color.Red, a, k1, v1, b), k2, v2, c)case Node(Color.Red, a, k1, v1, Node(Color.Red, b, k2, v2, c)) => Node(Color.Black, a, k1, v1, Node(Color.Red, b, k2, v2, c))case_ => t }////// Helper function for `delete`.///defrotate(t: RedBlackTree[k, v]): RedBlackTree[k, v] = matcht {case Node(Color.Red, left, k1, v1, right) =>rotateRed(t, left, k1, v1, right)case Node(Color.Black, left, k1, v1, right) =>rotateBlack(t, left, k1, v1, right)case_ => t }////// Helper function for `rotate`. Handles the red node cases.///defrotateRed(t: RedBlackTree[k, v], left: RedBlackTree[k, v], k1: k, v1: v, right: RedBlackTree[k, v]): RedBlackTree[k, v] =matchleft {case Node(Color.DoubleBlack, a, k2, v2, b) => matchright {case Node(Color.Black, c, k3, v3, d) =>balance(Node(Color.Black, Node(Color.Red, Node(Color.Black, a, k2, v2, b), k1, v1, c), k3, v3, d))case_ => t }case DoubleBlackLeaf => matchright {case Node(Color.Black, c, k3, v3, d) =>balance(Node(Color.Black, Node(Color.Red, Leaf, k1, v1, c), k3, v3, d))case_ => t }case Node(Color.Black, a, k2, v2, b) => matchright {case Node(Color.DoubleBlack, c, k3, v3, d) =>balance(Node(Color.Black, a, k2, v2, Node(Color.Red, b, k1, v1, Node(Color.Black, c, k3, v3, d))))case DoubleBlackLeaf =>balance(Node(Color.Black, a, k2, v2, Node(Color.Red, b, k1, v1, Leaf)))case_ => t }case_ => t }////// Helper function for `rotate`. Handles the black node cases.///defrotateBlack(t: RedBlackTree[k, v], left: RedBlackTree[k, v], k1: k, v1: v, right: RedBlackTree[k, v]): RedBlackTree[k, v] =matchleft {case Node(Color.DoubleBlack, a, k2, v2, b) => matchright {case Node(Color.Black, c, k3, v3, d) =>balance(Node(Color.DoubleBlack, Node(Color.Red, Node(Color.Black, a, k2, v2, b), k1, v1, c), k3, v3, d))case Node(Color.Red, Node(Color.Black, c, k3, v3, d), k4, v4, e) => Node(Color.Black, balance(Node(Color.Black, Node(Color.Red, Node(Color.Black, a, k2, v2, b), k1, v1, c), k3, v3, d)), k4, v4, e)case_ => t }case DoubleBlackLeaf => matchright {case Node(Color.Black, c, k3, v3, d) =>balance(Node(Color.DoubleBlack, Node(Color.Red, Leaf, k1, v1, c), k3, v3, d))case Node(Color.Red, Node(Color.Black, c, k3, v3, d), k4, v4, e) => Node(Color.Black, balance(Node(Color.Black, Node(Color.Red, Leaf, k1, v1, c), k3, v3, d)), k4, v4, e)case_ => t }case Node(Color.Black, a, k2, v2, b) => matchright {case Node(Color.DoubleBlack, c, k3, v3, d) =>balance(Node(Color.DoubleBlack, a, k2, v2, Node(Color.Red, b, k1, v1, Node(Color.Black, c, k3, v3, d))))case DoubleBlackLeaf =>balance(Node(Color.DoubleBlack, a, k2, v2, Node(Color.Red, b, k1, v1, Leaf)))case_ => t }case Node(Color.Red, a, k2, v2, Node(Color.Black, b, k3, v3, c)) => matchright {case Node(Color.DoubleBlack, d, k4, v4, e) => Node(Color.Black, a, k2, v2, balance(Node(Color.Black, b, k3, v3, Node(Color.Red, c, k1, v1, Node(Color.Black, d, k4, v4, e)))))case DoubleBlackLeaf => Node(Color.Black, a, k2, v2, balance(Node(Color.Black, b, k3, v3, Node(Color.Red, c, k1, v1, Leaf))))case_ => t }case_ => t }////// Helper function for `delete`.///defredden(t: RedBlackTree[k, v]): RedBlackTree[k, v] = matcht {case Node(Color.Black, Node(Color.Black, a, k1, v1, b), k2, v2, Node(Color.Black, c, k3, v3, d)) => Node(Color.Red, Node(Color.Black, a, k1, v1, b), k2, v2, Node(Color.Black, c, k3, v3, d))case DoubleBlackLeaf => Leafcase_ => t }////// Helper function for `delete`.///defminDelete(t: RedBlackTree[k, v]): (k, v, RedBlackTree[k, v]) =defloop(tt) = matchtt {case Node(Color.Red, Leaf, k1, v1, Leaf) => (k1, v1, Leaf)case Node(Color.Black, Leaf, k1, v1, Leaf) => (k1, v1, DoubleBlackLeaf)case Node(Color.Black, Leaf, k1, v1, Node(Color.Red, Leaf, k2, v2, Leaf)) => (k1, v1, Node(Color.Black, Leaf, k2, v2, Leaf))case Node(c, a, k1, v1, b) =>let (k, v, child) = loop(a); (k, v, rotate(Node(c, child, k1, v1, b)))case_ => unreachable!() };loop(t)////// Applies `f` to all key-value pairs from `t` where `p(k)` returns `Comparison.EqualTo`.////// The function `f` must be impure.///pubdefrangeQueryWith(p: k -> Comparison \ ef1, f: (k, v) -> Unit \ ef2, t: RedBlackTree[k, v]): Unit \ { ef1, ef2 } = matcht {case Node(_, a, k, v, b) =>matchp(k) {case Comparison.LessThan => rangeQueryWith(p, f, b)case Comparison.EqualTo => rangeQueryWith(p, f, a); f(k, v); rangeQueryWith(p, f, b)case Comparison.GreaterThan => rangeQueryWith(p, f, a) }case_ => () }////// Extracts a range of key-value pairs from `t`.////// That is, the result is a list of all pairs `f(k, v)` where `p(k)` returns `Equal`.///pubdefrangeQuery(p: k -> Comparison \ ef1, f: (k, v) -> a \ ef2, t: RedBlackTree[k, v]): List[a] \ { ef1, ef2 } = regionrc {letbuffer = MutList.empty(rc);letg = k -> v -> MutList.push(f(k, v), buffer);rangeQueryWith(p, g, t);MutList.toList(buffer) }////// Extracts `k => v` where `k` is the leftmost (i.e. smallest) key in the tree.///pubdefminimumKey(t: RedBlackTree[k, v]): Option[(k, v)] = matcht {case Node(_, Leaf, k, v, _) => Some((k, v))case Node(_, a, _, _, _) => minimumKey(a)case_ => None }////// Extracts `k => v` where `k` is the rightmost (i.e. largest) key in the tree.///pubdefmaximumKey(t: RedBlackTree[k, v]): Option[(k, v)] = matcht {case Node(_, _, k, v, Leaf) => Some((k, v))case Node(_, _, _, _, b) => maximumKey(b)case_ => None }////// Returns the black height of `t`.///pubdefblackHeight(t: RedBlackTree[k, v]): Int32 =defloop(tt, acc) = matchtt {case Node(Color.Black, a, _, _, _) => loop(a, 1+acc)case Node(_, a, _, _, _) => loop(a, acc)case_ => acc };loop(t, 0)////// Returns a RedBlackTree with mappings `k => f(k, v)` for every `k => v` in `t`.////// Purity reflective: Runs in parallel when given a pure function `f`.///@ParallelWhenPurepubdefmapWithKey(f: (k, v1) -> v2 \ ef, t: RedBlackTree[k, v1]): RedBlackTree[k, v2] \ ef =matchpurityOf2(f) {case Purity2.Pure(g) =>if (useParallelEvaluation(t))parMapWithKey(g, t)elseseqMapWithKey(f, t)case Purity2.Impure(_) => seqMapWithKey(f, t) }////// Maps `f` over the tree `t` in parallel.////// The implementation spawns a number of threads each applying `f` sequentially/// from left to right on some subtree that is disjoint from the rest of/// the threads.///@ParalleldefparMapWithKey(f: (k, v1) -> v2, t: RedBlackTree[k, v1]): RedBlackTree[k, v2] = {defvisitSubtree(n, st) = {if (n<=1)parSeqMapWithKey(f, st)elsematchst {case Leaf => Leafcase DoubleBlackLeaf => DoubleBlackLeafcase Node(c, a, k, v, b) =>par (// We divide the rest of the threads as follows:// We spawn two new threads leaving us with n - 2// that we distribute over the two spanned threads.l <- visitSubtree((n-2) /2, a);r <- visitSubtree((n-2) /2, b);v1 <- f(k, v) ) yield Node(c, l, k, v1, r) } };visitSubtree(threads()-1, t) }////// Maps `f` over the tree `t` sequentially from left to right.////// Note that this is equivalent to `seqMapWithKey` but for performance reasons -- to avoid/// megamorphic calls -- we use a copy here.///defparSeqMapWithKey(f: (k, v1) -> v2, t: RedBlackTree[k, v1]): RedBlackTree[k, v2] = matcht {// Note that while this is identical to `seqMapWithKey` it must still be its own function// because the parallel path must not be reuse the seq. path.case Leaf => Leafcase DoubleBlackLeaf => DoubleBlackLeafcase Node(c, a, k, v, b) =>leta1 = seqMapWithKey(f, a);letv1 = f(k, v);letb1 = seqMapWithKey(f, b); Node(c, a1, k, v1, b1) }////// Sequentially maps `f` over the tree `t`.///defseqMapWithKey(f: (k, v1) -> v2 \ ef, t: RedBlackTree[k, v1]): RedBlackTree[k, v2] \ ef = matcht {case Leaf => Leafcase DoubleBlackLeaf => DoubleBlackLeafcase Node(c, a, k, v, b) =>leta1 = seqMapWithKey(f, a);letv1 = f(k, v);letb1 = seqMapWithKey(f, b); Node(c, a1, k, v1, b1) }////// Applies `f` over the tree `t` in parallel and returns the number of elements/// that satisfy the predicate `f`.////// The implementation spawns a number of threads each applying `f` sequentially/// from left to right on some subtree that is disjoint from the rest of/// the threads.///@ParallelpubdefparCount(f: (k, v) -> Bool, t: RedBlackTree[k, v]): Int32 = {defvisitSubtree(n, st) = {if (n<=1)seqCount(f, st)elsematchst {case Leaf => 0case DoubleBlackLeaf => 0case Node(_, a, k, v, b) =>par (// We divide the rest of the threads as follows:// We spawn two new threads leaving us with n - 2// that we distribute over the two spanned threads.l <- visitSubtree((n-2) /2, a);r <- visitSubtree((n-2) /2, b);v1 <- if (f(k, v)) 1else0 ) yieldl+v1+r } };visitSubtree(threads()-1, t) }////// Applies `f` over the tree `t` sequentially from left to right and returns the number of elements/// that satisfy the predicate `f`.///defseqCount(f: (k, v) -> Bool, t: RedBlackTree[k, v]): Int32 = matcht {case Leaf => 0case DoubleBlackLeaf => 0case Node(_, a, k, v, b) =>leta1 = seqCount(f, a);letv1 = if (f(k, v)) 1else0;letb1 = seqCount(f, b);a1+v1+b1 }////// Returns the sum of all keys in the tree `t`.///pubdefsumKeys(t: RedBlackTree[Int32, v]): Int32 =sumWith((k, _) -> k, t)////// Returns the sum of all values in the tree `t`.///pubdefsumValues(t: RedBlackTree[k, Int32]): Int32 =sumWith((_, v) -> v, t)////// Returns the sum of all key-value pairs `k => v` in the tree `t`/// according to the function `f`.///pubdefsumWith(f: (k, v) -> Int32 \ ef, t: RedBlackTree[k, v]): Int32 \ ef = matcht {case Leaf => 0case DoubleBlackLeaf => 0case Node(_, a, k, v, b) =>letx = sumWith(f, a);lety = f(k, v);letz = sumWith(f, b);x+y+z }////// Returns the sum of all key-value pairs `k => v` in the tree `t`/// according to the function `f`.////// The implementation spawns a number of threads each applying `f` sequentially/// from left to right on some subtree that is disjoint from the rest of/// the threads.///@ParallelpubdefparSumWith(f: (k, v) -> Int32, t: RedBlackTree[k, v]): Int32 = {defvisitSubtree(n, st) = {if (n<=1)seqSumWith(f, st)elsematchst {case Leaf => 0case DoubleBlackLeaf => 0case Node(_, a, k, v, b) =>par (// We divide the rest of the threads as follows:// We spawn two new threads leaving us with n - 2// that we distribute over the two spanned threads.l <- visitSubtree((n-2) /2, a);r <- visitSubtree((n-2) /2, b);v1 <- f(k, v) ) yieldl+v1+r } };visitSubtree(threads()-1, t) }////// Returns the sum of all key-value pairs `k => v` in the tree `t`/// according to the function `f`.////// Note that this is equivalent to `sumWith` but for performance reasons -- to avoid/// megamorphic calls -- we use a copy here.///defseqSumWith(f: (k, v) -> Int32, t: RedBlackTree[k, v]): Int32 = matcht {case Leaf => 0case DoubleBlackLeaf => 0case Node(_, a, k, v, b) =>letx = seqSumWith(f, a);lety = f(k, v);letz = seqSumWith(f, b);x+y+z }////// Returns the tree `t` as a list. Elements are ordered from smallest (left) to largest (right).///pubdeftoList(t: RedBlackTree[k, v]): List[(k, v)] =RedBlackTree.foldRight((k, v, acc) -> (k, v) :: acc, Nil, t)////// Build a node applicatively.////// This is a helper function for `mapAWithKey`.///defnodeA(color: Color, left: m[RedBlackTree[k, v]], k: k, value: m[v], right: m[RedBlackTree[k, v]]): m[RedBlackTree[k, v]] withApplicative[m] =use Functor.{<$>};use Applicative.{<*>}; ((((l, v, r) -> Node(color, l, k, v, r)) <$> left) <*> value) <*> right////// Returns a RedBlackTree with mappings `k => f(v)` for every `k => v` in `t`.///pubdefmapAWithKey(f: (k, v1) -> m[v2] \ ef, t: RedBlackTree[k, v1]): m[RedBlackTree[k, v2]] \ efwithApplicative[m] = matcht {case Node(color, left, key, v, right) =>letleftA = mapAWithKey(f, left);letans = f(key, v);letrightA = mapAWithKey(f, right);nodeA(color, leftA, key, ans, rightA)case_ => Applicative.point(Leaf) }////// Applies `cmp` over the tree `t` in parallel and optionally returns the lowest/// element according to `cmp`.////// The implementation spawns a number of threads each applying `cmp` sequentially/// from left to right on some subtree that is disjoint from the rest of/// the threads.///@ParallelpubdefparMinimumBy(cmp: (k, v, k, v) -> Comparison, t: RedBlackTree[k, v]): Option[(k, v)] =parLimitBy((kl, vl, kr, vr) -> if (cmp(kl, vl, kr, vr) == Comparison.LessThan) (kl, vl) else (kr, vr), t)////// Applies `cmp` over the tree `t` in parallel and optionally returns the largest/// element according to `cmp`.////// The implementation spawns a number of threads each applying `cmp` sequentially/// from left to right on some subtree that is disjoint from the rest of/// the threads.///@ParallelpubdefparMaximumBy(cmp: (k, v, k, v) -> Comparison, t: RedBlackTree[k, v]): Option[(k, v)] =parLimitBy((kl, vl, kr, vr) -> if (cmp(kl, vl, kr, vr) == Comparison.GreaterThan) (kl, vl) else (kr, vr), t)////// Helper function for `minimumBy` & `maximumBy`.////// Applies `cmp` over the tree `t` in parallel and optionally returns the min/max (decided by `decider`)/// element according to `cmp`.////// The implementation spawns a number of threads each applying `cmp` sequentially/// from left to right on some subtree that is disjoint from the rest of/// the threads.///@ParalleldefparLimitBy(cmp: (k, v, k, v) -> (k, v), t: RedBlackTree[k, v]): Option[(k, v)] = {defvisitSubtree(n, st) = {if (n<=0)seqLimitBy(cmp, st)elsematchst {case Leaf => Nonecase DoubleBlackLeaf => Nonecase Node(_, a, k, v, b) =>par (// We divide the rest of the threads as follows:// We spawn two new threads leaving us with n - 2// that we distribute over the two spanned threads.l <- visitSubtree((n-2) /2, a);r <- visitSubtree((n-2) /2, b) ) yieldmatch (l, r) {case (None, None) => Some((k, v))case (None, Some((kr, vr))) => Some(cmp(k, v, kr, vr))case (Some((kl, vl)), None) => Some(cmp(kl, vl, k, v))case (Some((kl, vl)), Some((kr, vr))) =>let (km, vm) = cmp(kl, vl, k, v); // Compare "lesser" keys first Some(cmp(km, vm, kr, vr)) } } };visitSubtree(threads()-1, t) }////// Applies `cmp` over the tree `t` sequentially and optionally returns the lowest/// element according to `cmp`.///defseqLimitBy(cmp: (k, v, k, v) -> (k, v) \ ef, t: RedBlackTree[k, v]): Option[(k, v)] \ ef = matcht {case Node(_, a, k, v, b) =>letres = matchseqLimitBy(cmp, a) {case None => (k, v)case Some((kl, vl)) => cmp(kl, vl, k, v) };matchseqLimitBy(cmp, b) {case None => Some(res)case Some((kr, vr)) =>let (ks, vs) = res; Some(cmp(ks, vs, kr, vr)) }case_ => None }////// Returns the concatenation of the string representation of each key `k`/// in `t` with `sep` inserted between each element.///pubdefjoinKeys(sep: String, t: RedBlackTree[k, v]): StringwithToString[k] =joinWith((k, _) -> ToString.toString(k), sep, t)////// Returns the concatenation of the string representation of each value `v`/// in `t` with `sep` inserted between each element.///pubdefjoinValues(sep: String, t: RedBlackTree[k, v]): StringwithToString[v] =joinWith((_, v) -> ToString.toString(v), sep, t)////// Returns the concatenation of the string representation of each key-value pair/// `k => v` in `t` according to `f` with `sep` inserted between each element.///pubdefjoinWith(f: (k, v) -> String \ ef, sep: String, t: RedBlackTree[k, v]): String \ ef = regionrc {use StringBuilder.append;letlastSep = String.length(sep);letsb = StringBuilder.empty(rc);forEach((k, v) -> { append(f(k, v), sb); append(sep, sb) }, t);StringBuilder.toString(sb) |> String.dropRight(lastSep) }////// Returns a new copy of tree `t` with just the nodes that satisfy the predicate `f`.///pubdeffilter(f: v -> Bool \ ef, t: RedBlackTree[k, v]): RedBlackTree[k, v] \ efwithOrder[k] =foldLeft((acc, k, v) -> if (f(v)) insert(k, v, acc) elseacc, empty(), t)////// Collects the results of applying the partial function `f` to every element in `t`./// This traverses tree `t` and produces a new tree with just nodes where applying f/// produces `Some(_)`.///pubdeffilterMap(f: a -> Option[b] \ ef, t: RedBlackTree[k, a]): RedBlackTree[k, b] \ efwithOrder[k] =letstep = (acc, k, a) -> matchf(a) {case Some(b) => insert(k, b, acc)case None => acc };foldLeft(step, empty(), t)////// Returns an iterator over `t`.///pubdefiterator(rc: Region[r], t: RedBlackTree[k, v]): Iterator[(k, v), r, r] \ r =letstack1 = leftmost(t, Nil);letstate = Ref.fresh(rc, stack1);letnext = () -> matchRef.get(state) {case Nil => Nonecase (k, v, rtree) :: es =>Ref.put(leftmost(rtree, es), state); Some((k, v)) };Iterator.unfoldWithIter(rc, next)////// This represents pending items `(key, value, right-tree)` encountered while finding the/// leftmost node in a tree to start iterating from.///typealiasIterStack2[k, v] = List[(k, v, RedBlackTree[k, v])]////// Helper function for `iterator`./// This is called before iteration starts to find the leftmost node of/// the tree and build a stack of pending items. As the iterator is run it will/// call `leftmost` on pending "right trees" in the stack.///defleftmost(t: RedBlackTree[k, v], es: IterStack2[k, v]): IterStack2[k, v] = matcht {case Leaf => escase DoubleBlackLeaf => escase Node(_, ltree, k, v, rtree) => leftmost(ltree, (k, v, rtree) :: es) }}