
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