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

org.opalj.collection.immutable.ConstArray.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.reflect.ClassTag

import java.util.{Arrays ⇒ JArrays}
import java.lang.System.arraycopy

import scala.collection.IndexedSeqOptimized
import scala.collection.generic.CanBuildFrom
import scala.collection.mutable.Builder
import scala.collection.mutable.ArrayBuffer

import org.opalj.control.{find ⇒ findInArray}

/**
 * Wraps an array such that the underlying array is no longer directly accessible and
 * therefore also no longer mutable if `ConstArray` is the sole owner.
 *
 * @author Michael Eichberg
 */
final class ConstArray[T <: AnyRef] private (
        private val data: Array[T]
) extends IndexedSeq[T] with IndexedSeqOptimized[T, ConstArray[T]] {

    // Required to ensure that "map" creates a ConstArray whenever possible.
    override def newBuilder: Builder[T, ConstArray[T]] = ConstArray.newBuilder[T]()

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

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

    override def iterator: RefIterator[T] = new RefIterator[T] {
        private[this] var i = 0
        override def hasNext: Boolean = i < data.length
        override def next(): T = {
            val e = data(i)
            i += 1
            e
        }
    }

    /**
     * Creates a new `ConstArray` where the value at the given index is replaced by the given value.
     */
    def replaced(index: Int, e: T): ConstArray[T] = {
        val newData = JArrays.copyOf(data, data.length)
        newData(index) = e
        new ConstArray(newData)
    }

    def binarySearch(key: Comparable[T]): Int = {
        JArrays.binarySearch(data.asInstanceOf[Array[Object]], 0, data.length, key)
    }

    /**
     * Creates a new `ConstArray` where the given value is inserted at the specified
     * `insertionPoint`. If the underlying array happens to be sorted, then the insertion point can
     * easily be computed using `binarySearch`; it will be `-index -1` if the
     * returned index is less than zero.
     */
    def insertAt(insertionPoint: Int, e: T): ConstArray[T] = {
        val newData = JArrays.copyOf(data, data.length + 1)
        newData(insertionPoint) = e
        arraycopy(data, insertionPoint, newData, insertionPoint + 1, data.length - insertionPoint)
        new ConstArray(newData)
    }

    override def equals(other: Any): Boolean = {
        other match {
            case that: IndexedSeq[_] ⇒
                this.length == that.length && {
                    val thisIt = this.toIterator
                    val thatIt = that.toIterator
                    while (thisIt.hasNext && thisIt.next == thatIt.next) { /*continue*/ }
                    !thisIt.hasNext // <=> all elements are equal
                }
            case _ ⇒
                false
        }
    }

    override def canEqual(that: Any): Boolean = that.isInstanceOf[IndexedSeq[T]]

    override lazy val hashCode: Int = JArrays.hashCode(data.asInstanceOf[Array[Object]]) * 11

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

}

/*
/**
 * Low level implicits to; e.g., enable a mapping of an ''arbitrary'' data structure to
 * a [[ConstArray]].
 *
 * @example {{{ val c : ConstArray[List[String]] = List("a","b").map(List(_))}}}
 */
trait LowLevelConstArrayImplicits {

    implicit def canBuildFromAnything[T <: AnyRef, X, CC[X]]: CanBuildFrom[CC[_], T, ConstArray[T]] =
        new CanBuildFrom[CC[_], T, ConstArray[T]] {
            def apply(): Builder[T, ConstArray[T]] = ConstArray.newBuilder[T]()
            def apply(from: CC[_]): Builder[T, ConstArray[T]] = ConstArray.newBuilder[T]()
        }

}
*/

/**
 * Factory for [[ConstArray]]s.
 */
object ConstArray /*extends LowLevelConstArrayImplicits*/ {

    def newBuilder[T <: AnyRef](sizeHint: Int = 8): Builder[T, ConstArray[T]] = {
        val builder = new ArrayBuffer[T](sizeHint)
        builder mapResult (r ⇒ ConstArray(r.toArray[Object].asInstanceOf[Array[T]]))
    }

    implicit def canBuildFrom[T <: AnyRef]: CanBuildFrom[ConstArray[_ <: AnyRef], T, ConstArray[T]] = {
        new CanBuildFrom[ConstArray[_], T, ConstArray[T]] {
            def apply(): Builder[T, ConstArray[T]] = newBuilder[T]()
            def apply(from: ConstArray[_]): Builder[T, ConstArray[T]] = newBuilder[T](from.size)
        }
    }

    // TODO rename binarySearch
    def find[T <: AnyRef](sortedConstArray: ConstArray[T])(evaluate: T ⇒ Int): Option[T] = {
        findInArray(sortedConstArray.data)(evaluate)
    }

    def empty[T <: AnyRef: ClassTag]: ConstArray[T] = new ConstArray[T](new Array[T](0))

    def apply[T <: AnyRef: ClassTag](data: T*): ConstArray[T] = new ConstArray(data.toArray)

    /**
     * Creates a new [[ConstArray]] by cloning the given array.
     *
     * I.e., modifications to the given array will not be reflected.
     */
    def apply[T <: AnyRef](data: Array[T]): ConstArray[T] = new ConstArray(data.clone())

    /**
     * Creates a new [[ConstArray]] 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 ConstArray takes over the ownership of the array.
    def _UNSAFE_from[T <: AnyRef](data: Array[T]): ConstArray[T] = new ConstArray(data)

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy