2010-06-22 03:22:11 +02:00
|
|
|
/* sbt -- Simple Build Tool
|
|
|
|
|
* Copyright 2010 Mark Harrah
|
|
|
|
|
*/
|
|
|
|
|
package sbt
|
|
|
|
|
|
|
|
|
|
object Relation
|
|
|
|
|
{
|
|
|
|
|
/** Constructs a new immutable, finite relation that is initially empty. */
|
2010-06-27 15:16:16 +02:00
|
|
|
def empty[A,B]: Relation[A,B] = make(Map.empty, Map.empty)
|
|
|
|
|
def make[A,B](forward: Map[A,Set[B]], reverse: Map[B, Set[A]]): Relation[A,B] = new MRelation(forward, reverse)
|
2010-06-22 03:22:11 +02:00
|
|
|
}
|
2010-06-25 00:09:07 +02:00
|
|
|
/** Binary relation between A and B. It is a set of pairs (_1, _2) for _1 in A, _2 in B. */
|
|
|
|
|
trait Relation[A,B]
|
2010-06-22 03:22:11 +02:00
|
|
|
{
|
|
|
|
|
/** Returns the set of all _2s such that (_1, _2) is in this relation. */
|
2010-06-25 00:09:07 +02:00
|
|
|
def forward(_1: A): Set[B]
|
2010-06-22 03:22:11 +02:00
|
|
|
/** Returns the set of all _1s such that (_1, _2) is in this relation. */
|
2010-06-25 00:09:07 +02:00
|
|
|
def reverse(_2: B): Set[A]
|
2010-06-22 03:22:11 +02:00
|
|
|
/** Includes the relation given by `pair`. */
|
2010-06-25 00:09:07 +02:00
|
|
|
def +(pair: (A, B)): Relation[A,B]
|
2010-06-22 03:22:11 +02:00
|
|
|
/** Includes the relation (a, b). */
|
2010-06-25 00:09:07 +02:00
|
|
|
def +(a: A, b: B): Relation[A,B]
|
2010-06-22 03:22:11 +02:00
|
|
|
/** Includes the relations (a, b) for all b in bs. */
|
2010-06-25 00:09:07 +02:00
|
|
|
def +(a: A, bs: Iterable[B]): Relation[A,B]
|
2010-06-22 03:22:11 +02:00
|
|
|
/** Returns the union of the relation r with this relation. */
|
2010-06-25 00:09:07 +02:00
|
|
|
def ++(r: Relation[A,B]): Relation[A,B]
|
2010-06-22 03:22:11 +02:00
|
|
|
/** Includes the given relations. */
|
2010-06-25 00:09:07 +02:00
|
|
|
def ++(rs: Iterable[(A,B)]): Relation[A,B]
|
2010-06-22 03:22:11 +02:00
|
|
|
/** Removes all relations (_1, _2) for all _1 in _1s. */
|
2010-06-25 00:09:07 +02:00
|
|
|
def --(_1s: Iterable[A]): Relation[A,B]
|
2010-06-22 03:22:11 +02:00
|
|
|
/** Removes all `pairs` from this relation. */
|
2010-06-25 00:09:07 +02:00
|
|
|
def --(pairs: Traversable[(A,B)]): Relation[A,B]
|
2010-06-22 03:22:11 +02:00
|
|
|
/** Removes all pairs (_1, _2) from this relation. */
|
2010-06-25 00:09:07 +02:00
|
|
|
def -(_1: A): Relation[A,B]
|
2010-06-22 03:22:11 +02:00
|
|
|
/** Removes `pair` from this relation. */
|
2010-06-25 00:09:07 +02:00
|
|
|
def -(pair: (A,B)): Relation[A,B]
|
2010-06-22 03:22:11 +02:00
|
|
|
/** Returns the set of all _1s such that (_1, _2) is in this relation. */
|
2010-06-25 00:09:07 +02:00
|
|
|
def _1s: collection.Set[A]
|
2010-06-22 03:22:11 +02:00
|
|
|
/** Returns the set of all _2s such that (_1, _2) is in this relation. */
|
2010-06-25 00:09:07 +02:00
|
|
|
def _2s: collection.Set[B]
|
2010-06-22 03:22:11 +02:00
|
|
|
|
|
|
|
|
/** Returns all pairs in this relation.*/
|
2010-06-25 00:09:07 +02:00
|
|
|
def all: Traversable[(A,B)]
|
2010-06-22 03:22:11 +02:00
|
|
|
|
2010-06-25 00:09:07 +02:00
|
|
|
def forwardMap: Map[A, Set[B]]
|
|
|
|
|
def reverseMap: Map[B, Set[A]]
|
2010-06-22 03:22:11 +02:00
|
|
|
}
|
2010-06-25 00:09:07 +02:00
|
|
|
private final class MRelation[A,B](fwd: Map[A, Set[B]], rev: Map[B, Set[A]]) extends Relation[A,B]
|
2010-06-22 03:22:11 +02:00
|
|
|
{
|
2010-06-25 00:09:07 +02:00
|
|
|
type M[X,Y] = Map[X, Set[Y]]
|
2010-06-22 03:22:11 +02:00
|
|
|
|
|
|
|
|
def forwardMap = fwd
|
|
|
|
|
def reverseMap = rev
|
|
|
|
|
|
2010-06-25 00:09:07 +02:00
|
|
|
def forward(t: A) = get(fwd, t)
|
|
|
|
|
def reverse(t: B) = get(rev, t)
|
2010-06-22 03:22:11 +02:00
|
|
|
|
|
|
|
|
def _1s = fwd.keySet
|
|
|
|
|
def _2s = rev.keySet
|
|
|
|
|
|
2010-06-25 00:09:07 +02:00
|
|
|
def all: Traversable[(A,B)] = fwd.iterator.flatMap { case (a, bs) => bs.iterator.map( b => (a,b) ) }.toTraversable
|
2010-06-22 03:22:11 +02:00
|
|
|
|
2010-06-25 00:09:07 +02:00
|
|
|
def +(pair: (A,B)) = this + (pair._1, Set(pair._2))
|
|
|
|
|
def +(from: A, to: B) = this + (from, Set(to))
|
|
|
|
|
def +(from: A, to: Iterable[B]) =
|
2010-06-22 03:22:11 +02:00
|
|
|
new MRelation( add(fwd, from, to), (rev /: to) { (map, t) => add(map, t, Seq(from)) })
|
|
|
|
|
|
2010-06-25 00:09:07 +02:00
|
|
|
def ++(rs: Iterable[(A,B)]) = ((this: Relation[A,B]) /: rs) { _ + _ }
|
|
|
|
|
def ++(other: Relation[A,B]) = new MRelation[A,B]( combine(fwd, other.forwardMap), combine(rev, other.reverseMap) )
|
2010-06-22 03:22:11 +02:00
|
|
|
|
2010-06-25 00:09:07 +02:00
|
|
|
def --(ts: Iterable[A]): Relation[A,B] = ((this: Relation[A,B]) /: ts) { _ - _ }
|
|
|
|
|
def --(pairs: Traversable[(A,B)]): Relation[A,B] = ((this: Relation[A,B]) /: pairs) { _ - _ }
|
|
|
|
|
def -(pair: (A,B)): Relation[A,B] =
|
2010-06-22 03:22:11 +02:00
|
|
|
new MRelation( remove(fwd, pair._1, pair._2), remove(rev, pair._2, pair._1) )
|
2010-06-25 00:09:07 +02:00
|
|
|
def -(t: A): Relation[A,B] =
|
2010-06-22 03:22:11 +02:00
|
|
|
fwd.get(t) match {
|
|
|
|
|
case Some(rs) =>
|
|
|
|
|
val upRev = (rev /: rs) { (map, r) => remove(map, r, t) }
|
|
|
|
|
new MRelation(fwd - t, upRev)
|
|
|
|
|
case None => this
|
|
|
|
|
}
|
|
|
|
|
|
2010-06-25 00:09:07 +02:00
|
|
|
private def remove[X,Y](map: M[X,Y], from: X, to: Y): M[X,Y] =
|
2010-06-22 03:22:11 +02:00
|
|
|
map.get(from) match {
|
|
|
|
|
case Some(tos) =>
|
|
|
|
|
val newSet = tos - to
|
|
|
|
|
if(newSet.isEmpty) map - from else map.updated(from, newSet)
|
|
|
|
|
case None => map
|
|
|
|
|
}
|
|
|
|
|
|
2010-06-25 00:09:07 +02:00
|
|
|
private def combine[X,Y](a: M[X,Y], b: M[X,Y]): M[X,Y] =
|
2010-06-22 03:22:11 +02:00
|
|
|
(a /: b) { (map, mapping) => add(map, mapping._1, mapping._2) }
|
|
|
|
|
|
2010-06-25 00:09:07 +02:00
|
|
|
private[this] def add[X,Y](map: M[X,Y], from: X, to: Iterable[Y]): M[X,Y] =
|
2010-06-22 03:22:11 +02:00
|
|
|
map.updated(from, get(map, from) ++ to)
|
|
|
|
|
|
2010-06-25 00:09:07 +02:00
|
|
|
private[this] def get[X,Y](map: M[X,Y], t: X): Set[Y] = map.getOrElse(t, Set.empty[Y])
|
2010-06-22 03:22:11 +02:00
|
|
|
|
|
|
|
|
override def toString = all.mkString("Relation [", ", ", "]")
|
|
|
|
|
}
|