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

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

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

import java.util.{Arrays ⇒ JArrays}

import scala.collection.AbstractIterator
import scala.collection.mutable.Builder

/**
 * Wraps an array such that the underlying array is no longer directly accessible and
 * therefore also no longer mutable.
 *
 * @author Michael Eichberg
 */
class IntArray private (
        private val data: Array[Int]
) extends scala.collection.immutable.Seq[Int] {

    /**
     * Directly performs the map operation on the underlying array and then creates a new
     * appropriately typed `RefArray[X]` object which wraps the modified array.
     *
     * '''This method is only to be used if `this` instance is no longer used afterwards!'''
     */
    // IMPROVE Design annotation (+Analysis) that ensures that this operation is only performed if – after the usage of this method - the reference to this data-structure will not be used anymore.
    def _UNSAFE_map(f: Int ⇒ Int): this.type = {
        var i = 0
        val max = data.length
        while (i < max) {
            data(i) = f(data(i))
            i += 1
        }
        this
    }

    /**
     * Directly updates the value at the given index and then creates a new
     * appropriately typed `RefArray[X]` object which wraps the modified array.
     *
     * '''This method is only to be used if `this` instance is no longer used afterwards!'''
     */
    // IMPROVE Design annotation (+Analysis) that ensures that this operation is only performed if – after the usage of this method - the reference to this data-structure will not be used anymore.
    def _UNSAFE_replace(index: Int, e: Int): this.type = {
        data(index) = e
        this
    }

    def apply(idx: Int): Int = data(idx)

    def map[X <: AnyRef](f: Int ⇒ X): RefArray[X] = {
        val newData = new Array[AnyRef](data.length)
        var i = 0
        val max = data.length
        while (i < max) {
            newData(i) = f(data(i))
            i += 1
        }
        RefArray._UNSAFE_from[X](newData)
    }

    def map(f: Int ⇒ Int): IntArray = {
        val newData = new Array[Int](data.length)
        var i = 0
        val max = data.length
        while (i < max) {
            newData(i) = f(data(i))
            i += 1
        }
        new IntArray(newData)
    }

    def flatMap[X <: AnyRef](f: Int ⇒ TraversableOnce[X]): RefArray[X] = {
        val b = RefArray.newBuilder[X]
        var i = 0
        val max = data.length
        b.sizeHint(max)
        while (i < max) {
            b ++= f(data(i))
            i += 1
        }
        b.result()
    }

    def flatMap(f: Int ⇒ TraversableOnce[Int]): IntArray = {
        val b = IntArray.newBuilder
        var i = 0
        val max = data.length
        b.sizeHint(max)
        while (i < max) {
            b ++= f(data(i))
            i += 1
        }
        b.result()
    }

    @inline final def sorted: IntArray = {
        val newData = data.clone
        JArrays.parallelSort(newData)
        new IntArray(newData)
    }

    /**
     * Checks if the given element is stored in the array. Performs a linear sweep of the array
     * (complexity O(N)).
     * If the array happens to be sorted, consider using `binarySearch`.
     */
    def contains(v: Int): Boolean = {
        val data = this.data
        val max = data.length
        var i = 0
        while (i < max) {
            if (data(i) == v) {
                return true;
            }
            i += 1
        }
        false
    }

    override def isEmpty: Boolean = data.length == 0
    override def nonEmpty: Boolean = data.length > 0

    override def size: Int = data.length
    override def length: Int = data.length

    override def head: Int = {
        if (nonEmpty)
            data(0)
        else
            throw new NoSuchElementException
    }

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

    /** Appends the given element. */
    def :+(elem: Int): IntArray = {
        val newData = JArrays.copyOf(data, data.length + 1)
        newData(data.length) = elem
        new IntArray(newData)
    }

    def intIterator: IntIterator = new IntIterator {
        private[this] var i = 0
        override def hasNext: Boolean = i < data.length
        override def next(): Int = { val e = data(i); i += 1; e }
    }

    /** Do consider using IntIterator to avaoid (un)boxing operations! */
    override def iterator: Iterator[Int] = new AbstractIterator[Int] {
        private[this] var i = 0
        override def hasNext: Boolean = i < data.length
        override def next(): Int = { val e = data(i); i += 1; e }
    }

    override def filter(f: Int ⇒ Boolean): IntArray = {
        val b = IntArray.newBuilder
        val data = this.data
        val max = data.length
        b.sizeHint(Math.min(8, max))
        var i = 0
        while (i < max) {
            val e = data(i)
            if (f(e)) {
                b += e
            }
            i += 1
        }
        b.result()
    }

    override def filterNot(f: Int ⇒ Boolean): IntArray = filter(e ⇒ !f(e))

    /**
     * Creates a new `IntArray` where the value at the given index is replaced by
     * the given value.
     */
    def replaced(index: Int, e: Int): IntArray = {
        val newData = java.util.Arrays.copyOf(data, data.length)
        newData(index) = e
        new IntArray(newData)
    }

    override def equals(other: Any): Boolean = {
        other match {
            case that: IntArray ⇒ JArrays.equals(this.data, that.data)
            case _ ⇒
                false
        }
    }

    override lazy val hashCode: Int = JArrays.hashCode(data) * 11

    override def toString: String = data.mkString("RefArray(", ", ", ")")

}

/**
 * Factory for [[IntArray]]s.
 */
object IntArray {

    def newBuilder: Builder[Int, IntArray] = {
        new Builder[Int, IntArray] {
            private[this] var data: Array[Int] = null
            private[this] var i = 0
            override def +=(e: Int): this.type = {
                if (data == null) {
                    data = new Array[Int](8)
                } else if (i == data.length) {
                    data = JArrays.copyOf(data, (i + 1) * 2)
                }
                data(i) = e
                i += 1
                this
            }
            override def clear(): Unit = i = 0
            override def result(): IntArray = {
                if (data == null)
                    empty
                else
                    new IntArray(
                        if (i == data.length)
                            data
                        else
                            JArrays.copyOf(data, i)
                    )
            }
            override def sizeHint(size: Int): Unit = {
                if (data == null) data = new Array[Int](size)
            }
        }
    }

    val EmptyArrayOfInt = new Array[Int](0)
    val Empty: IntArray = new IntArray(EmptyArrayOfInt)

    def empty: IntArray = Empty

    def apply(data: Int*): IntArray = new IntArray(data.toArray[Int])

    def unapplySeq(x: IntArray): Option[Seq[Int]] = Some(x)

    /**
     * Creates a new [[IntArray]] by cloning the given array.
     *
     * I.e., modifications to the given array will not be reflected.
     */
    def apply(data: Array[Int]): IntArray = {
        new IntArray(data.clone())
    }

    def from[T](data: Traversable[T])(f: T ⇒ Int): IntArray = {
        val max = data.size
        val it = data.toIterator
        val newData = new Array[Int](max)
        var i = 0; while (i < max) { newData(i) = f(it.next()); i += 1 }
        new IntArray(newData)
    }

    /**
     * Creates a new [[RefArray]] from the given array. Hence, changes to the
     * underlying array would be reflected!
     *
     * '''Only use this factory method if you have full control over all
     * aliases to the given array to ensure that the underlying array is not mutated.'''
     */
    // IMPROVE Use an ownership annotation to specify that RefArray takes over the ownership of the array.
    def _UNSAFE_from(data: Array[Int]): IntArray = new IntArray(data)

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy