
scalax.collection.mutable.Graph.scala Maven / Gradle / Ivy
The newest version!
package scalax.collection
package mutable
import java.io.{ObjectInputStream, ObjectOutputStream}
import scala.collection.generic.{CanBuildFrom, Growable, Shrinkable}
import scala.collection.mutable.{ArrayBuffer, Builder, Cloneable, Set => MutableSet}
import scala.reflect.ClassTag
import scala.math.max
import scalax.collection.{Graph => CommonGraph, GraphLike => CommonGraphLike}
import GraphPredef.{EdgeLikeIn, InnerEdgeParam, InnerNodeParam, OuterEdge, OuterNode, Param}
import generic.{GraphCompanion, MutableGraphCompanion}
import config._
import GraphEdge.UnDiEdge
abstract protected[collection] class BuilderImpl[
N,
E[+X] <: EdgeLikeIn[X],
CC[N, E[+X] <: EdgeLikeIn[X]] <: CommonGraph[N, E] with CommonGraphLike[N, E, CC]](implicit edgeT: ClassTag[E[N]],
config: GraphConfig)
extends Builder[Param[N, E], CC[N, E]]
with Compat.Growable[Param[N, E]] {
protected type This = CC[N, E]
protected val nodes = new ArrayBuffer[N](config.orderHint)
protected val edges = new ArrayBuffer[E[N]](
config match {
case CoreConfig(order, adjList) => order * max(adjList.initialCapacity, 16)
case _ => config.orderHint * 32
}
)
protected def add(elem: Param[N, E]) {
elem match {
case n: OuterNode[N] => nodes += n.value
case n: InnerNodeParam[N] => nodes += n.value
case e: OuterEdge[N, E] => edges += e.edge
case e: InnerEdgeParam[N, E, _, E] => edges += e.asEdgeTProjection[N, E].toOuter
}
}
def addOne(elem: Param[N, E]): this.type = {
add(elem)
this
}
def clear() {
nodes.clear()
edges.clear()
}
}
class GraphBuilder[N,
E[+X] <: EdgeLikeIn[X],
CC[N, E[+X] <: EdgeLikeIn[X]] <: CommonGraphLike[N, E, CC] with CommonGraph[N, E]](
companion: GraphCompanion[CC])(implicit edgeT: ClassTag[E[N]], config: GraphConfig)
extends BuilderImpl[N, E, CC] {
def result: This =
companion.from(nodes, edges)(edgeT, config.asInstanceOf[companion.Config])
}
/** Trait with common mutable Graph methods.
*
* @author Peter Empen
*/
trait GraphLike[N, E[+X] <: EdgeLikeIn[X], +This[X, Y[+X] <: EdgeLikeIn[X]] <: GraphLike[X, Y, This] with Graph[X, Y]]
extends CommonGraphLike[N, E, This]
with Growable[Param[N, E]]
with Shrinkable[Param[N, E]]
with Cloneable[Graph[N, E]]
with EdgeOps[N, E, This] {
this: // This[N,E] => see https://youtrack.jetbrains.com/issue/SCL-13199
This[N, E] with GraphLike[N, E, This] with Graph[N, E] =>
override def clone: This[N, E] = graphCompanion.from[N, E](nodes.toOuter, edges.toOuter)
type NodeT <: InnerNode
trait InnerNode extends super.InnerNode with InnerNodeOps {
this: NodeT =>
}
type NodeSetT <: NodeSet
trait NodeSet extends MutableSet[NodeT] with super.NodeSet {
@inline final def -?=(node: NodeT): this.type = { removeGently(node); this }
override def remove(node: NodeT): Boolean = subtract(node, rippleDelete = true, minus, minusEdges)
def removeGently(node: NodeT): Boolean = subtract(node, rippleDelete = false, minus, minusEdges)
/** removes all incident edges of `node` from the edge set leaving the node set unchanged.
*
* @param node the node the incident edges of which are to be removed from the edge set.
*/
protected def minusEdges(node: NodeT): Unit
override def diff(that: AnySet[NodeT]) = this -- that
override def clear(): Unit = this.toList.foreach(elem => this -= elem)
}
type EdgeSetT <: EdgeSet
trait EdgeSet extends MutableSet[EdgeT] with super.EdgeSet with Compat.AddSubtract[EdgeT, EdgeSet] {
@inline final def addOne(edge: EdgeT) = { add(edge); this }
@inline final def subtractOne(edge: EdgeT) = { remove(edge); this }
/** Same as `upsert` at graph level. */
def upsert(edge: EdgeT): Boolean
def removeWithNodes(edge: EdgeT): Boolean
override def diff(that: AnySet[EdgeT]) = this -- that
override def clear(): Unit = this.toList.foreach(elem => this -= elem)
}
/** Adds a node to this graph.
*
* @param node the node to be added
* @return `true` if the node was not yet present in the graph, `false` otherwise.
*/
def add(node: N): Boolean
/** Adds the given node if not yet present and returns it as an inner node.
*
* @param node the node to add.
* @return inner node containing the added node.
*/
@inline final def addAndGet(node: N): NodeT = { add(node); find(node).get }
def +(node: N) =
if (nodes contains Node(node)) this.asInstanceOf[This[N, E]]
else clone += node
@inline final def +=(node: N): this.type = { add(node); this }
def add(edge: E[N]): Boolean
/** Adds the given edge if not yet present and returns it as an inner edge.
*
* @param edge the edge to add.
* @return the inner edge containing the added edge.
*/
@inline final def addAndGet(edge: E[N]): EdgeT = { add(edge); find(edge).get }
protected def +=#(edge: E[N]): this.type
def addOne(elem: Param[N, E]): this.type =
elem match {
case n: OuterNode[N] => this += n.value
case n: InnerNodeParam[N] => this += n.value
case e: OuterEdge[N, E] => this +=# e.edge
case e: InnerEdgeParam[N, E, _, E] => this +=# e.asEdgeTProjection[N, E].toOuter
}
override def knownSize = nodes.size + edges.size
/** If an inner edge equaling to `edge` is present in this graph, it is replaced
* by `edge`, otherwise `edge` will be inserted. Such an update may be useful
* whenever non-key parts of an immutable edge are to be modified.
*
* @param edge The edge to add to this graph.
* @return `true` if `edge` has been inserted.
*/
def upsert(edge: E[N]): Boolean
@inline final def -(node: N): This[N, E] = clone -= node
@inline final def remove(node: N): Boolean = nodes find node exists (nodes remove _)
@inline final def -=(node: N): this.type = { remove(node); this }
@inline final def -?=(node: N): this.type = { removeGently(node); this }
@inline final def minusIsolated(node: N): This[N, E] = clone -?= node
@inline final def removeGently(node: N): Boolean = nodes find node exists (nodes removeGently _)
@inline final def -(edge: E[N]): This[N, E] = clone -=# edge
@inline final def remove(edge: E[N]): Boolean = edges remove Edge(edge)
@inline final protected def -=#(edge: E[N]): this.type = { remove(edge); this }
@inline final protected def -!=#(edge: E[N]): this.type = { removeWithNodes(edge); this }
@inline final def -!(edge: E[N]): This[N, E] = clone -!=# edge
@inline final protected def -!#(edge: E[N]): This[N, E] = clone -!=# edge
@inline final def removeWithNodes(edge: E[N]): Boolean = edges removeWithNodes Edge(edge)
def subtractOne(elem: Param[N, E]): this.type = elem match {
case n: OuterNode[N] => this -= n.value
case n: InnerNodeParam[N] => this -= n.value
case e: OuterEdge[N, E] => this -=# e.edge
case e: InnerEdgeParam[N, E, _, E] => this -=# e.asEdgeTProjection[N, E].toOuter
}
def -!=(elem: Param[N, E]): this.type = elem match {
case n: OuterNode[N] => this -= n.value
case n: InnerNodeParam[N] => this -= n.value
case e: OuterEdge[N, E] => this -!=# e.edge
case e: InnerEdgeParam[N, E, _, E] => this -!=# e.asEdgeTProjection[N, E].toOuter
}
/** Shrinks this graph to its intersection with `coll`.
*
* @param coll Collection of nodes and/or edges to intersect with;
* @return this graph shrinked by the nodes and edges not contained in `coll`.
*/
def &=(coll: Iterable[Param[N, E]]): this.type = {
val toKeep = MSet.empty[Param[N, E]] ++= coll
val toRemove = new EqHashSet[Param[N, E]](order)
def check(p: Param[N, E]): Unit = if (!toKeep.contains(p)) toRemove += p
this foreach check
toRemove foreach -=
this
}
/** Removes all elements of `coll` from this graph. Edges will be ripple removed.
*
* @param coll Collection of nodes and/or edges to be removed; if the element type is N,
* it is removed from the node set otherwise from the edge set.
* @return this graph shrinked by the nodes and edges contained in `coll`.
*/
@inline final def --!=(coll: Iterable[Param[N, E]]): This[N, E] = (this /: coll)(_ -!= _)
}
/** The main trait for mutable graphs bundling functionality that is not specific to graph representation.
*
* @tparam N the type of the nodes (vertices) in this graph.
* @tparam E the kind of the edges in this graph.
* @author Peter Empen
*/
trait Graph[N, E[+X] <: EdgeLikeIn[X]] extends CommonGraph[N, E] with GraphLike[N, E, Graph] {
override def empty: Graph[N, E] = Graph.empty[N, E]
}
/** The main companion object for mutable graphs.
*
* @author Peter Empen
*/
object Graph extends MutableGraphCompanion[Graph] {
def empty[N, E[+X] <: EdgeLikeIn[X]](implicit edgeT: ClassTag[E[N]], config: Config = defaultConfig): Graph[N, E] =
new DefaultGraphImpl[N, E]()(edgeT, config)
override def from[N, E[+X] <: EdgeLikeIn[X]](nodes: Iterable[N] = Nil, edges: Iterable[E[N]])(
implicit edgeT: ClassTag[E[N]],
config: Config = defaultConfig): Graph[N, E] =
DefaultGraphImpl.from[N, E](nodes, edges)(edgeT, config)
implicit def cbfUnDi[N, E[+X] <: EdgeLikeIn[X]](implicit edgeT: ClassTag[E[N]], config: Config = defaultConfig) =
new GraphCanBuildFrom[N, E]()(edgeT, config)
.asInstanceOf[GraphCanBuildFrom[N, E] with CanBuildFrom[Graph[_, UnDiEdge], Param[N, E], Graph[N, E]]]
}
@SerialVersionUID(74L)
class DefaultGraphImpl[N, E[+X] <: EdgeLikeIn[X]](iniNodes: Iterable[N] = Set[N](),
iniEdges: Iterable[E[N]] = Set[E[N]]())(
implicit override val edgeT: ClassTag[E[N]],
override val config: DefaultGraphImpl.Config with AdjacencyListArrayConfig)
extends Graph[N, E]
with AdjacencyListGraph[N, E, DefaultGraphImpl]
with GraphTraversalImpl[N, E] {
final override val graphCompanion = DefaultGraphImpl
protected type Config = DefaultGraphImpl.Config
type NodeSetT = NodeSet
@inline final protected def newNodeSet: NodeSetT = new NodeSet
@transient private[this] var _nodes: NodeSetT = newNodeSet
@inline final override def nodes = _nodes
type EdgeSetT = EdgeSet
@transient private[this] var _edges: EdgeSetT = new EdgeSet
@inline final override def edges = _edges
initialize(iniNodes, iniEdges)
// TODO what to do with newBuilder & empty?
//override protected[this] def newBuilder = new GraphBuilder[N, E, DefaultGraphImpl](DefaultGraphImpl)
final override def empty: DefaultGraphImpl[N, E] = DefaultGraphImpl.empty[N, E]
final override def clone: this.type = super.clone.asInstanceOf[this.type]
@inline final protected def +#(edge: E[N]): DefaultGraphImpl[N, E] = clone +=# edge
@inline protected def -#(edge: E[N]): DefaultGraphImpl.this.type = clone -=# edge
@SerialVersionUID(7370L)
final protected class NodeBase(value: N, hints: ArraySet.Hints)
extends InnerNodeImpl(value, hints)
with InnerNodeTraversalImpl
type NodeT = NodeBase
@inline final protected def newNodeWithHints(n: N, h: ArraySet.Hints) = new NodeT(n, h)
private def writeObject(out: ObjectOutputStream): Unit = serializeTo(out)
private def readObject(in: ObjectInputStream): Unit = {
_nodes = newNodeSet
_edges = new EdgeSet
initializeFrom(in, _nodes, _edges)
}
}
object DefaultGraphImpl extends MutableGraphCompanion[DefaultGraphImpl] {
def empty[N, E[+X] <: EdgeLikeIn[X]](implicit edgeT: ClassTag[E[N]], config: Config = defaultConfig) =
new DefaultGraphImpl[N, E]()(edgeT, config)
override def from[N, E[+X] <: EdgeLikeIn[X]](nodes: Iterable[N] = Nil, edges: Iterable[E[N]])(
implicit edgeT: ClassTag[E[N]],
config: Config = defaultConfig) =
new DefaultGraphImpl[N, E](nodes, edges)(edgeT, config)
}