Skip to content

Instantly share code, notes, and snippets.

@Swoorup
Created January 31, 2022 16:28
Show Gist options
  • Save Swoorup/47c0f389661cb722377ad076753c3858 to your computer and use it in GitHub Desktop.
Save Swoorup/47c0f389661cb722377ad076753c3858 to your computer and use it in GitHub Desktop.
Append only data structure backed by array.
final case class ArrayLog[A](
private val arr: Array[A],
private val curWriteIdx: Int,
maxLength: Int
)(using ct: ClassTag[A]) { x =>
private inline def offset: Int =
if curWriteIdx < maxLength then 0 else curWriteIdx - maxLength
inline def size: Int =
if curWriteIdx < maxLength then curWriteIdx else maxLength
def appended(elem: A): ArrayLog[A] =
var _arr = arr
var _pos = curWriteIdx
if _pos == arr.length then
_arr = ct.newArray((maxLength * 1.6).toInt)
arr.copyToArray(_arr, _pos - maxLength + 1, maxLength - 1)
_pos = maxLength - 1
_arr(_pos) = elem
_pos += 1
ArrayLog[A](_arr, _pos, maxLength)
inline final def :+(elem: A): ArrayLog[A] = appended(elem)
def appendedAll(suffix: IterableOnce[A]): ArrayLog[A] =
val other = suffix.iterator.toArray.takeRight(maxLength)
if (curWriteIdx + other.length) <= arr.length then
Array.copy(other, 0, arr, curWriteIdx, other.length)
this.copy(curWriteIdx = curWriteIdx + other.length)
else
val newArray = ct.newArray((maxLength * 1.6).toInt)
val lastDataLenToCapture = maxLength - Math.min(other.length, maxLength)
if lastDataLenToCapture > 0 then
Array.copy(arr, curWriteIdx - 1 - lastDataLenToCapture, newArray, 0, lastDataLenToCapture)
Array.copy(other, 0, newArray, Math.max(lastDataLenToCapture - 1, 0), other.length)
ArrayLog(newArray, lastDataLenToCapture + other.length, maxLength)
/** Alias for `appendedAll` */
inline final def :++ (suffix: IterableOnce[A]): ArrayLog[A] = appendedAll(suffix)
// Make `concat` an alias for `appendedAll` so that it benefits from performance
// overrides of this method
inline final def concat(suffix: IterableOnce[A]): ArrayLog[A] = appendedAll(suffix)
def asDenseVector: DenseVector[A] =
DenseVector.create(
data = arr,
offset = x.offset,
stride = 1,
length = x.size
)
def toIndexedSeq: IndexedSeq[A] = new IndexedSeq {
override def apply(i: Int): A = arr(i + x.offset)
override def length: Int = x.size
}
}
object ArrayLog:
def apply[A](maxLength: Int)(elems: A*)(implicit ct: ClassTag[A]): ArrayLog[A] =
ArrayLog(maxLength)(elems.toArray)
def apply[A](maxLength: Int)(initial: Array[A])(implicit ct: ClassTag[A]): ArrayLog[A] =
var arr = initial
if maxLength >= arr.length then
arr = Array.copyOf(initial, (maxLength * 1.6).toInt)
ArrayLog(arr, curWriteIdx = initial.size, maxLength = maxLength)
def ofMaxLen[A](maxLength: Int)(implicit ct: ClassTag[A]): ArrayLog[A] =
ArrayLog(ct.newArray((maxLength * 1.6).toInt), 0, maxLength = maxLength)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment