summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/main/scala/forge/Evaluator.scala23
-rw-r--r--src/main/scala/forge/Target.scala1
-rw-r--r--src/main/scala/forge/Util.scala151
-rw-r--r--src/main/scala/forge/util/MultiBiMap.scala42
-rw-r--r--src/main/scala/forge/util/OSet.scala97
-rw-r--r--src/main/scala/forge/util/PathRef.scala26
-rw-r--r--src/test/scala/forge/EvaluationTests.scala1
-rw-r--r--src/test/scala/forge/GraphTests.scala1
-rw-r--r--src/test/scala/forge/Main.scala2
-rw-r--r--src/test/scala/forge/TestUtil.scala1
10 files changed, 178 insertions, 167 deletions
diff --git a/src/main/scala/forge/Evaluator.scala b/src/main/scala/forge/Evaluator.scala
index 888f6639..e6366f42 100644
--- a/src/main/scala/forge/Evaluator.scala
+++ b/src/main/scala/forge/Evaluator.scala
@@ -1,10 +1,11 @@
package forge
-import play.api.libs.json.{JsValue, Json, Reads}
+import play.api.libs.json.{JsValue, Json}
import scala.collection.mutable
import ammonite.ops._
+import forge.util.{MultiBiMap, OSet}
class Evaluator(workspacePath: Path,
labeling: Map[Target[_], Seq[String]]){
@@ -16,7 +17,7 @@ class Evaluator(workspacePath: Path,
labeling
)
- val evaluated = new MutableOSet[Target[_]]
+ val evaluated = new OSet.Mutable[Target[_]]
val results = mutable.LinkedHashMap.empty[Target[_], Any]
for (groupIndex <- sortedGroups.keys()){
@@ -52,7 +53,7 @@ class Evaluator(workspacePath: Path,
val metadataPath = targetDestPath / up / (targetDestPath.last + ".forge.json")
val cached = for{
- json <- util.Try(Json.parse(read.getInputStream(metadataPath))).toOption
+ json <- scala.util.Try(Json.parse(read.getInputStream(metadataPath))).toOption
(cachedHash, terminalResults) <- Json.fromJson[(Int, Seq[JsValue])](json).asOpt
if cachedHash == inputsHash
} yield terminalResults
@@ -126,7 +127,7 @@ object Evaluator{
def groupAroundNamedTargets(topoSortedTargets: TopoSorted,
labeling: Map[Target[_], Seq[String]]): MultiBiMap[Int, Target[_]] = {
- val grouping = new MutableMultiBiMap[Int, Target[_]]()
+ val grouping = new MultiBiMap.Mutable[Int, Target[_]]()
var groupCount = 0
@@ -151,7 +152,7 @@ object Evaluator{
}
val targetOrdering = topoSortedTargets.values.items.zipWithIndex.toMap
- val output = new MutableMultiBiMap[Int, Target[_]]
+ val output = new MultiBiMap.Mutable[Int, Target[_]]
// Sort groups amongst themselves, and sort the contents of each group
// before aggregating it into the final output
@@ -161,22 +162,12 @@ object Evaluator{
output
}
- def checkTopological(targets: OSet[Target[_]]) = {
- val seen = mutable.Set.empty[Target[_]]
- for(t <- targets.items.reverseIterator){
- seen.add(t)
- for(upstream <- t.inputs){
- assert(!seen(upstream))
- }
- }
- }
-
/**
* Takes the given targets, finds all the targets they transitively depend
* on, and sort them topologically. Fails if there are dependency cycles
*/
def topoSortedTransitiveTargets(sourceTargets: OSet[Target[_]]): TopoSorted = {
- val transitiveTargets = new MutableOSet[Target[_]]
+ val transitiveTargets = new OSet.Mutable[Target[_]]
def rec(t: Target[_]): Unit = {
if (transitiveTargets.contains(t)) () // do nothing
else {
diff --git a/src/main/scala/forge/Target.scala b/src/main/scala/forge/Target.scala
index fe975638..3b4ba2a8 100644
--- a/src/main/scala/forge/Target.scala
+++ b/src/main/scala/forge/Target.scala
@@ -2,6 +2,7 @@ package forge
import ammonite.ops.{ls, mkdir}
+import forge.util.PathRef
import play.api.libs.json.{Format, JsValue, Json}
abstract class Target[T](implicit formatter: Format[T]) extends Target.Ops[T]{
/**
diff --git a/src/main/scala/forge/Util.scala b/src/main/scala/forge/Util.scala
deleted file mode 100644
index 9a225f8b..00000000
--- a/src/main/scala/forge/Util.scala
+++ /dev/null
@@ -1,151 +0,0 @@
-package forge
-
-
-import ammonite.ops.ls
-import play.api.libs.json.{Format, Json}
-
-import scala.collection.mutable
-
-object PathRef{
- implicit def jsonFormatter: Format[PathRef] = Json.format
-}
-case class PathRef(path: ammonite.ops.Path){
- override def hashCode() = {
- if (!path.isDir) path.hashCode() + path.mtime.toMillis.toInt
- else ls.rec.iter(path)
- .filter(_.isFile)
- .map(x => x.toString.hashCode + x.mtime.toMillis)
- .sum
- .toInt
- }
-}
-
-
-trait MultiBiMap[K, V]{
- def containsValue(v: V): Boolean
- def lookupKey(k: K): OSet[V]
- def lookupValue(v: V): K
- def lookupValueOpt(v: V): Option[K]
- def add(k: K, v: V): Unit
- def removeAll(k: K): OSet[V]
- def addAll(k: K, vs: TraversableOnce[V]): Unit
- def keys(): Iterator[K]
- def values(): Iterator[OSet[V]]
-}
-class MutableMultiBiMap[K, V]() extends MultiBiMap[K, V]{
- private[this] val valueToKey = mutable.LinkedHashMap.empty[V, K]
- private[this] val keyToValues = mutable.LinkedHashMap.empty[K, MutableOSet[V]]
- def containsValue(v: V) = valueToKey.contains(v)
- def lookupKey(k: K) = keyToValues(k)
- def lookupValue(v: V) = valueToKey(v)
- def lookupValueOpt(v: V) = valueToKey.get(v)
- def add(k: K, v: V): Unit = {
- valueToKey(v) = k
- keyToValues.getOrElseUpdate(k, new MutableOSet[V]()).append(v)
- }
- def removeAll(k: K): OSet[V] = keyToValues.get(k) match {
- case None => OSet()
- case Some(vs) =>
- vs.foreach(valueToKey.remove)
-
- keyToValues.remove(k)
- vs
- }
- def addAll(k: K, vs: TraversableOnce[V]): Unit = vs.foreach(this.add(k, _))
-
- def keys() = keyToValues.keysIterator
-
- def values() = keyToValues.valuesIterator
-}
-
-/**
- * A collection with enforced uniqueness, fast contains and deterministic
- * ordering. Raises an exception if a duplicate is found; call
- * `toSeq.distinct` if you explicitly want to make it swallow duplicates
- */
-trait OSet[V] extends TraversableOnce[V]{
- def contains(v: V): Boolean
- def items: IndexedSeq[V]
- def flatMap[T](f: V => TraversableOnce[T]): OSet[T]
- def map[T](f: V => T): OSet[T]
- def filter(f: V => Boolean): OSet[V]
- def collect[T](f: PartialFunction[V, T]): OSet[T]
- def zipWithIndex: OSet[(V, Int)]
- def reverse: OSet[V]
-}
-
-object OSet{
- def apply[V](items: V*) = from(items)
-
- def from[V](items: TraversableOnce[V]): OSet[V] = {
- val set = new MutableOSet[V]()
- items.foreach(set.append)
- set
- }
-}
-
-class MutableOSet[V]() extends OSet[V]{
-
- private[this] val set0 = mutable.LinkedHashSet.empty[V]
- def contains(v: V) = set0.contains(v)
- def append(v: V) = if (!contains(v)){
- set0.add(v)
-
- }else {
- throw new Exception("Duplicated item inserted into OrderedSet: " + v)
- }
- def appendAll(vs: Seq[V]) = vs.foreach(append)
- def items: IndexedSeq[V] = set0.toIndexedSeq
- def set: collection.Set[V] = set0
-
- def map[T](f: V => T): OSet[T] = {
- val output = new MutableOSet[T]
- for(i <- items) output.append(f(i))
- output
- }
- def flatMap[T](f: V => TraversableOnce[T]): OSet[T] = {
- val output = new MutableOSet[T]
- for(i <- items) for(i0 <- f(i)) output.append(i0)
- output
- }
- def filter(f: V => Boolean): OSet[V] = {
- val output = new MutableOSet[V]
- for(i <- items) if (f(i)) output.append(i)
- output
- }
-
- def collect[T](f: PartialFunction[V, T]) = this.filter(f.isDefinedAt).map(x => f(x))
-
- def zipWithIndex = {
- var i = 0
- this.map{ x =>
- i += 1
- (x, i-1)
- }
- }
-
- def reverse = OSet.from(items.reverseIterator)
-
- // Members declared in scala.collection.GenTraversableOnce
- def isTraversableAgain: Boolean = items.isTraversableAgain
- def toIterator: Iterator[V] = items.toIterator
- def toStream: Stream[V] = items.toStream
-
- // Members declared in scala.collection.TraversableOnce
- def copyToArray[B >: V](xs: Array[B],start: Int,len: Int): Unit = items.copyToArray(xs, start, len)
- def exists(p: V => Boolean): Boolean = items.exists(p)
- def find(p: V => Boolean): Option[V] = items.find(p)
- def forall(p: V => Boolean): Boolean = items.forall(p)
- def foreach[U](f: V => U): Unit = items.foreach(f)
- def hasDefiniteSize: Boolean = items.hasDefiniteSize
- def isEmpty: Boolean = items.isEmpty
- def seq: scala.collection.TraversableOnce[V] = items
- def toTraversable: Traversable[V] = items
-
- override def hashCode() = items.hashCode()
- override def equals(other: Any) = other match{
- case s: OSet[_] => items.equals(s.items)
- case _ => super.equals(other)
- }
- override def toString = items.mkString("OSet(", ", ", ")")
-} \ No newline at end of file
diff --git a/src/main/scala/forge/util/MultiBiMap.scala b/src/main/scala/forge/util/MultiBiMap.scala
new file mode 100644
index 00000000..3eff686e
--- /dev/null
+++ b/src/main/scala/forge/util/MultiBiMap.scala
@@ -0,0 +1,42 @@
+package forge.util
+
+import scala.collection.mutable
+
+trait MultiBiMap[K, V]{
+ def containsValue(v: V): Boolean
+ def lookupKey(k: K): OSet[V]
+ def lookupValue(v: V): K
+ def lookupValueOpt(v: V): Option[K]
+ def add(k: K, v: V): Unit
+ def removeAll(k: K): OSet[V]
+ def addAll(k: K, vs: TraversableOnce[V]): Unit
+ def keys(): Iterator[K]
+ def values(): Iterator[OSet[V]]
+}
+object MultiBiMap{
+ class Mutable[K, V]() extends MultiBiMap[K, V]{
+ private[this] val valueToKey = mutable.LinkedHashMap.empty[V, K]
+ private[this] val keyToValues = mutable.LinkedHashMap.empty[K, OSet.Mutable[V]]
+ def containsValue(v: V) = valueToKey.contains(v)
+ def lookupKey(k: K) = keyToValues(k)
+ def lookupValue(v: V) = valueToKey(v)
+ def lookupValueOpt(v: V) = valueToKey.get(v)
+ def add(k: K, v: V): Unit = {
+ valueToKey(v) = k
+ keyToValues.getOrElseUpdate(k, new OSet.Mutable[V]()).append(v)
+ }
+ def removeAll(k: K): OSet[V] = keyToValues.get(k) match {
+ case None => OSet()
+ case Some(vs) =>
+ vs.foreach(valueToKey.remove)
+
+ keyToValues.remove(k)
+ vs
+ }
+ def addAll(k: K, vs: TraversableOnce[V]): Unit = vs.foreach(this.add(k, _))
+
+ def keys() = keyToValues.keysIterator
+
+ def values() = keyToValues.valuesIterator
+ }
+}
diff --git a/src/main/scala/forge/util/OSet.scala b/src/main/scala/forge/util/OSet.scala
new file mode 100644
index 00000000..34e297bd
--- /dev/null
+++ b/src/main/scala/forge/util/OSet.scala
@@ -0,0 +1,97 @@
+package forge.util
+
+
+import scala.collection.mutable
+
+/**
+ * A collection with enforced uniqueness, fast contains and deterministic
+ * ordering. Raises an exception if a duplicate is found; call
+ * `toSeq.distinct` if you explicitly want to make it swallow duplicates
+ */
+trait OSet[V] extends TraversableOnce[V]{
+ def contains(v: V): Boolean
+ def items: IndexedSeq[V]
+ def flatMap[T](f: V => TraversableOnce[T]): OSet[T]
+ def map[T](f: V => T): OSet[T]
+ def filter(f: V => Boolean): OSet[V]
+ def collect[T](f: PartialFunction[V, T]): OSet[T]
+ def zipWithIndex: OSet[(V, Int)]
+ def reverse: OSet[V]
+}
+
+object OSet{
+ def apply[V](items: V*) = from(items)
+
+ def from[V](items: TraversableOnce[V]): OSet[V] = {
+ val set = new OSet.Mutable[V]()
+ items.foreach(set.append)
+ set
+ }
+
+
+ class Mutable[V]() extends OSet[V]{
+
+ private[this] val set0 = mutable.LinkedHashSet.empty[V]
+ def contains(v: V) = set0.contains(v)
+ def append(v: V) = if (!contains(v)){
+ set0.add(v)
+
+ }else {
+ throw new Exception("Duplicated item inserted into OrderedSet: " + v)
+ }
+ def appendAll(vs: Seq[V]) = vs.foreach(append)
+ def items: IndexedSeq[V] = set0.toIndexedSeq
+ def set: collection.Set[V] = set0
+
+ def map[T](f: V => T): OSet[T] = {
+ val output = new OSet.Mutable[T]
+ for(i <- items) output.append(f(i))
+ output
+ }
+ def flatMap[T](f: V => TraversableOnce[T]): OSet[T] = {
+ val output = new OSet.Mutable[T]
+ for(i <- items) for(i0 <- f(i)) output.append(i0)
+ output
+ }
+ def filter(f: V => Boolean): OSet[V] = {
+ val output = new OSet.Mutable[V]
+ for(i <- items) if (f(i)) output.append(i)
+ output
+ }
+
+ def collect[T](f: PartialFunction[V, T]) = this.filter(f.isDefinedAt).map(x => f(x))
+
+ def zipWithIndex = {
+ var i = 0
+ this.map{ x =>
+ i += 1
+ (x, i-1)
+ }
+ }
+
+ def reverse = OSet.from(items.reverseIterator)
+
+ // Members declared in scala.collection.GenTraversableOnce
+ def isTraversableAgain: Boolean = items.isTraversableAgain
+ def toIterator: Iterator[V] = items.toIterator
+ def toStream: Stream[V] = items.toStream
+
+ // Members declared in scala.collection.TraversableOnce
+ def copyToArray[B >: V](xs: Array[B],start: Int,len: Int): Unit = items.copyToArray(xs, start, len)
+ def exists(p: V => Boolean): Boolean = items.exists(p)
+ def find(p: V => Boolean): Option[V] = items.find(p)
+ def forall(p: V => Boolean): Boolean = items.forall(p)
+ def foreach[U](f: V => U): Unit = items.foreach(f)
+ def hasDefiniteSize: Boolean = items.hasDefiniteSize
+ def isEmpty: Boolean = items.isEmpty
+ def seq: scala.collection.TraversableOnce[V] = items
+ def toTraversable: Traversable[V] = items
+
+ override def hashCode() = items.hashCode()
+ override def equals(other: Any) = other match{
+ case s: OSet[_] => items.equals(s.items)
+ case _ => super.equals(other)
+ }
+ override def toString = items.mkString("OSet(", ", ", ")")
+ }
+}
diff --git a/src/main/scala/forge/util/PathRef.scala b/src/main/scala/forge/util/PathRef.scala
new file mode 100644
index 00000000..3621d0b6
--- /dev/null
+++ b/src/main/scala/forge/util/PathRef.scala
@@ -0,0 +1,26 @@
+package forge
+package util
+
+import ammonite.ops.ls
+import play.api.libs.json.{Format, Json}
+
+
+/**
+ * A wrapper around `ammonite.ops.Path` that calculates it's hashcode based
+ * on the contents of the filesystem underneath it. Used to ensure filesystem
+ * changes can bust caches which are keyed off hashcodes.
+ */
+case class PathRef(path: ammonite.ops.Path){
+ override def hashCode() = {
+ if (!path.isDir) path.hashCode() + path.mtime.toMillis.toInt
+ else ls.rec.iter(path)
+ .filter(_.isFile)
+ .map(x => x.toString.hashCode + x.mtime.toMillis)
+ .sum
+ .toInt
+ }
+}
+
+object PathRef{
+ implicit def jsonFormatter: Format[PathRef] = Json.format
+} \ No newline at end of file
diff --git a/src/test/scala/forge/EvaluationTests.scala b/src/test/scala/forge/EvaluationTests.scala
index 2c18be2f..313ceaaa 100644
--- a/src/test/scala/forge/EvaluationTests.scala
+++ b/src/test/scala/forge/EvaluationTests.scala
@@ -1,6 +1,7 @@
package forge
+import forge.util.OSet
import utest._
import utest.framework.TestPath
diff --git a/src/test/scala/forge/GraphTests.scala b/src/test/scala/forge/GraphTests.scala
index 5cfea75d..d197fb5f 100644
--- a/src/test/scala/forge/GraphTests.scala
+++ b/src/test/scala/forge/GraphTests.scala
@@ -2,6 +2,7 @@ package forge
import utest._
import Target.test
+import forge.util.OSet
object GraphTests extends TestSuite{
diff --git a/src/test/scala/forge/Main.scala b/src/test/scala/forge/Main.scala
index 2ef6083b..6f281f54 100644
--- a/src/test/scala/forge/Main.scala
+++ b/src/test/scala/forge/Main.scala
@@ -1,8 +1,10 @@
package forge
import java.io.FileOutputStream
import java.util.jar.JarEntry
+
import collection.JavaConverters._
import ammonite.ops._
+import forge.util.{OSet, PathRef}
object Main{
val sourceRoot = Target.path(pwd / 'src / 'test / 'resources / 'example / 'src)
val resourceRoot = Target.path(pwd / 'src / 'test / 'resources / 'example / 'resources)
diff --git a/src/test/scala/forge/TestUtil.scala b/src/test/scala/forge/TestUtil.scala
index 8d944c65..8405c87c 100644
--- a/src/test/scala/forge/TestUtil.scala
+++ b/src/test/scala/forge/TestUtil.scala
@@ -1,5 +1,6 @@
package forge
+import forge.util.OSet
import utest.assert
import scala.collection.mutable