
scala.collection.immutable.ListSet.scala Maven / Gradle / Ivy
/*
* Scala (https://www.scala-lang.org)
*
* Copyright EPFL and Lightbend, Inc.
*
* Licensed under Apache License 2.0
* (http://www.apache.org/licenses/LICENSE-2.0).
*
* See the NOTICE file distributed with this work for
* additional information regarding copyright ownership.
*/
package scala
package collection
package immutable
import generic._
import scala.annotation.tailrec
/**
* $factoryInfo
*
* Note that each element insertion takes O(n) time, which means that creating a list set with
* n elements will take O(n^2^) time. This makes the builder suitable only for a small number of
* elements.
*
* @since 1
* @define Coll ListSet
* @define coll list set
*/
object ListSet extends ImmutableSetFactory[ListSet] {
/**
* $setCanBuildFromInfo
*/
implicit def canBuildFrom[A]: CanBuildFrom[Coll, A, ListSet[A]] =
ReusableCBF.asInstanceOf[CanBuildFrom[Coll, A, ListSet[A]]]
private[this] val ReusableCBF = setCanBuildFrom[Any]
@SerialVersionUID(5010379588739277132L)
private object EmptyListSet extends ListSet[Any]
private[collection] def emptyInstance: ListSet[Any] = EmptyListSet
}
/**
* This class implements immutable sets using a list-based data structure. List set iterators and
* traversal methods visit elements in the order whey were first inserted.
*
* Elements are stored internally in reversed insertion order, which means the newest element is at
* the head of the list. As such, methods such as `head` and `tail` are O(n), while `last` and
* `init` are O(1). Other operations, such as inserting or removing entries, are also O(n), which
* makes this collection suitable only for a small number of elements.
*
* Instances of `ListSet` represent empty sets; they can be either created by calling the
* constructor directly, or by applying the function `ListSet.empty`.
*
* @tparam A the type of the elements contained in this list set
*
* @author Matthias Zenger
* @since 1
* @define Coll ListSet
* @define coll list set
* @define mayNotTerminateInf
* @define willNotTerminateInf
*/
@SerialVersionUID(-8417059026623606218L)
sealed class ListSet[A] extends AbstractSet[A]
with Set[A]
with GenericSetTemplate[A, ListSet]
with SetLike[A, ListSet[A]]
with Serializable {
override def companion: GenericCompanion[ListSet] = ListSet
override def size: Int = 0
override def isEmpty: Boolean = true
def contains(elem: A): Boolean = false
def +(elem: A): ListSet[A] = new Node(elem)
def -(elem: A): ListSet[A] = this
override def ++(xs: GenTraversableOnce[A]): ListSet[A] =
xs match {
// we want to avoid to use of iterator as it causes allocations
// during reverseList
case ls: ListSet[A] =>
if (ls eq this) this
else {
val lsSize = ls.size
if (lsSize == 0) this else {
@tailrec def skip(ls: ListSet[A], count: Int): ListSet[A] = {
if (count == 0) ls else skip(ls.next, count - 1)
}
@tailrec def containsLimited(n: ListSet[A], e: A, end: ListSet[A]): Boolean =
(n ne end) && (e == n.elem || containsLimited(n.next, e, end))
// We hope to get some structural sharing so find the tail of the
// ListSet that are `eq` (or if there are not any then the ends of the lists),
// and we optimise the add to only iterate until we reach the common end
val thisSize = this.size
val remaining = Math.min(thisSize, lsSize)
var thisTail = skip(this, thisSize - remaining)
var lsTail = skip(ls, lsSize - remaining)
while ((thisTail ne lsTail) && !lsTail.isEmpty) {
thisTail = thisTail.next
lsTail = lsTail.next
}
var toAdd = ls
var result: ListSet[A] = this
while (toAdd ne lsTail) {
val elem = toAdd.elem
if (!containsLimited(result, elem, lsTail)) {
val r = result
result = new r.Node(elem)
}
toAdd = toAdd.next
}
result
}
}
case _ =>
if (xs.isEmpty) this
else (repr /: xs) (_ + _)
}
def iterator: Iterator[A] = {
def reverseList = {
var curr: ListSet[A] = this
var res: List[A] = Nil
while (!curr.isEmpty) {
res = curr.elem :: res
curr = curr.next
}
res
}
reverseList.iterator
}
protected def elem: A = throw new NoSuchElementException("elem of empty set")
protected def next: ListSet[A] = throw new NoSuchElementException("next of empty set")
override def toSet[B >: A]: Set[B] = this.asInstanceOf[ListSet[B]]
override def stringPrefix = "ListSet"
/**
* Represents an entry in the `ListSet`.
*/
@SerialVersionUID(-787710309854855049L)
protected class Node(override protected val elem: A) extends ListSet[A] with Serializable {
override def size = sizeInternal(this, 0)
@tailrec private[this] def sizeInternal(n: ListSet[A], acc: Int): Int =
if (n.isEmpty) acc
else sizeInternal(n.next, acc + 1)
override def isEmpty: Boolean = false
override def contains(e: A) = containsInternal(this, e)
@tailrec private[this] def containsInternal(n: ListSet[A], e: A): Boolean =
!n.isEmpty && (n.elem == e || containsInternal(n.next, e))
@tailrec private[this] def indexInternal(n: ListSet[A], e: A, i:Int): Int =
if (n.isEmpty) -1
else if (n.elem == e) i
else indexInternal(n.next, e, i + 1)
override def +(e: A): ListSet[A] = if (contains(e)) this else new Node(e)
override def -(e: A): ListSet[A] = {
val index = indexInternal(this, e, 0)
if (index < 0) this
else if (index == 0) next
else {
val data = new Array[ListSet[A]](index)
@tailrec def store(i: Int, e: ListSet[A]): Unit = {
if (i < index) {
data(i) = e
store(i + 1, e.next)
}
}
@tailrec def reform(i: Int, e: ListSet[A]): ListSet[A] = {
if (i < 0) e
else reform (i -1, new e.Node(data(i).elem))
}
store(0, this)
reform(index -1, data(index - 1).next.next)
}
}
override protected def next: ListSet[A] = ListSet.this
override def last: A = elem
override def init: ListSet[A] = next
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy