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

org.opalj.collection.mutable.IntArrayStack.scala Maven / Gradle / Ivy

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

import scala.collection.mutable
import scala.collection.generic

/**
 * An array based implementation of a mutable stack of `int` values which has a
 * given initial size. If the stack is non-empty, the index of the top value is `0` and the
 * index of the bottom value is (`length-1`).
 *
 * @param data The array containing the values.
 * @param size0 The number of stored values.
 * @author Michael Eichberg
 */
final class IntArrayStack private (
        private var data:  Array[Int],
        private var size0: Int
) extends mutable.IndexedSeq[Int]
    with mutable.IndexedSeqLike[Int, IntArrayStack]
    with mutable.Cloneable[IntArrayStack]
    with Serializable { stack ⇒

    def this(initialSize: Int = 4) { this(new Array[Int](initialSize), 0) }

    override def size: Int = size0
    override def length: Int = size0
    override def isEmpty: Boolean = size0 == 0
    override def nonEmpty: Boolean = size0 > 0

    override def apply(index: Int): Int = {
        val size0 = this.size0
        val valueIndex = size0 - 1 - index
        if (valueIndex < 0 || valueIndex >= size0)
            throw new IndexOutOfBoundsException(s"$index (size: $size0)");

        data(valueIndex)
    }

    override def update(index: Int, v: Int): Unit = data(size0 - 1 - index) = v

    override def newBuilder: mutable.Builder[Int, IntArrayStack] = IntArrayStack.newBuilder

    override def reverse: IntArrayStack = {
        val newData = new Array[Int](size0)
        val max = size0 - 1
        var i = 0
        while (i <= max) {
            newData(max - i) = data(i)
            i += 1
        }
        new IntArrayStack(newData, size0)
    }

    /** The same as push but additionally returns `this`. */
    def +=(i: Int): this.type = {
        push(i)
        this
    }

    def push(i: Int): Unit = {
        val size0 = this.size0
        var data = this.data
        if (data.length == size0) {
            val newData = new Array[Int]((size0 + 1) * 2)
            System.arraycopy(data, 0, newData, 0, size0)
            data = newData
            this.data = newData
        }

        data(size0) = i
        this.size0 = size0 + 1
    }

    /**
     * Pushes the value of the given stack on this stack while maintaining the order
     * in which the values were pushed on the given stack. I.e.,
     * if this contains the values `[1|2->` and the given one the values `[3,4->`
     * then the resulting stack will contain the values `[1|2|3|4...`.
     *
     * @note In case of `++` the order of the values is reversed.
     */
    def push(that: IntArrayStack): Unit = {
        val thatSize = that.size0

        if (thatSize == 0) {
            return ;
        }

        val thisSize = this.size0
        var thisData = this.data

        val newSize = thisSize + thatSize
        if (newSize > thisData.length) {
            val newData = new Array[Int](newSize + 10)
            System.arraycopy(thisData, 0, newData, 0, thisSize)
            thisData = newData
            this.data = thisData
        }

        System.arraycopy(that.data, 0, thisData, thisSize, thatSize)

        this.size0 = newSize
    }

    /**
     * Returns and removes the top most value from the stack.
     *
     * @note If the stack is empty a `NoSuchElementException` will be thrown.
     */
    def pop(): Int = {
        val index = this.size0 - 1
        if (index < 0)
            throw new NoSuchElementException("the stack is empty");

        val i = this.data(index)
        this.size0 = index
        i
    }

    /**
     * Returns the stack's top-most value.
     *
     * @note If the stack is empty a `NoSuchElementException` will be thrown.
     */
    def top(): Int = {
        val index = this.size0 - 1
        if (index < 0)
            throw new NoSuchElementException("the stack is empty");

        this.data(index)
    }

    /**
     * Same as `top()`, but potentially less efficient due to (un)boxing if the head method
     * of the supertype is called.
     */
    override /*TraversableLike*/ def head: Int = top()

    override /*TraversableLike*/ def last: Int = {
        if (this.size0 == 0)
            throw new NoSuchElementException("the stack is empty");

        this.data(0)
    }

    override def foreach[U](f: Int ⇒ U): Unit = {
        val data = this.data
        var i = this.size0 - 1
        while (i >= 0) {
            f(data(i))
            i -= 1
        }
    }

    def foreachReverse[U](f: Int ⇒ U): Unit = {
        val data = this.data
        val max = this.size0 - 1
        var i = 0
        while (i <= max) {
            f(data(i))
            i += 1
        }
    }

    override def foldLeft[B](z: B)(f: (B, Int) ⇒ B): B = {
        val data = this.data
        var v = z
        var i = this.size0 - 1
        while (i >= 0) {
            v = f(v, data(i))
            i -= 1
        }
        v
    }

    /**
     * Returns an iterator which produces the values in LIFO order.
     *
     * @note    The `next` method will throw an `IndexOutOfBoundsException`
     *          when all elements are already returned.
     */
    override def iterator: IntIterator = new IntIterator {
        var currentIndex = stack.size0 - 1
        def hasNext: Boolean = currentIndex >= 0

        def next(): Int = {
            val currentIndex = this.currentIndex
            val r = stack.data(currentIndex)
            this.currentIndex = currentIndex - 1
            r
        }

    }

    def toArray: Array[Int] = java.util.Arrays.copyOfRange(data, 0, size0)

    override def clone(): IntArrayStack = new IntArrayStack(data.clone(), size0)

    override def toString: String = {
        s"IntArrayStack(/*size=$size0;*/data=${data.take(size0).mkString("[", ",", "→")})"
    }
}

/**
 * Factory to create [[IntArrayStack]]s.
 */
object IntArrayStack {

    implicit def canBuildFrom: generic.CanBuildFrom[IntArrayStack, Int, IntArrayStack] = {
        new generic.CanBuildFrom[IntArrayStack, Int, IntArrayStack] {
            def apply(): mutable.Builder[Int, IntArrayStack] = newBuilder
            def apply(from: IntArrayStack): mutable.Builder[Int, IntArrayStack] = newBuilder
        }
    }

    def newBuilder: mutable.Builder[Int, IntArrayStack] = {
        new mutable.ArrayBuffer[Int] mapResult fromSeq
    }

    /**
     * Creates a new stack based on a given sequence. The last value of the sequence will
     * be the top value of the stack.
     */
    def fromSeq(seq: TraversableOnce[Int]): IntArrayStack = {
        seq.foldLeft(new IntArrayStack(8))(_ += _)
    }

    def apply(value: Int): IntArrayStack = {
        val initialArray = new Array[Int](10)
        initialArray(0) = value
        new IntArrayStack(initialArray, 1)
    }

    def empty: IntArrayStack = new IntArrayStack
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy