Skip to content

Instantly share code, notes, and snippets.

@thibseisel
Created February 7, 2018 21:37
Show Gist options
  • Save thibseisel/5dcf569aff9ce43cda5497b426e72bb0 to your computer and use it in GitHub Desktop.
Save thibseisel/5dcf569aff9ce43cda5497b426e72bb0 to your computer and use it in GitHub Desktop.
An IntArrayList implementation based on the original ArrayList written in Kotlin
package com.github.thibseisel.kblock.utils
import java.util.*
/**
* Default initial capacity.
*/
private const val DEFAULT_CAPACITY = 10
/**
* The maximum size of array to allocate.
* Some VMs reserve some header words in an array.
* Attempt to allocate larger arrays may result in `OutOfMemoryError`s.
*/
private const val MAX_ARRAY_SIZE = Int.MAX_VALUE - 8
/**
* Shared empty array instance used for empty instances.
*/
private val EMPTY_ELEMENT_DATA = IntArray(0)
/**
* Shared empty array instance used for default sized empty instances.
* We distinguish this from [EMPTY_ELEMENT_DATA] to know how much to inflate
* when first element is added.
*/
private val DEFAULTCAPACITY_EMPTY_ELEMENTDATA = IntArray(0)
class IntArrayList : AbstractMutableList<Int>, RandomAccess, Cloneable {
/**
* The array into which elements of the list are stored.
* The capacity of thie ArrayList is the length of this array buffer.
*/
private var elementData: IntArray
/**
* Constructs an empty list with the specified initial capacity.
*
* @param initialCapacity The initial capacity of the list. Must not be negative.
* @throws IllegalArgumentException if the specified initial capacity is negative.
*/
constructor(initialCapacity: Int) {
elementData = when {
initialCapacity > 0 -> IntArray(initialCapacity)
initialCapacity == 0 -> EMPTY_ELEMENT_DATA
else -> throw IllegalArgumentException("Illegal Capacity: $initialCapacity")
}
}
/**
* Constructs an empty list with an initial capacity of ten.
*/
constructor() {
elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA
}
/**
* Constructs a list containing the elements of the specified array in the same order.
*
* @param source The array whose elements are to be placed into this list.
*/
constructor(source: IntArray) {
elementData = if (source.isNotEmpty()) source.copyOf() else EMPTY_ELEMENT_DATA
}
/**
* Trim the capacity of this list instance to be the list's current size.
* An application can use this operation to minimize memory usage.
*/
fun trimToSize() {
modCount++
if (size < elementData.size) {
elementData = if (size == 0) EMPTY_ELEMENT_DATA else elementData.copyOf(size)
}
}
/**
* Increases the capacity of this list if necessary to ensure that it can hold at least
* the number of elements specified by the minimum capacity parameter.
*
* @param minCapacity The desired minimum capacity.
*/
fun ensureCapacity(minCapacity: Int) {
val minExpand = if (elementData === DEFAULTCAPACITY_EMPTY_ELEMENTDATA) 0 else DEFAULT_CAPACITY
if (minCapacity > minExpand) {
ensureExplicitCapacity(minCapacity)
}
}
private fun ensureCapacityInternal(minCapacity: Int) {
val targetMinCapacity = if (elementData === DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
maxOf(DEFAULT_CAPACITY, minCapacity)
} else minCapacity
ensureExplicitCapacity(targetMinCapacity)
}
private fun ensureExplicitCapacity(minCapacity: Int) {
modCount++
// Overflow conscious code
if (minCapacity - elementData.size > 0) {
grow(minCapacity)
}
}
/**
* Increases the capacity to ensure that it can hold at least
* the number of elements specified by the minimum capacity parameter.
*
* @param minCapacity The desired minimum capacity.
*/
private fun grow(minCapacity: Int) {
val oldCapacity = elementData.size
val newCapacity = (oldCapacity + (oldCapacity shr 1)).coerceIn(minCapacity, MAX_ARRAY_SIZE)
elementData = elementData.copyOf(newCapacity)
}
/**
* The number of elements in this list.
*/
override var size: Int = 0
private set
/**
* Returns `true` if this list contains no elements.
*/
override fun isEmpty() = size == 0
override fun indexOf(element: Int): Int {
for (i in 0 until size) {
if (element == elementData[i]) return i
}
return -1
}
override fun lastIndexOf(element: Int): Int {
for (i in (size - 1) downTo 0) {
if (element == elementData[i]) return i
}
return -1
}
/**
* Returns a deep copy of this list.
* Elements themselves *are* copied.
*/
public override fun clone(): Any {
try {
val clone = super.clone() as IntArrayList
clone.elementData = elementData.copyOf(size)
clone.modCount = 0
return clone
} catch (e: CloneNotSupportedException) {
// This shouldn't happen, since we are Cloneable
throw InternalError(e)
}
}
fun toIntArray() = elementData.copyOf(size)
override fun toArray(): Array<Any> = Array(size, elementData::get)
override fun get(index: Int): Int {
rangeCheck(index)
return elementData[index]
}
override fun set(index: Int, element: Int): Int {
rangeCheck(index)
val oldValue = elementData[index]
elementData[index] = element
return oldValue
}
override fun add(element: Int): Boolean {
ensureCapacityInternal(size + 1) // Increments modCount!!
elementData[size++] = element
return true
}
override fun add(index: Int, element: Int) {
rangeCheckForAdd(index)
ensureCapacityInternal(size + 1) // Increments modCount!!
System.arraycopy(elementData, index, elementData, index + 1, size - index)
elementData[index] = element
size++
}
override fun remove(element: Int): Boolean {
for (index in 0 until size) {
if (element == elementData[index]) {
fastRemove(index)
return true
}
}
return false
}
private fun fastRemove(index: Int) {
modCount++
val numMoved = size - index -1
if (numMoved > 0) {
System.arraycopy(elementData, index + 1, elementData, index, numMoved)
}
// No need to clear the removed value ; just decrement size
size--
}
override fun clear() {
modCount++
// No need to rewrite all elements.
size = 0
}
private fun rangeCheck(index: Int) {
if (index >= size) {
throw IndexOutOfBoundsException(outOfBoundsMsg(index))
}
}
private fun rangeCheckForAdd(index: Int) {
}
private fun outOfBoundsMsg(index: Int) = "index: $index, Size: $size"
override fun removeAt(index: Int): Int {
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
}
inner class ListIterator : IntIterator() {
private var index = 0
override fun hasNext() = index < size
override fun nextInt(): Int {
if (!hasNext()) throw NoSuchElementException()
return elementData[index++]
}
}
}
private fun hugeCapacity(minCapacity: Int): Int {
if (minCapacity < 0) throw OutOfMemoryError()
return if (minCapacity > MAX_ARRAY_SIZE) Int.MAX_VALUE else MAX_ARRAY_SIZE
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment