From 0846ffd02baeeadac4c45ed0f21bc173e9a990d1 Mon Sep 17 00:00:00 2001 From: Mark Harrah Date: Sat, 30 Oct 2010 11:54:43 -0400 Subject: [PATCH] minor updates to utilities --- util/collection/Relation.scala | 50 +++++++++++++++++------------ util/collection/TypeFunctions.scala | 6 ++-- util/io/Using.scala | 7 ++-- 3 files changed, 38 insertions(+), 25 deletions(-) diff --git a/util/collection/Relation.scala b/util/collection/Relation.scala index a282bf7e2..b305bb47c 100644 --- a/util/collection/Relation.scala +++ b/util/collection/Relation.scala @@ -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 [", ", ", "]") } \ No newline at end of file diff --git a/util/collection/TypeFunctions.scala b/util/collection/TypeFunctions.scala index 92a5fb4b7..ca173f9bc 100644 --- a/util/collection/TypeFunctions.scala +++ b/util/collection/TypeFunctions.scala @@ -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) } diff --git a/util/io/Using.scala b/util/io/Using.scala index 731c8ca8d..988536408 100644 --- a/util/io/Using.scala +++ b/util/io/Using.scala @@ -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) =>