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

scalaz.Cord.scala Maven / Gradle / Ivy

package scalaz

import std.anyVal._
import std.vector._
import std.string._

/**
 * A `Cord` is a purely functional data structure for efficiently
 * storing and manipulating `String`s that are potentially very long.
 * Very similar to `Rope[Char]`, but with better constant factors and a
 * simpler interface since it's specialized for `String`s.
 */
final case class Cord(self: FingerTree[Int, String]) {

  import Cord.{stringToCord => _, _}

  private def rangeError(i: Int) = sys.error("Index out of range: " + i + " >= " + self.measure)

  /**
    * Returns the character at the given position. Throws an error if the index is out of range.
    * Time complexity: O(log N)
    */
  def apply(i: Int): Char = {
    val (a, b) = self.split(_ > i)
    b.viewl.headOption.map(_(i - a.measure)).getOrElse(rangeError(i))
  }

  /**
   * Splits this `Cord` in two at the given position.
   * Time complexity: O(log N)
   */
  def split(i: Int): (Cord, Cord) = {
    val (l, mid, r) = self.split1(_ > i)
    val (midl, midr) = mid.splitAt(i - l.measure)
    (cord(l :+ midl), cord(midr +: r))
  }

  /**
   * Returns the number of characters in this `Cord`.
   * Time complexity: O(1)
   */
  def length: Int = self.measure

  /**
   * Returns the number of characters in this `Cord`.
   * Time complexity: O(1)
   */
  def size: Int = self.measure

  /**
   * Appends another `Cord` to the end of this one.
   * Time complexity: O(log (min N M)) where M and N are the lengths of the two `Cord`s.
   */
  def ++(xs: Cord): Cord = cord(self <++> xs.self)

  /**
   * Appends a `String` to the end of this `Cord`.
   * Time complexity: O(1)
   */
  def :+(x: => String): Cord = cord(self :+ x)

  /**
   * Prepends a `String` to the beginning of this `Cord`.
   * Time complexity: O(1)
   */
  def +:(x: => String): Cord = cord(x +: self)

  /**
   * Prepends a `Char` to the beginning of this `Cord`.
   * Time complexity: O(1)
   */
  def -:(x: => Char): Cord = cord(x.toString +: self)

  /**
   * Appends a `Char` to the end of this `Cord`.
   * Time complexity: O(1)
   */
  def :-(x: => Char): Cord = cord(self :+ x.toString)

  /**
   * Removes the first character of this `Cord`.
   * Time complexity: O(1)
   */
  def tail: Cord = drop(1)

  /**
   * Removes the last character of this `Cord`.
   * Time complexity: O(1)
   */
  def init: Cord = take(self.measure - 1)

  /**
   * Removes the first `n` characters from the front of this `Cord`.
   * Time complexity: O(min N (N - n))
   */
  def drop(n: Int): Cord = split(n)._2

  /**
   * Returns the first `n` characters at the front of this `Cord`.
   * Time complexity: O(min N (N - n))
   */
  def take(n: Int): Cord = split(n)._1

  /**
   * Modifies each character in this `Cord` by the given function.
   * Time complexity: O(N)
   */
  def map(f: Char => Char): Cord = cord(self map (_ map f))

  def toList: List[Char] = toVector.toList
  def toStream: Stream[Char] = toVector.toStream
  def toVector: Vector[Char] = self.foldMap(_.toVector)
  override def toString: String = {
    import syntax.foldable._
    import Free._
    val sb = new StringBuilder(self.measure)
    val t = self.traverse_[Trampoline](x => Trampoline.delay(sb ++= x))
    t.run
    sb.toString
  }

  /** Transforms each character to a `Cord` according to the given function and concatenates them all into one `Cord`. */
  def flatMap(f: Char => Cord): Cord = toVector.foldLeft(Cord())((as, a) => as ++ f(a))

  /** Returns whether this `Cord` will expand to an empty string. */
  def isEmpty: Boolean = !nonEmpty

  /** Returns whether this `Cord` will expand to a non-empty string. */
  def nonEmpty: Boolean = self.iterator.exists(_.nonEmpty)
}

object Cord {
  private def cord[A](v: FingerTree[Int, String]): Cord = new Cord(v)

  implicit def stringToCord(s: String): Cord = cord(FingerTree.single[Int, String](s))

  lazy val empty: Cord = apply()

  def apply(as: Cord*): Cord = as.foldLeft(cord(FingerTree.empty))(_ ++ _)

  def fromStrings[A](as: Seq[String]): Cord = cord(as.foldLeft(FingerTree.empty[Int, String](sizer))((x, y) => x :+ y))

  implicit val sizer: Reducer[String, Int] = UnitReducer((a: String) => a.length)

  def mkCord(sep: Cord, as: Cord*): Cord =
    if (!as.isEmpty)
      as.tail.foldLeft(as.head)(_ ++ sep ++ _)
    else
      Cord()

  implicit val CordShow: Show[Cord] = new Show[Cord] {
    override def show(x: Cord) = x
    override def shows(x: Cord) = x.toString
  }

  implicit val CordMonoid: Monoid[Cord] = new Monoid[Cord] {
    def zero = empty
    def append(x: Cord, y: => Cord) = x ++ y
  }

  implicit val CordEqual: Equal[Cord] = new Equal[Cord] {
    def equal(x: Cord, y: Cord) = Equal[FingerTree[Int, String]].equal(x.self, y.self)
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy