All Downloads are FREE. Search and download functionalities are using the official Maven repository.

scalax.collection.constrained.mutable.Graph.scala Maven / Gradle / Ivy

The newest version!
package scalax.collection.constrained
package mutable

import java.io.{ObjectInputStream, ObjectOutputStream}

import scala.language.{higherKinds, postfixOps}
import scala.collection.Set
import scala.collection.generic.{Growable, Shrinkable}
import scala.collection.mutable.Cloneable
import scala.reflect.ClassTag

import scalax.collection.GraphTraversalImpl
import scalax.collection.GraphPredef.{EdgeLikeIn, Param}
import scalax.collection.mutable.{ArraySet, BuilderImpl}
import scalax.collection.config.AdjacencyListArrayConfig
import scalax.collection.constrained.{Graph => CGraph, GraphLike => CGraphLike}
import PreCheckFollowUp._
import generic.GraphConstrainedCompanion
import config.GenConstrainedConfig

class GraphBuilder[N, E[X] <: EdgeLikeIn[X], GC[N, E[X] <: EdgeLikeIn[X]] <: CGraph[N, E] with CGraphLike[N, E, GC]](
    companion: GraphConstrainedCompanion[GC])(implicit edgeT: ClassTag[E[N]], config: GenConstrainedConfig)
    extends BuilderImpl[N, E, GC] {
  def result: This =
    companion.from(nodes, edges)(edgeT, config.asInstanceOf[companion.Config])
}

trait GraphLike[N, E[X] <: EdgeLikeIn[X], +This[X, Y[X] <: EdgeLikeIn[X]] <: GraphLike[X, Y, This] with Graph[X, Y]]
    extends scalax.collection.mutable.GraphLike[N, E, This]
    with scalax.collection.constrained.GraphLike[N, E, This]
    with GraphOps[N, E, This]
    with Growable[Param[N, E]]
    with Shrinkable[Param[N, E]]
    with Cloneable[This[N, E]]
    with Mutable {
  selfGraph: // This[N,E] => see https://youtrack.jetbrains.com/issue/SCL-13199
  This[N, E] with GraphLike[N, E, This] with Graph[N, E] =>

  trait NodeSet extends super.NodeSet {

    protected def checkedRemove(fake: NodeT, ripple: Boolean): Either[ConstraintViolation, Boolean] =
      nodes find fake map { node =>
        def remove = withoutChecks {
          subtract(node, ripple, minus, minusEdges)
        }
        if (checkSuspended) Right(remove)
        else {
          val preCheckResult = preSubtract(node.asInstanceOf[self.NodeT], ripple)
          preCheckResult.followUp match {
            case Complete => Right(remove)
            case PostCheck =>
              val incidentEdges = node.edges.toBuffer
              if (remove) {
                postSubtract(selfGraph, Set(node), Set.empty[E[N]], preCheckResult).fold(
                  failure => {
                    withoutChecks {
                      selfGraph += node.value
                      selfGraph ++= incidentEdges
                    }
                    Left(failure)
                  },
                  _ => Right(true)
                )
              } else Right(false)
            case Abort => Left(preCheckResult)
          }
        }
      } getOrElse Right(false)

    final override def remove(node: NodeT): Boolean       = remove_?(node) getOrElse false
    final override def removeGently(node: NodeT): Boolean = removeGently_?(node) getOrElse false

    def remove_?(fake: NodeT): Either[ConstraintViolation, Boolean]       = checkedRemove(fake, ripple = true)
    def removeGently_?(fake: NodeT): Either[ConstraintViolation, Boolean] = checkedRemove(fake, ripple = false)
  }

  override def +(node: N): This[N, E] = +?(node) getOrElse this

  def +?(node: N): Either[ConstraintViolation, This[N, E]] =
    checkedPlus(
      contained = nodes contains Node(node),
      preAdd = preAdd(node),
      copy = clone += node,
      nodes = Set(node),
      edges = Set.empty)

  final override protected def +#(e: E[N]): This[N, E] = +#?(e) getOrElse this

  final protected def +#?(e: E[N]): Either[ConstraintViolation, This[N, E]] =
    checkedPlus(
      contained = edges contains Edge(e),
      preAdd = preAdd(e),
      copy = clone +=# e,
      nodes = Set.empty,
      edges = Set(e))

  override def ++=(elems: TraversableOnce[Param[N, E]]): this.type = ++=?(elems) getOrElse this

  def ++=?(elems: TraversableOnce[Param[N, E]]): Either[ConstraintViolation, this.type] = {
    def add: this.type = withoutChecks { super.++=(elems) }
    if (checkSuspended) Right(add)
    else {
      def process(elems: Traversable[Param[N, E]]): Option[ConstraintViolation] = {
        val (filteredElems, newNodes, newEdges) = {
          val p     = new Param.Partitions[N, E]((elems filterNot contains).toSet)
          val edges = p.toOuterEdges
          (
            p.toInParams.toSeq,
            nodesToAdd(p.toOuterNodes, edges),
            edges
          )
        }
        val preCheckResult = preAdd(filteredElems: _*)
        if (preCheckResult.abort) Some(preCheckResult)
        else {
          add
          if (preCheckResult.postCheck) {
            postAdd(this, newNodes, newEdges, preCheckResult).fold(
              failure => {
                withoutChecks {
                  newNodes foreach super.remove
                  newEdges foreach super.remove
                }
                Some(failure)
              },
              _ => None
            )
          } else None
        }
      }
      (elems match {
        case elems: Traversable[Param[N, E]] => process(elems)
        case traversableOnce                 => process(traversableOnce.toSet)
      }).fold[Either[ConstraintViolation, this.type]](Right(this))(Left(_))
    }
  }

  final def -?(node: N): Either[ConstraintViolation, This[N, E]] =
    checkedMinusNode(node, forced = true, (outer: N, inner: NodeT) => { val c = clone; c -= outer; c })

  final override protected def -#(e: E[N]): This[N, E] = +#?(e) getOrElse this

  final protected def -#?(e: E[N]): Either[ConstraintViolation, This[N, E]] =
    checkedMinusEdge(e, simple = true, (outer: E[N], inner: EdgeT) => { val c = clone; c -=# outer; c })

  def --=?(elems: TraversableOnce[Param[N, E]]): Either[ConstraintViolation, this.type] = {
    val (outerNodes, outerEdges) = {
      val p = partition(elems)
      (p.toOuterNodes.toSet, p.toOuterEdges.toSet)
    }
    val (innerNodes, innerEdges) = (outerNodes map find flatten, outerEdges map find flatten)
    val preCheckResult =
      preSubtract(innerNodes.asInstanceOf[Set[self.NodeT]], innerEdges.asInstanceOf[Set[self.EdgeT]], true)
    preCheckResult.followUp match {
      case Complete => Right(withoutChecks { super.--=(elems) })
      case PostCheck =>
        val subtractables = (elems filter this.contains).toArray ++ innerNodes.flatMap(_.edges).toBuffer
        withoutChecks { super.--=(subtractables) }
        postSubtract(this, outerNodes, outerEdges, preCheckResult).fold(
          failure => {
            withoutChecks { super.++=(subtractables) }
            Left(failure)
          },
          _ => Right(this)
        )
      case Abort => Left(preCheckResult)
    }
  }
}

import scalax.collection.constrained.generic.MutableGraphCompanion

trait Graph[N, E[X] <: EdgeLikeIn[X]]
    extends scalax.collection.mutable.Graph[N, E]
    with scalax.collection.constrained.Graph[N, E]
    with GraphLike[N, E, Graph] {
  override def empty: Graph[N, E] = Graph.empty[N, E](edgeT, config)
}

object Graph extends MutableGraphCompanion[Graph] {
  override def empty[N, E[X] <: EdgeLikeIn[X]](implicit edgeT: ClassTag[E[N]], config: Config): Graph[N, E] =
    DefaultGraphImpl.empty[N, E](edgeT, config)

  override protected[collection] def fromWithoutCheck[N, E[X] <: EdgeLikeIn[X]](
      nodes: Traversable[N],
      edges: Traversable[E[N]])(implicit edgeT: ClassTag[E[N]], config: Config): Graph[N, E] =
    DefaultGraphImpl.fromWithoutCheck[N, E](nodes, edges)(edgeT, config)

  override def from[N, E[X] <: EdgeLikeIn[X]](nodes: Traversable[N], edges: Traversable[E[N]])(
      implicit edgeT: ClassTag[E[N]],
      config: Config): Graph[N, E] =
    DefaultGraphImpl.from[N, E](nodes, edges)(edgeT, config)

  // TODO: canBuildFrom
}

abstract class DefaultGraphImpl[N, E[X] <: EdgeLikeIn[X]](iniNodes: Traversable[N] = Set[N](),
                                                          iniEdges: Traversable[E[N]] = Set[E[N]]())(
    implicit override val edgeT: ClassTag[E[N]],
    _config: DefaultGraphImpl.Config with GenConstrainedConfig 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
  final override def config = _config.asInstanceOf[graphCompanion.Config with Config]

  @inline final protected def newNodeSet: NodeSetT = new NodeSet
  @transient protected[this] var _nodes: NodeSetT  = newNodeSet
  @inline final override def nodes                 = _nodes

  @transient protected[this] var _edges: EdgeSetT = new EdgeSet
  @inline final override def edges                = _edges

  initialize(iniNodes, iniEdges)

  @inline final override def empty = DefaultGraphImpl.empty(edgeT, config)

  @inline final override def clone: this.type =
    graphCompanion.fromWithoutCheck[N, E](nodes.toOuter, edges.toOuter)(edgeT, config).asInstanceOf[this.type]

  @SerialVersionUID(8082L)
  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)
}

object DefaultGraphImpl extends MutableGraphCompanion[DefaultGraphImpl] {
  override def empty[N, E[X] <: EdgeLikeIn[X]](implicit edgeT: ClassTag[E[N]], config: Config): DefaultGraphImpl[N, E] =
    fromWithoutCheck(Set.empty, Set.empty)(edgeT, config)

  override protected[collection] def fromWithoutCheck[N, E[X] <: EdgeLikeIn[X]](
      nodes: Traversable[N],
      edges: Traversable[E[N]])(implicit edgeT: ClassTag[E[N]], config: Config): DefaultGraphImpl[N, E] =
    new UserConstrainedGraphImpl[N, E](nodes, edges)(edgeT, config)

  final override def from[N, E[X] <: EdgeLikeIn[X]](nodes: Traversable[N], edges: Traversable[E[N]])(
      implicit edgeT: ClassTag[E[N]],
      config: Config): DefaultGraphImpl[N, E] = from_?(nodes, edges) getOrElse empty[N, E](edgeT, config)

  def from_?[N, E[X] <: EdgeLikeIn[X]](nodes: Traversable[N], edges: Traversable[E[N]])(
      implicit edgeT: ClassTag[E[N]],
      config: Config): Either[ConstraintViolation, DefaultGraphImpl[N, E]] = {
    def emptyGraph = empty[N, E](edgeT, config)

    if (nodes.isEmpty && edges.isEmpty) Right(empty[N, E](edgeT, config))
    else {
      val constraint     = config.constraintCompanion[N, E, DefaultGraphImpl[N, E]](emptyGraph)
      val preCheckResult = constraint.preCreate(nodes, edges)
      if (preCheckResult.abort) Left(preCheckResult)
      else {
        val newGraph = fromWithoutCheck[N, E](nodes, edges)(edgeT, config)
        preCheckResult.followUp match {
          case Complete  => Right(newGraph)
          case PostCheck => constraint.postAdd(newGraph, nodes, edges, preCheckResult)
          case Abort     => Left(preCheckResult)
        }
      }
    }
  }
}

@SerialVersionUID(7701L)
class UserConstrainedGraphImpl[N, E[X] <: EdgeLikeIn[X]](
    iniNodes: Traversable[N] = Nil,
    iniEdges: Traversable[E[N]] = Nil)(implicit override val edgeT: ClassTag[E[N]], _config: DefaultGraphImpl.Config)
    extends DefaultGraphImpl[N, E](iniNodes, iniEdges)(edgeT, _config)
    with UserConstrainedGraph[N, E, DefaultGraphImpl[N, E]] {

  final override val self              = this
  final override val constraintFactory = config.constraintCompanion
  final override val constraint        = constraintFactory(this)

  private def writeObject(out: ObjectOutputStream): Unit = serializeTo(out)

  private def readObject(in: ObjectInputStream): Unit = {
    _nodes = newNodeSet
    _edges = new EdgeSet
    initializeFrom(in, _nodes, _edges)
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy