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

org.opalj.collection.immutable.Chain.scala Maven / Gradle / Ivy

The newest version!
/* BSD 2-Clause License - see OPAL/LICENSE for details. */
package org.opalj
package collection
package immutable

import scala.language.implicitConversions

import scala.collection.GenIterable
import scala.collection.GenTraversableOnce
import scala.collection.AbstractIterator
import scala.collection.generic.CanBuildFrom
import scala.collection.mutable.Builder
import scala.collection.generic.FilterMonadic
import scala.collection.AbstractIterable

/**
 * A linked list which does not perform any length related checks. I.e., it fails in
 * case of `drop` and `take` etc. if the size of the list is smaller than expected.
 * Furthermore, all directly implemented methods use `while` loops for maximum
 * efficiency and the list is also specialized for primitive `int` values which
 * makes this list far more efficient when used for storing lists of `int` values.
 *
 * @note    In most cases a `Chain` can be used as a drop-in replacement for a standard
 *          Scala List.
 *
 * @note    Some core methods, e.g. `drop` and `take`, have different
 *          semantics when compared to the methods with the same name defined
 *          by the Scala collections API. In this case these methods may
 *          fail arbitrarily if the list is not long enough.
 *          Therefore, `Chain` does not inherit from `scala...Seq`.
 *
 * @author Michael Eichberg
 */
sealed trait Chain[@specialized(Int) +T]
    extends TraversableOnce[T]
    with FilterMonadic[T, Chain[T]]
    with Serializable { self ⇒

    /**
     * Represents a filtered [[Chain]]. Instances of [[ChainWithFilter]] are typically
     * created by [[Chain]]'s `withFilter` method.
     */
    class ChainWithFilter(p: T ⇒ Boolean) extends FilterMonadic[T, Chain[T]] {

        def map[B, That](f: T ⇒ B)(implicit bf: CanBuildFrom[Chain[T], B, That]): That = {
            val list = self
            var rest = list

            val b = bf(list)
            while (rest.nonEmpty) {
                val x = rest.head
                if (p(x)) b += f(x)
                rest = rest.tail
            }
            b.result
        }

        def flatMap[B, That](
            f: T ⇒ GenTraversableOnce[B]
        )(
            implicit
            bf: CanBuildFrom[Chain[T], B, That]
        ): That = {
            val list = self
            val b = bf(list)
            var rest = list
            while (rest.nonEmpty) {
                val x = rest.head
                if (p(x)) b ++= f(x).seq
                rest = rest.tail
            }
            b.result
        }

        def foreach[U](f: T ⇒ U): Unit = {
            var rest = self
            while (rest.nonEmpty) {
                val x = rest.head
                if (p(x)) f(x)
                rest = rest.tail
            }
        }

        def withFilter(q: T ⇒ Boolean): ChainWithFilter = {
            new ChainWithFilter(x ⇒ p(x) && q(x))
        }
    }

    final override def hasDefiniteSize: Boolean = true

    final override def isTraversableAgain: Boolean = true

    final override def seq: this.type = this

    override def foreach[U](f: T ⇒ U): Unit = {
        var rest = this
        while (rest.nonEmpty) {
            f(rest.head)
            rest = rest.tail
        }
    }

    /**
     * Executes the given function `f` for each element of this chain as long as
     * it returns `true`.
     */
    def foreachWhile(f: T ⇒ Boolean): Boolean = {
        var rest = this
        while (rest.nonEmpty) {
            if (!f(rest.head))
                return false;

            rest = rest.tail
        }
        return true;
    }

    def startsWith[X >: T](other: Chain[X]): Boolean = {
        var thisRest = this
        var otherRest = other
        while (otherRest.nonEmpty) {
            if (thisRest.isEmpty || thisRest.head != otherRest.head)
                return false;
            thisRest = thisRest.tail
            otherRest = otherRest.tail
        }
        true
    }

    /**
     *  Computes the shared prefix.
     */
    def sharedPrefix[X >: T](other: Chain[X]): Chain[T] = {
        val Nil = Naught
        var prefixHead: Chain[T] = Nil
        var prefixLast: :&:[T] = null
        var thisRest = this
        var otherRest = other
        while (thisRest.nonEmpty && otherRest.nonEmpty && thisRest.head == otherRest.head) {
            if (prefixLast == null) {
                prefixLast = new :&:[T](thisRest.head, Nil)
                prefixHead = prefixLast
            } else {
                prefixLast.rest = new :&:[T](thisRest.head, Nil)
            }
            thisRest = thisRest.tail
            otherRest = otherRest.tail
        }
        if (thisRest.isEmpty)
            this
        else if (otherRest.isEmpty)
            other.asInstanceOf[Chain[T]]
        else
            prefixHead
    }

    def forFirstN[U](n: Int)(f: T ⇒ U): Unit = {
        var rest = this
        var i = 0
        while (i < n) {
            val head = rest.head
            rest = rest.tail
            f(head)
            i += 1
        }
    }

    def flatMap[B, That](
        f: T ⇒ GenTraversableOnce[B]
    )(
        implicit
        bf: CanBuildFrom[Chain[T], B, That]
    ): That = {
        val b = bf(this)
        //OLD: foreach { t ⇒ f(t) foreach { e ⇒ builder += e } }
        var rest = this
        while (rest.nonEmpty) {
            val t = rest.head
            b ++= f(t).seq
            rest = rest.tail
        }
        b.result
    }

    def map[B, That](f: (T) ⇒ B)(implicit bf: CanBuildFrom[Chain[T], B, That]): That = {
        val builder = bf(this)
        var rest = this
        while (rest.nonEmpty) {
            val t = rest.head
            builder += f(t)
            rest = rest.tail
        }
        builder.result
    }

    def withFilter(p: (T) ⇒ Boolean): ChainWithFilter = new ChainWithFilter(p)

    def head: T

    def headOption: Option[T]

    def tail: Chain[T]

    def last: T = {
        var rest = this
        while (rest.tail.nonEmpty) { rest = rest.tail }
        rest.head
    }

    def isSingletonList: Boolean

    def hasMultipleElements: Boolean

    override def nonEmpty: Boolean

    /**
     * Returns the value of the element of this list with the given index.
     *
     * @param index A valid index. A value in the range [0...this.size-1].
     */
    def apply(index: Int): T = {
        var count = index
        var rest = this
        while (count > 0) {
            rest = rest.tail
            count -= 1
        }
        rest.head
    }

    def exists(f: T ⇒ Boolean): Boolean = {
        var rest = this
        while (rest.nonEmpty) {
            if (f(rest.head))
                return true;
            rest = rest.tail
        }
        false
    }

    def forall(f: T ⇒ Boolean): Boolean = {
        var rest = this
        while (rest.nonEmpty) {
            if (!f(rest.head))
                return false;
            rest = rest.tail
        }
        true
    }

    def contains[X >: T](e: X): Boolean = {
        var rest = this
        while (rest.nonEmpty) {
            if (rest.head == e)
                return true;
            rest = rest.tail
        }
        false
    }

    def find(p: T ⇒ Boolean): Option[T] = {
        var rest = this
        while (rest.nonEmpty) {
            val e = rest.head
            if (p(e))
                return Some(e);
            rest = rest.tail
        }
        None
    }

    /**
     * Counts the number of elements.
     *
     * @note   This operation has complexity O(n).
     * @return The size of this list.
     */
    override def size: Int = {
        var result = 0
        var rest = this
        while (rest.nonEmpty) {
            result += 1
            rest = rest.tail
        }
        result
    }

    /**
     * Prepends the given element to this Chain.
     */
    def :&:[X >: T](x: X): Chain[X] = new :&:(x, this)

    /**
     * Prepends the given `int` value to this Chain if this chain is a chain of int values.
     */
    def :&:(x: Int)(implicit ev: this.type <:< Chain[Int]): Chain[Int] = {
        new :&:[Int](x, ev(this))
    }

    /**
     * Prepends the given `Chain` to `this` chain.
     */
    def :&::[X >: T](x: Chain[X]): Chain[X]

    /**
     * Prepends the given list to '''this list''' by setting the end of the given list to
     * this list.
     *
     * @note     '''This mutates the given list unless the given list is empty; hence
     *           The return value ''must not be ignored''.'''
     *
     * @note    Using this function is save if and only if no alias of this list
     *          or the given list exists.
     */
    private[opalj] def ++!:[X >: T](x: Chain[X]): Chain[X] = {
        if (x.isEmpty)
            return this;

        var lastNode = x.asInstanceOf[:&:[X]]
        while (lastNode.rest.nonEmpty) {
            lastNode = lastNode.rest.asInstanceOf[:&:[X]]
        }
        lastNode.rest = this
        x
    }

    /**
     * @see [[++!:]]
     */
    private[opalj] def ++![X >: T](x: Chain[X]): Chain[X] = x.++!:(this)

    /**
     * Clones this list and returns the cloned list as well as the last element of the list; using
     * the last element it is possible to immediately attach further elements to the list at its end.
     * If this list is empty, the last element is null.
     */
    private[opalj] def copy[X >: T](): (Chain[X], :&:[X]) = {
        val Nil: Chain[X] = Naught
        if (isEmpty)
            return (this, null);

        val result = new :&:[X](head, Nil)
        var last = result
        var rest: Chain[X] = this.tail
        while (rest.nonEmpty) {
            val x = rest.head
            rest = rest.tail
            val newLast = new :&:[X](x, Nil)
            last.rest = newLast
            last = newLast
        }
        (result, last)
    }

    // TODO Manually specialize Chain!
    def ++[X >: T](that: Chain[X]): Chain[X] = {
        if (that.isEmpty)
            return this;
        if (this.isEmpty)
            return that;

        val (head, last) = copy[X]
        last.rest = that
        head
    }

    // TODO Manually specialize Chain!
    def ++[X >: T](other: Traversable[X]): Chain[X] = {
        if (other.isEmpty)
            return this;

        val that = other.foldLeft(new Chain.ChainBuilder[X])(_ += _).result
        if (this.isEmpty)
            that
        else {
            val (head, last) = copy[X]()
            last.rest = that
            head
        }
    }

    /**
     * Takes the first n elements of this list. If this list does not contain at
     * least n elements an IllegalStateException  will be thrown.
     * @param n    An int value in the range [0...this.size].
     * @return     A list consisting of the first n value.
     */
    def take(n: Int): Chain[T]

    /**
     * Takes up to the first n elements of this list. The returned list will contain at most
     * `this.size` elements.
     * @param n    An int value euqal or larger than 0.
     * @return     A list consisting of the first n value.
     */
    def takeUpTo(n: Int): Chain[T]

    def takeWhile(f: T ⇒ Boolean): Chain[T]

    def filter(f: T ⇒ Boolean): Chain[T]

    def filterNot(f: T ⇒ Boolean): Chain[T] = filter(t ⇒ !f(t))

    def drop(n: Int): Chain[T]

    def dropWhile(f: T ⇒ Boolean): Chain[T] = {
        var rest = this
        while (rest.nonEmpty && f(rest.head)) { rest = rest.tail }
        rest
    }

    def zip[X](other: GenIterable[X]): Chain[(T, X)] = {
        if (this.isEmpty)
            return this.asInstanceOf[Naught.type];
        val otherIt = other.iterator
        if (!otherIt.hasNext)
            return Naught;

        var thisIt = this.tail
        val result: :&:[(T, X)] = new :&:((this.head, otherIt.next), Naught)
        var last = result
        while (thisIt.nonEmpty && otherIt.hasNext) {
            val newLast = new :&:((thisIt.head, otherIt.next), Naught)
            last.rest = newLast
            last = newLast
            thisIt = thisIt.tail
        }
        result
    }

    def zip[X](other: Chain[X]): Chain[(T, X)] = {
        if (this.isEmpty)
            return this.asInstanceOf[Naught.type];
        if (other.isEmpty)
            return other.asInstanceOf[Naught.type];

        var thisIt = this.tail
        var otherIt = other.tail
        val result: :&:[(T, X)] = new :&:((this.head, other.head), Naught)
        var last = result
        while (thisIt.nonEmpty && otherIt.nonEmpty) {
            val newLast = new :&:((thisIt.head, otherIt.head), Naught)
            last.rest = newLast
            last = newLast
            thisIt = thisIt.tail
            otherIt = otherIt.tail
        }
        result
    }

    def zipWithIndex: Chain[(T, Int)] = {
        var index = 0
        map[(T, Int), Chain[(T, Int)]] { e ⇒
            val currentIndex = index
            index += 1
            (e, currentIndex)
        }
    }

    /**
     * @see    `merge`
     */
    def corresponds[X](other: Chain[X])(f: (T, X) ⇒ Boolean): Boolean = {
        if (this.isEmpty)
            return other.isEmpty;
        if (other.isEmpty)
            return false;
        // both lists have at least one element...
        if (!f(this.head, other.head))
            return false;

        var thisIt = this.tail
        var otherIt = other.tail
        while (thisIt.nonEmpty && otherIt.nonEmpty) {
            if (!f(thisIt.head, otherIt.head))
                return false;
            thisIt = thisIt.tail
            otherIt = otherIt.tail
        }
        thisIt.isEmpty && otherIt.isEmpty
    }

    def mapConserve[X >: T <: AnyRef](f: T ⇒ X): Chain[X]

    def reverse: Chain[T]

    override def mkString: String = mkString("", "", "")

    override def mkString(pre: String, sep: String, post: String): String = {
        val result = new StringBuilder(pre)
        var rest = this
        if (rest.nonEmpty) {
            result.append(head)
            rest = rest.tail
            while (rest.nonEmpty) {
                result.append(sep)
                result.append(rest.head.toString)
                rest = rest.tail
            }
        }

        result.append(post)
        result.toString
    }

    override def toIterable: Iterable[T] = {
        new AbstractIterable[T] { def iterator: Iterator[T] = self.toIterator }
    }

    def toIterator: Iterator[T] = {
        new AbstractIterator[T] {
            private var rest = self
            def hasNext: Boolean = rest.nonEmpty
            def next(): T = {
                val result = rest.head
                rest = rest.tail
                result
            }
        }
    }

    def mapToIntIterator(f: T ⇒ Int): IntIterator = {
        new IntIterator {
            private var rest = self
            def hasNext: Boolean = rest.nonEmpty
            def next(): Int = {
                val result = f(rest.head)
                rest = rest.tail
                result
            }
        }
    }

    /**
     * Returns a newly created `Traversable[T]` collection.
     */
    def toTraversable: Traversable[T] = {
        new Traversable[T] { def foreach[U](f: T ⇒ U): Unit = self.foreach(f) }
    }

    def toIntArraySet(implicit ev: T <:< Int): IntArraySet = {
        foldLeft(new IntArraySetBuilder())(_ += _).result()
    }

    def toIntTrieSet(implicit ev: T <:< Int): IntTrieSet = {
        // foldLeft(EmptyIntTrieSet: IntTrieSet)(_ + _)
        var set: IntTrieSet = EmptyIntTrieSet
        var rest = this
        while (rest ne Naught) {
            set += rest.head
            rest = rest.tail
        }
        set
    }

    def toStream: Stream[T] = toTraversable.toStream

    def copyToArray[B >: T](xs: Array[B], start: Int, len: Int): Unit = {
        val max = xs.length
        var copied = 0
        var rest = this
        while (copied < len && start + copied < max && rest.nonEmpty) {
            xs(start + copied) = rest.head
            copied += 1
            rest = rest.tail
        }
    }

    /**
     * Merges this chain with the given chain by merging the values using the given function.
     * If all results are the same (reference equality) as this chain's elements then the result
     * will be `this`. Otherwise, only the tail that is identical will be kept.
     *
     * @param     other A chain with the same number of elements as this chain. If the size of
     *            the chains it not equal, the result is undefined.
     */
    def merge[X <: AnyRef, Z >: T <: AnyRef](that: Chain[X])(f: (T, X) ⇒ Z): Chain[Z]

    /**
     * Fuses this chain with the given chain by fusing the values using the given function.
     * The function `onDiff` is only called if the given list's element and this list's
     * element differ. Hence, when the tail of both lists is equal fusing both lists
     * will terminate immediately and the common tail is attached to the new heading.
     *
     * @param     other A chain with the same number of elements as this chain. If the size of
     *            the chains it not equal, the result is undefined.
     */
    def fuse[X >: T <: AnyRef](that: Chain[X], onDiff: (T, X) ⇒ X): Chain[X]
}

//trait ChainLowPriorityImplicits

/**
 * Factory for [[Chain]]s.
 *
 * @author Michael Eichberg
 */
object Chain /* extends ChainLowPriorityImplicits */ {

    /**
     * Builder for [[Chain]]s. The builder is specialized for the primitive
     * type `Int` to enable the creation of new instances of the correspondingly
     * specialized list.
     *
     * @note     The builder must not be used after a `result` call.
     *
     * @tparam T The type of the list's element.
     */
    class ChainBuilder[@specialized(Int) T] extends Builder[T, Chain[T]] {
        private[this] var list: Chain[T] = null
        private[this] var last: :&:[T] = null
        def +=(elem: T): this.type = {
            val newLast = new :&:[T](elem, Naught)
            if (list == null) {
                list = newLast
            } else {
                last.rest = newLast
            }
            last = newLast
            this
        }
        def clear(): Unit = list = null

        /** Returns the constructed list. The builder must not be used afterwards. */
        def result(): Chain[T] = { val list = this.list; if (list == null) Naught else list }
    }

    private[this] val baseCanBuildFrom = new CanBuildFrom[Chain[_], AnyRef, Chain[AnyRef]] {
        def apply(from: Chain[_]) = new ChainBuilder[AnyRef]
        def apply() = new ChainBuilder[AnyRef]
    }
    implicit def canBuildFrom[A <: AnyRef]: CanBuildFrom[Chain[_], A, Chain[A]] = {
        baseCanBuildFrom.asInstanceOf[CanBuildFrom[Chain[_], A, Chain[A]]]
    }
    private[this] val specializedCanBuildFrom = new CanBuildFrom[Chain[_], Int, Chain[Int]] {
        def apply(from: Chain[_]) = new ChainBuilder[Int]
        def apply() = new ChainBuilder[Int]
    }
    implicit def canBuildIntChainFrom: CanBuildFrom[Chain[_], Int, Chain[Int]] = {
        specializedCanBuildFrom
    }

    val GenericSpecializedCBF = new CanBuildFrom[Any, Int, Chain[Int]] {
        def apply(from: Any) = new ChainBuilder[Int]
        def apply() = new ChainBuilder[Int]
    }

    implicit def toTraversable[T](cl: Chain[T]): Traversable[T] = cl.toIterable

    def newBuilder[T](implicit t: scala.reflect.ClassTag[T]): ChainBuilder[T] = {
        if (t.runtimeClass == classOf[Int])
            new ChainBuilder[Int].asInstanceOf[ChainBuilder[T]]
        else
            new ChainBuilder[T]
    }

    final val IncompleteEmptyChain = new IncompleteCollection(Naught: Chain[Nothing])

    final val CompleteEmptyChain = new CompleteCollection(Naught: Chain[Nothing])

    /**
     * Returns an empty list.
     *
     * @note    In general it is preferable to directly use [[Naught]].
     */
    def empty[T]: Chain[T] = Naught

    def singleton[@specialized(Int) T](e: T): Chain[T] = new :&:[T](e, Naught)

    /**
     * @note     The recommended way to create a Chain with one element is to
     *           use the `singleton` method.
     */
    def apply[@specialized(Int) T](es: T*): Chain[T] = {
        val naught = Naught
        if (es.isEmpty)
            return naught;
        val result = new :&:[T](es.head, naught)
        var last = result
        val it = es.iterator
        it.next // es is non-empty
        it foreach { e ⇒
            val newLast = new :&:[T](e, naught)
            last.rest = newLast
            last = newLast
        }
        result
    }

}

/**
 * An empty [[Chain]]s.
 *
 * @author Michael Eichberg
 */
case object Naught extends Chain[Nothing] {

    private def listIsEmpty = new NoSuchElementException("the list is empty")

    def head: Nothing = throw listIsEmpty
    def headOption: Option[Nothing] = None
    def tail: Nothing = throw listIsEmpty
    def isEmpty: Boolean = true
    def isSingletonList: Boolean = false
    def hasMultipleElements: Boolean = false
    override def nonEmpty: Boolean = false
    def :&::[X >: Nothing](x: Chain[X]): Chain[X] = x
    def take(n: Int): Naught.type = { if (n == 0) this else throw listIsEmpty }
    def takeUpTo(n: Int): this.type = this
    def takeWhile(f: Nothing ⇒ Boolean): Chain[Nothing] = this
    def filter(f: Nothing ⇒ Boolean): Chain[Nothing] = this
    def drop(n: Int): Naught.type = { if (n == 0) this else throw listIsEmpty }
    def mapConserve[X >: Nothing <: AnyRef](f: Nothing ⇒ X): Chain[X] = this
    def reverse: Chain[Nothing] = this

    def merge[X <: AnyRef, Z >: Nothing <: AnyRef](
        that: Chain[X]
    )(
        f: (Nothing, X) ⇒ Z
    ): Chain[Z] = this

    def fuse[X >: Nothing <: AnyRef](that: Chain[X], onDiff: (Nothing, X) ⇒ X): Chain[X] = this
}

/**
 * An container for a list element.
 *
 * @author Michael Eichberg
 */
final case class :&:[@specialized(Int) T](
        head:                    T,
        private[opalj] var rest: Chain[T] = Naught
) extends Chain[T] {

    def headOption: Option[T] = Some(head)

    def tail: Chain[T] = rest

    def isSingletonList: Boolean = rest eq Naught

    def hasMultipleElements: Boolean = rest ne Naught

    def isEmpty: Boolean = false

    override def nonEmpty: Boolean = true

    // prepends the given list... to make sure that
    // we keep the specialization we have to ask the
    // other list to append this one...
    def :&::[X >: T](x: Chain[X]): Chain[X] = {
        x match {
            case Naught        ⇒ this
            case other: :&:[X] ⇒ other ++ this
        }
    }

    def take(n: Int): Chain[T] = {
        val Nil = Naught

        if (n == 0)
            return Nil;

        var taken = 1
        val result = new :&:[T](head, Nil)
        var last = result
        var rest: Chain[T] = this.rest
        while (taken < n) {
            val x = rest.head
            rest = rest.tail
            val newLast = new :&:[T](x, Nil)
            last.rest = newLast
            last = newLast
            taken += 1
        }
        result
    }

    def takeUpTo(n: Int): Chain[T] = {
        val Nil = Naught

        if (n == 0)
            return Nil;

        var taken = 1
        val result = new :&:[T](head, Nil)
        var last = result
        var rest: Chain[T] = this.rest
        while (taken < n && rest.nonEmpty) {
            val x = rest.head
            rest = rest.tail
            val newLast = new :&:[T](x, Nil)
            last.rest = newLast
            last = newLast
            taken += 1
        }
        result

    }

    def takeWhile(f: T ⇒ Boolean): Chain[T] = {
        val head = this.head
        val Nil = Naught

        if (!f(head))
            return Nil;

        val result = new :&:(head, Nil)
        var last = result
        var rest: Chain[T] = this.rest
        while (rest.nonEmpty && f(rest.head)) {
            val x = rest.head
            rest = rest.tail
            val newLast = new :&:[T](x, Nil)
            last.rest = newLast
            last = newLast
        }
        result
    }

    def filter(f: T ⇒ Boolean): Chain[T] = {
        val Nil = Naught

        var result: Chain[T] = Nil
        var last = result
        var rest: Chain[T] = this
        do {
            val x = rest.head
            rest = rest.tail
            if (f(x)) {
                val newLast = new :&:[T](x, Nil)
                if (last.nonEmpty) {
                    last.asInstanceOf[:&:[T]].rest = newLast
                } else {
                    result = newLast
                }
                last = newLast
            }
        } while (rest.nonEmpty)
        result
    }

    def drop(n: Int): Chain[T] = {
        if (n == 0)
            return this;

        var dropped = 1
        var result: Chain[T] = this.rest
        while (dropped < n) {
            dropped += 1
            result = result.tail
        }
        result
    }

    def mapConserve[X >: T <: AnyRef](f: T ⇒ X): Chain[X] = {
        val head = this.head
        val newHead = f(head)
        var updated = (head.asInstanceOf[AnyRef] ne newHead)
        val result = new :&:[X](newHead, Naught)
        var last = result
        var rest: Chain[T] = this.rest
        while (rest.nonEmpty) {
            val e = rest.head
            val x = f(e)
            updated = updated || (x ne e.asInstanceOf[AnyRef])
            rest = rest.tail
            val newLast = new :&:[X](x, Naught)
            last.rest = newLast
            last = newLast
        }
        if (updated)
            result
        else
            this
    }

    def reverse: Chain[T] = {
        var result: Chain[T] = new :&:[T](head, Naught)
        var rest = this.rest
        while (rest.nonEmpty) {
            // NOTE: WE CAN'T USE THE STANDARD :&: OPERATOR
            // BECAUSE WE WOULD LOOSE THE SPECIALIZATION OF THE LIST!
            // DOESN'T WORK: result :&:= rest.head
            result = new :&:[T](rest.head, result)
            rest = rest.tail
        }
        result
    }

    /**
     * @note    The `merge` function first calls the given function and then checks if the
     *             result is reference equal to the element of the first list while `fuse` first
     *             checks the reference equality of the members before it calls the given function.
     *             Therefore `fuse` can abort checking all further values when the
     *             remaining list fragments are reference equal because both lists are immutable.
     *             In other words: `fuse` is an optimized version of `merge` where the function `f`
     *             has the following shape: `(x,y) => if(x eq y) x else /*whatever*/`.
     */
    def fuse[X >: T <: AnyRef](
        that:   Chain[X],
        onDiff: (T, X) ⇒ X
    ): Chain[X] = {

        var thisHead: Chain[T] = this
        var thatHead: Chain[X] = that

        var equalHead: Chain[X] = null

        var newHead: :&:[X] = null
        var newLast: :&:[X] = null
        def appendToNewLast(t: X): Unit = {
            if (newLast eq null) {
                newLast = new :&:[X](t, Naught)
                newHead = newLast
            } else {
                val e = new :&:[X](t, Naught)
                newLast.rest = e
                newLast = e
            }
        }

        do {
            val thisValue: T = thisHead.head
            val thatValue: X = thatHead.head

            if (thatValue eq thisValue.asInstanceOf[AnyRef]) {
                if (equalHead eq null) equalHead = thisHead
            } else {
                val mergedValue: X = onDiff(thisValue, thatValue)
                if (mergedValue eq thisValue.asInstanceOf[AnyRef]) {
                    if (equalHead eq null) equalHead = thisHead
                } else {
                    if (equalHead ne null) {
                        // we have to clone all elements in the range [equalNode...thisHead)
                        // to make it possible to attach a new element.
                        appendToNewLast(equalHead.head)
                        equalHead = equalHead.tail
                        while (equalHead ne thisHead) {
                            appendToNewLast(equalHead.head)
                            equalHead = equalHead.tail
                        }
                        equalHead = null
                    }
                    appendToNewLast(mergedValue)
                }
            }
            thisHead = thisHead.tail
            thatHead = thatHead.tail
        } while (thisHead.nonEmpty && (thisHead ne thatHead))

        if (newHead eq null) {
            this // or equalHead
        } else if (equalHead ne null) {
            newLast.rest = equalHead
            newHead
        } else if (thisHead.nonEmpty) {
            newLast.rest = thisHead
            newHead
        } else {
            newHead
        }
    }

    def merge[X <: AnyRef, Z >: T <: AnyRef](
        that: Chain[X]
    )(
        f: (T, X) ⇒ Z
    ): Chain[Z] = {
        // The idea: iterate over both lists in parallel, when the merge results in the
        // same value as this list's value, then we do not create a new list element, but
        // instead store this information and otherwise wait until we see a change.
        var thisHead: Chain[T] = this
        var thatHead: Chain[X] = that

        var equalHead: Chain[Z] = null

        var newHead: :&:[Z] = null
        var newLast: :&:[Z] = null
        def appendToNewLast(t: Z): Unit = {
            if (newLast eq null) {
                newLast = new :&:[Z](t, Naught)
                newHead = newLast
            } else {
                val e = new :&:[Z](t, Naught)
                newLast.rest = e
                newLast = e
            }
        }

        do {
            val thisValue: T = thisHead.head
            val thatValue: X = thatHead.head

            val mergedValue: Z = f(thisValue, thatValue)
            if (mergedValue eq thisValue.asInstanceOf[AnyRef]) {
                if (equalHead eq null) {
                    equalHead = thisHead
                }
            } else {
                if (equalHead ne null) {
                    // we have to clone all elements in the range [equalNode...thisHead)
                    // to make it possible to attach a new element.
                    appendToNewLast(equalHead.head)
                    equalHead = equalHead.tail
                    while (equalHead ne thisHead) {
                        appendToNewLast(equalHead.head)
                        equalHead = equalHead.tail
                    }
                    equalHead = null
                }
                appendToNewLast(mergedValue)
            }
            thisHead = thisHead.tail
            thatHead = thatHead.tail
        } while (thisHead.nonEmpty)

        if (newHead eq null) {
            this // or equalHead
        } else if (equalHead ne null) {
            newLast.rest = equalHead
            newHead
        } else
            newHead
    }

    override def toString: String = {
        //s"$head :&: ${rest.toString}" // cannot handle very long lists (uses recursion)...
        mkString("", " :&: ", " :&: Naught")
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy