diff options
author | Li Haoyi <haoyi.sg@gmail.com> | 2018-01-13 13:00:21 -0800 |
---|---|---|
committer | Li Haoyi <haoyi.sg@gmail.com> | 2018-01-13 14:37:24 -0800 |
commit | 57501fca3b6c2c64d32744e6d534b9de3a6674f6 (patch) | |
tree | 912a22fb405c971f4a4b75d737a35e522d6a420e /core/src/main/scala/mill/util/OSet.scala | |
parent | 91102940a0bcdd7efc1d13e43510c4a0e406ead2 (diff) | |
download | mill-57501fca3b6c2c64d32744e6d534b9de3a6674f6.tar.gz mill-57501fca3b6c2c64d32744e6d534b9de3a6674f6.tar.bz2 mill-57501fca3b6c2c64d32744e6d534b9de3a6674f6.zip |
Migrate most classpath-related code onto `Loose.OSet` abstraction, to enforce deduplication
Diffstat (limited to 'core/src/main/scala/mill/util/OSet.scala')
-rw-r--r-- | core/src/main/scala/mill/util/OSet.scala | 192 |
1 files changed, 99 insertions, 93 deletions
diff --git a/core/src/main/scala/mill/util/OSet.scala b/core/src/main/scala/mill/util/OSet.scala index 52b47cde..a4fcc406 100644 --- a/core/src/main/scala/mill/util/OSet.scala +++ b/core/src/main/scala/mill/util/OSet.scala @@ -3,108 +3,114 @@ package mill.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: Iterator[V] - def indexed: 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 withFilter(f: V => Boolean): OSet[V] - def collect[T](f: PartialFunction[V, T]): OSet[T] - def zipWithIndex: OSet[(V, Int)] - def reverse: OSet[V] - def zip[T](other: OSet[T]): OSet[(V, T)] -} - -object OSet{ - implicit def jsonFormat[T: upickle.default.ReadWriter]: upickle.default.ReadWriter[OSet[T]] = - upickle.default.ReadWriter[OSet[T]] ( - oset => upickle.default.writeJs(oset.toList), - {case json => OSet.from(upickle.default.readJs[Seq[T]](json))} - ) - 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 +object Strict extends OSetWrapper(true) +object Loose extends OSetWrapper(false) +sealed class OSetWrapper(strictUniqueness: Boolean){ + /** + * 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: Iterator[V] + def indexed: 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 withFilter(f: V => Boolean): OSet[V] + def collect[T](f: PartialFunction[V, T]): OSet[T] + def zipWithIndex: OSet[(V, Int)] + def reverse: OSet[V] + def zip[T](other: OSet[T]): OSet[(V, T)] + def ++[T >: V](other: TraversableOnce[T]): OSet[T] } + object OSet{ + def empty[V]: OSet[V] = new OSet.Mutable[V] + implicit def jsonFormat[T: upickle.default.ReadWriter]: upickle.default.ReadWriter[OSet[T]] = + upickle.default.ReadWriter[OSet[T]] ( + oset => upickle.default.writeJs(oset.toList), + {case json => OSet.from(upickle.default.readJs[Seq[T]](json))} + ) + 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) + class Mutable[V]() extends OSet[V]{ - }else { - throw new Exception("Duplicated item inserted into OrderedSet: " + v) - } - def appendAll(vs: Seq[V]) = vs.foreach(append) - def items = set0.iterator - def indexed: IndexedSeq[V] = items.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 withFilter(f: V => Boolean): OSet[V] = filter(f) + 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) - def collect[T](f: PartialFunction[V, T]) = this.filter(f.isDefinedAt).map(x => f(x)) + }else if (strictUniqueness){ + throw new Exception("Duplicated item inserted into OrderedSet: " + v) + } + def appendAll(vs: Seq[V]) = vs.foreach(append) + def items = set0.iterator + def indexed: IndexedSeq[V] = items.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 withFilter(f: V => Boolean): OSet[V] = filter(f) - def zipWithIndex = { - var i = 0 - this.map{ x => - i += 1 - (x, i-1) + 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(indexed.reverseIterator) - - def zip[T](other: OSet[T]) = OSet.from(items.zip(other.items)) - - // 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.toTraversable - - override def hashCode() = items.hashCode() - override def equals(other: Any) = other match{ - case s: OSet[_] => items.sameElements(s.items) - case _ => super.equals(other) + def reverse = OSet.from(indexed.reverseIterator) + + def zip[T](other: OSet[T]) = OSet.from(items.zip(other.items)) + def ++[T >: V](other: TraversableOnce[T]) = OSet.from(items ++ other) + + // 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.toTraversable + + override def hashCode() = items.map(_.hashCode()).sum + override def equals(other: Any) = other match{ + case s: OSet[_] => items.sameElements(s.items) + case _ => super.equals(other) + } + override def toString = items.mkString("OSet(", ", ", ")") } - override def toString = items.mkString("OSet(", ", ", ")") } } |