minor updates to utilities

This commit is contained in:
Mark Harrah 2010-10-30 11:54:43 -04:00
parent f8439d2d64
commit 0846ffd02b
3 changed files with 38 additions and 25 deletions

View File

@ -3,12 +3,40 @@
*/
package sbt
import Relation._
object Relation
{
/** Constructs a new immutable, finite relation that is initially empty. */
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)
def reconstruct[A,B](forward: Map[A, Set[B]]): Relation[A,B] =
{
val reversePairs = for( (a,bs) <- forward.view; b <- bs.view) yield (b, a)
val reverse = (Map.empty[B,Set[A]] /: reversePairs) { case (m, (b, a)) => add(m, b, a :: Nil) }
make(forward, reverse)
}
private[sbt] def remove[X,Y](map: M[X,Y], from: X, to: Y): M[X,Y] =
map.get(from) match {
case Some(tos) =>
val newSet = tos - to
if(newSet.isEmpty) map - from else map.updated(from, newSet)
case None => map
}
private[sbt] def combine[X,Y](a: M[X,Y], b: M[X,Y]): M[X,Y] =
(a /: b) { (map, mapping) => add(map, mapping._1, mapping._2) }
private[sbt] def add[X,Y](map: M[X,Y], from: X, to: Iterable[Y]): M[X,Y] =
map.updated(from, get(map, from) ++ to)
private[sbt] def get[X,Y](map: M[X,Y], t: X): Set[Y] = map.getOrElse(t, Set.empty[Y])
private[sbt] type M[X,Y] = Map[X, Set[Y]]
}
/** 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]
{
@ -49,8 +77,6 @@ trait Relation[A,B]
}
private final class MRelation[A,B](fwd: Map[A, Set[B]], rev: Map[B, Set[A]]) extends Relation[A,B]
{
type M[X,Y] = Map[X, Set[Y]]
def forwardMap = fwd
def reverseMap = rev
@ -65,9 +91,9 @@ private final class MRelation[A,B](fwd: Map[A, Set[B]], rev: Map[B, Set[A]]) ext
def all: Traversable[(A,B)] = fwd.iterator.flatMap { case (a, bs) => bs.iterator.map( b => (a,b) ) }.toTraversable
def +(pair: (A,B)) = this + (pair._1, Set(pair._2))
def +(from: A, to: B) = this + (from, Set(to))
def +(from: A, to: B) = this + (from, to :: Nil)
def +(from: A, to: Iterable[B]) =
new MRelation( add(fwd, from, to), (rev /: to) { (map, t) => add(map, t, Seq(from)) })
new MRelation( add(fwd, from, to), (rev /: to) { (map, t) => add(map, t, from :: Nil) })
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) )
@ -84,21 +110,5 @@ private final class MRelation[A,B](fwd: Map[A, Set[B]], rev: Map[B, Set[A]]) ext
case None => this
}
private def remove[X,Y](map: M[X,Y], from: X, to: Y): M[X,Y] =
map.get(from) match {
case Some(tos) =>
val newSet = tos - to
if(newSet.isEmpty) map - from else map.updated(from, newSet)
case None => map
}
private def combine[X,Y](a: M[X,Y], b: M[X,Y]): M[X,Y] =
(a /: b) { (map, mapping) => add(map, mapping._1, mapping._2) }
private[this] def add[X,Y](map: M[X,Y], from: X, to: Iterable[Y]): M[X,Y] =
map.updated(from, get(map, from) ++ to)
private[this] def get[X,Y](map: M[X,Y], t: X): Set[Y] = map.getOrElse(t, Set.empty[Y])
override def toString = all.map { case (a,b) => a + " -> " + b }.mkString("Relation [", ", ", "]")
}

View File

@ -6,9 +6,9 @@ package sbt
trait TypeFunctions
{
type Id[X] = X
trait Const[A] { type Apply[B] = A }
trait Compose[A[_], B[_]] { type Apply[T] = A[B[T]] }
trait P1of2[M[_,_], A] { type Apply[B] = M[A,B]; type Flip[B] = M[B, A] }
sealed trait Const[A] { type Apply[B] = A }
sealed trait Compose[A[_], B[_]] { type Apply[T] = A[B[T]] }
sealed trait P1of2[M[_,_], A] { type Apply[B] = M[A,B]; type Flip[B] = M[B, A] }
final val left = new (Id ~> P1of2[Left, Nothing]#Flip) { def apply[T](t: T) = Left(t) }
final val right = new (Id ~> P1of2[Right, Nothing]#Apply) { def apply[T](t: T) = Right(t) }

View File

@ -74,6 +74,8 @@ object Using
}
private def closeCloseable[T <: Closeable]: T => Unit = _.close()
def bufferedOutputStream = wrap( (out: OutputStream) => new BufferedOutputStream(out) )
def bufferedInputStream = wrap( (in: InputStream) => new BufferedInputStream(in) )
def fileOutputStream(append: Boolean = false) = file(f => new BufferedOutputStream(new FileOutputStream(f, append)))
def fileInputStream = file(f => new BufferedInputStream(new FileInputStream(f)))
def urlInputStream = resource( (u: URL) => translate("Error opening " + u + ": ")(u.openStream))
@ -85,9 +87,10 @@ object Using
def jarFile(verify: Boolean) = file(f => new JarFile(f, verify), (_: JarFile).close())
def zipFile = file(f => new ZipFile(f), (_: ZipFile).close())
def streamReader = wrap{ (_: (InputStream, Charset)) match { case (in, charset) => new InputStreamReader(in, charset) } }
def gzipInputStream = wrap( (in: InputStream) => new GZIPInputStream(in) )
def gzipInputStream = wrap( (in: InputStream) => new GZIPInputStream(in, 8192) )
def zipInputStream = wrap( (in: InputStream) => new ZipInputStream(in))
def gzipOutputStream = wrap((out: OutputStream) => new GZIPOutputStream(out), (_: GZIPOutputStream).finish())
def zipOutputStream = wrap( (out: OutputStream) => new ZipOutputStream(out))
def gzipOutputStream = wrap((out: OutputStream) => new GZIPOutputStream(out, 8192), (_: GZIPOutputStream).finish())
def jarOutputStream = wrap( (out: OutputStream) => new JarOutputStream(out))
def jarInputStream = wrap( (in: InputStream) => new JarInputStream(in))
def zipEntry(zip: ZipFile) = resource( (entry: ZipEntry) =>