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

scalax.collection.ToString.scala Maven / Gradle / Ivy

The newest version!
package scalax.collection

import scalax.collection.generic.Edge

protected trait ToString[N, E <: Edge[N], +CC[X, Y <: Edge[X]] <: GraphLike[X, Y, CC] with AnyGraph[X, Y]] {
  this: GraphLike[N, E, CC] =>
  import ToString._

  protected def className: String = "Graph"

  /** Sorts nodes and edges as long as this `Graph` has at most 100 elements.
    * See also `def render`.
    */
  override def toString: String = if (elementCount <= 100) render(SingleLine) else super.toString

  /** Sorts all nodes of this graph by `ordNode` followed by all edges sorted by `ordEdge`
    * and concatenates their string representation `nodeSeparator` and `edgeSeparator`
    * respectively.
    *
    * @param nodeEdgeSetSeparator to separate the node set from the edge set.
    * @param withInnerPrefix      whether the node set and edge set should be prefixed.
    * @param ordNode              the node ordering defaulting to `defaultNodeOrdering`.
    * @param ordEdge              the edge ordering defaulting to `defaultEdgeOrdering`.
    */
  def render(
      style: Style,
      nodeSeparator: String = GraphBase.defaultSeparator,
      edgeSeparator: String = GraphBase.defaultSeparator,
      nodeEdgeSetSeparator: String = GraphBase.defaultSeparator,
      withInnerPrefix: Boolean = true
  )(implicit ordNode: NodeOrdering = defaultNodeOrdering, ordEdge: EdgeOrdering = defaultEdgeOrdering): String =
    if (nodes.isEmpty) s"$className()"
    else {
      val sets = {
        val setStyle: SetStyle = (style match {
          case s: StyleWithIndent[_] => s.incremented
          case s                     => s
        }).toSetStyle
        List(
          nodes.render(setStyle, nodeSeparator, withInnerPrefix)(ordNode),
          edges.render(setStyle, edgeSeparator, withInnerPrefix)(ordEdge)
        )
      }
      sets.prefixed(style, className, nodeEdgeSetSeparator)
    }

  protected trait SetToString[A] extends AnySet[A] {

    /** Sorts all nodes according to `ord`, concatenates them using `separator`,
      * and prefixes and parenthesizes the result unless `prefix` is blank.
      */
    def render(style: SetStyle, separator: String = GraphBase.defaultSeparator, prefix: String = className)(implicit
        ord: Ordering[A]
    ): String =
      toList.sorted.prefixed(style, prefix, separator)

    /** Sorts all nodes according to `ord`, concatenates them using `separator`,
      * and prefixes and parenthesizes the result if `withPrefix` is `true`.
      */
    def render(style: SetStyle, separator: String, withPrefix: Boolean)(implicit
        ord: Ordering[A]
    ): String =
      render(style, separator, if (withPrefix) className else "")
  }

  protected trait NodeSetToString extends SetToString[NodeT] {
    final override protected def className: String = "NodeSet"
  }

  protected trait EdgeSetToString extends SetToString[EdgeT] {
    final override protected def className: String = "EdgeSet"
  }
}

object ToString {
  sealed trait Style {
    def toSetStyle: SetStyle = this match {
      case s: SetStyle            => s
      case s: SetsOnSeparateLines => SingleLine
    }
  }
  sealed trait StyleWithIndent[C <: StyleWithIndent[C]] extends Style {
    def indent: Int
    def incremented: C
  }
  sealed trait SetStyle extends Style

  object SingleLine extends SetStyle
  final case class SetsOnSeparateLines(indent: Int = 0) extends StyleWithIndent[SetsOnSeparateLines] {
    def incremented: SetsOnSeparateLines = copy(indent + 2)
  }
  final case class SetElemsOnSeparateLines(indent: Int = 0)
      extends StyleWithIndent[SetElemsOnSeparateLines]
      with SetStyle {
    def incremented: SetElemsOnSeparateLines = copy(indent + 2)
  }

  private val lineSeparator = System.lineSeparator

  implicit private class StringEnrichments(val it: Iterable[_]) extends AnyVal {

    def prefixed(style: Style, prefix: String, separator: String): String = {
      val (prefixOpeningBrace, closingBrace) =
        if (prefix.isBlank) ("", "")
        else (s"$prefix(", ")")
      val (open, sep, close) =
        style match {
          case SingleLine =>
            (prefixOpeningBrace, separator, closingBrace)
          case style: StyleWithIndent[_] =>
            def spaces(count: Int) = " " * count
            val newLine            = s"$lineSeparator${spaces(style.incremented.indent)}"
            (
              s"$prefixOpeningBrace${if (it.isEmpty) "" else if (prefix.isBlank) "  " else newLine}",
              s"${separator.trim}$newLine",
              closingBrace
            )
        }
      it.mkString(open, sep, close)
    }
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy