Analysis.groupBy implementation.

This commit is contained in:
Benjy 2012-10-10 18:21:44 -07:00 committed by Mark Harrah
parent 9bf5405621
commit 657d842238
6 changed files with 83 additions and 6 deletions

View File

@ -24,10 +24,11 @@ trait APIs
def markInternalSource(src: File, api: Source): APIs
def markExternalAPI(ext: String, api: Source): APIs
def removeInternal(remove: Iterable[File]): APIs
def filterExt(keep: String => Boolean): APIs
def groupBy[K](internal: (File) => K, keepExternal: Map[K, String => Boolean]): Map[K, APIs]
def internal: Map[File, Source]
def external: Map[String, Source]
}
@ -58,6 +59,9 @@ private class MAPIs(val internal: Map[File, Source], val external: Map[String, S
def removeInternal(remove: Iterable[File]): APIs = new MAPIs(internal -- remove, external)
def filterExt(keep: String => Boolean): APIs = new MAPIs(internal, external.filterKeys(keep))
def groupBy[K](f: (File) => K, keepExternal: Map[K, String => Boolean]): Map[K, APIs] =
internal.groupBy(item => f(item._1)) map { group => (group._1, new MAPIs(group._2, external).filterExt(keepExternal.getOrElse(group._1, _ => false)))}
def internalAPI(src: File) = getAPI(internal, src)
def externalAPI(ext: String) = getAPI(external, ext)

View File

@ -23,6 +23,8 @@ trait Analysis
def addExternalDep(src: File, dep: String, api: Source): Analysis
def addProduct(src: File, product: File, stamp: Stamp, name: String): Analysis
def groupBy[K](f: (File => K)): Map[K, Analysis]
override lazy val toString = Analysis.summary(this)
}
@ -61,7 +63,7 @@ private class MAnalysis(val stamps: Stamps, val apis: APIs, val relations: Relat
def -- (sources: Iterable[File]): Analysis =
{
val newRelations = relations -- sources
def keep[T](f: (Relations, T) => Set[_]): T => Boolean = file => !f(newRelations, file).isEmpty
def keep[T](f: (Relations, T) => Set[_]): T => Boolean = keepFor(newRelations)(f)
val newAPIs = apis.removeInternal(sources).filterExt( keep(_ usesExternal _) )
val newStamps = stamps.filter( keep(_ produced _), sources, keep(_ usesBinary _))
@ -81,4 +83,31 @@ private class MAnalysis(val stamps: Stamps, val apis: APIs, val relations: Relat
def addProduct(src: File, product: File, stamp: Stamp, name: String): Analysis =
copy( stamps.markProduct(product, stamp), apis, relations.addProduct(src, product, name), infos )
def groupBy[K](f: File => K): Map[K, Analysis] =
{
def outerJoin(stampsMap: Map[K, Stamps], apisMap: Map[K, APIs], relationsMap: Map[K, Relations], infosMap: Map[K, SourceInfos]): Map[K, Analysis] =
{
def kAnalysis(k: K): Analysis =
new MAnalysis(
stampsMap.getOrElse(k, Stamps.empty),
apisMap.getOrElse(k, APIs.empty),
relationsMap.getOrElse(k, Relations.empty),
infosMap.getOrElse(k, SourceInfos.empty)
)
val keys = (stampsMap.keySet ++ apisMap.keySet ++ relationsMap.keySet ++ infosMap.keySet).toList
Map( keys map( (k: K) => (k, kAnalysis(k)) ) :_*)
}
val relationsMap: Map[K, Relations] = relations.groupBy(f)
def keepMap[T](f: (Relations, T) => Set[_]): Map[K, T => Boolean] =
relationsMap map { item => (item._1, keepFor(item._2)(f) ) }
val keepExternal: Map[K, String => Boolean] = keepMap(_ usesExternal _)
val keepProduced: Map[K, File => Boolean] = keepMap(_ produced _)
val keepBinary: Map[K, File => Boolean] = keepMap(_ usesBinary _)
outerJoin(stamps.groupBy(keepProduced, f, keepBinary), apis.groupBy(f, keepExternal), relationsMap, infos.groupBy(f))
}
private def keepFor[T](newRelations: Relations)(f: (Relations, T) => Set[_]): T => Boolean = file => !f(newRelations, file).isEmpty
}

View File

@ -39,6 +39,7 @@ trait Relations
def ++ (o: Relations): Relations
def -- (sources: Iterable[File]): Relations
def groupBy[K](f: (File => K)): Map[K, Relations]
def srcProd: Relation[File, File]
def binaryDep: Relation[File, File]
@ -113,6 +114,25 @@ private class MRelations(val srcProd: Relation[File, File], val binaryDep: Relat
def -- (sources: Iterable[File]) =
new MRelations(srcProd -- sources, binaryDep -- sources, internalSrcDep -- sources, externalDep -- sources, classes -- sources)
def groupBy[K](f: File => K): Map[K, Relations] =
{
type MapRel[T] = Map[K, Relation[File, T]]
def outerJoin(srcProdMap: MapRel[File], binaryDepMap: MapRel[File], internalSrcDepMap: MapRel[File],
externalDepMap: MapRel[String], classesMap: MapRel[String]): Map[K, Relations] =
{
def kRelations(k: K): Relations = {
def get[T](m: Map[K, Relation[File, T]]) = m.getOrElse(k, Relation.empty)
new MRelations( get(srcProdMap), get(binaryDepMap), get(internalSrcDepMap), get(externalDepMap), get(classesMap) )
}
val keys = (srcProdMap.keySet ++ binaryDepMap.keySet ++ internalSrcDepMap.keySet ++ externalDepMap.keySet ++ classesMap.keySet).toList
Map( keys.map( (k: K) => (k, kRelations(k)) ) : _*)
}
def f1[B](item: (File, B)): K = f(item._1)
outerJoin(srcProd.groupBy(f1), binaryDep.groupBy(f1), internalSrcDep.groupBy(f1), externalDep.groupBy(f1), classes.groupBy(f1))
}
/** Making large Relations a little readable. */
private val userDir = sys.props("user.dir").stripSuffix("/") + "/"
private def nocwd(s: String) = s stripPrefix userDir

View File

@ -15,6 +15,7 @@ trait SourceInfos
def ++(o: SourceInfos): SourceInfos
def add(file: File, info: SourceInfo): SourceInfos
def --(files: Iterable[File]): SourceInfos
def groupBy[K](f: (File) => K): Map[K, SourceInfos]
def get(file: File): SourceInfo
def allInfos: Map[File, SourceInfo]
}
@ -31,6 +32,7 @@ private final class MSourceInfos(val allInfos: Map[File, SourceInfo]) extends So
{
def ++(o: SourceInfos) = new MSourceInfos(allInfos ++ o.allInfos)
def --(sources: Iterable[File]) = new MSourceInfos(allInfos -- sources)
def groupBy[K](f: (File) => K): Map[K, SourceInfos] = allInfos.groupBy(item => f(item._1)) map { group => (group._1, new MSourceInfos(group._2)) }
def add(file: File, info: SourceInfo) = new MSourceInfos(allInfos + ((file, info)))
def get(file:File) = allInfos.getOrElse(file, SourceInfos.emptyInfo)
}

View File

@ -38,6 +38,7 @@ trait Stamps extends ReadStamps
def filter(prod: File => Boolean, removeSources: Iterable[File], bin: File => Boolean): Stamps
def ++ (o: Stamps): Stamps
def groupBy[K](prod: Map[K, File => Boolean], sourcesGrouping: File => K, bin: Map[K, File => Boolean]): Map[K, Stamps]
}
sealed trait Stamp
@ -111,6 +112,22 @@ private class MStamps(val products: Map[File, Stamp], val sources: Map[File, Sta
def filter(prod: File => Boolean, removeSources: Iterable[File], bin: File => Boolean): Stamps =
new MStamps(products.filterKeys(prod), sources -- removeSources, binaries.filterKeys(bin), classNames.filterKeys(bin))
def groupBy[K](prod: Map[K, File => Boolean], sourcesGrouping: File => K, bin: Map[K, File => Boolean]): Map[K, Stamps] =
{
val sourcesMap: Map[K, Map[File, Stamp]] = sources.groupBy(item => sourcesGrouping(item._1))
val constFalse = (f: File) => false
def kStamps(k: K): Stamps = new MStamps(
products.filterKeys(prod.getOrElse(k, constFalse)),
sourcesMap.getOrElse(k, Map.empty[File,Stamp]),
binaries.filterKeys(bin.getOrElse(k, constFalse)),
classNames.filterKeys(bin.getOrElse(k, constFalse))
)
val keys = (prod.keySet ++ sourcesMap.keySet ++ bin.keySet).toList
Map( keys.map( (k: K) => (k, kStamps(k)) ) : _*)
}
def product(prod: File) = getStamp(products, prod)
def internalSource(src: File) = getStamp(sources, src)
def binary(bin: File) = getStamp(binaries, bin)

View File

@ -72,10 +72,13 @@ trait Relation[A,B]
def contains(a: A, b: B): Boolean
/** Returns a relation with only pairs (a,b) for which f(a,b) is true.*/
def filter(f: (A,B) => Boolean): Relation[A,B]
/** Partitions this relation into a map of relations according to some discriminator function. */
def groupBy[K](f: ((A,B)) => K): Map[K, Relation[A,B]]
/** Returns all pairs in this relation.*/
def all: Traversable[(A,B)]
def forwardMap: Map[A, Set[B]]
def reverseMap: Map[B, Set[A]]
}
@ -93,7 +96,7 @@ private final class MRelation[A,B](fwd: Map[A, Set[B]], rev: Map[B, Set[A]]) ext
def size = fwd.size
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, to :: Nil)
def +(from: A, to: Traversable[B]) =
@ -116,6 +119,8 @@ private final class MRelation[A,B](fwd: Map[A, Set[B]], rev: Map[B, Set[A]]) ext
def filter(f: (A,B) => Boolean): Relation[A,B] = Relation.empty[A,B] ++ all.filter(f.tupled)
def groupBy[K](f: ((A,B)) => K): Map[K, Relation[A,B]] = all.groupBy(f) mapValues { Relation.empty[A,B] ++ _ }
def contains(a: A, b: B): Boolean = forward(a)(b)
override def toString = all.map { case (a,b) => a + " -> " + b }.mkString("Relation [", ", ", "]")