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

org.neo4j.cypher.internal.runtime.GrowingArray.scala Maven / Gradle / Ivy

/*
 * Copyright (c) "Neo4j"
 * Neo4j Sweden AB [https://neo4j.com]
 *
 * This file is part of Neo4j.
 *
 * Neo4j is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see .
 */
package org.neo4j.cypher.internal.runtime

import org.neo4j.cypher.internal.runtime.GrowingArray.DEFAULT_SIZE
import org.neo4j.cypher.internal.runtime.GrowingArray.SHALLOW_SIZE
import org.neo4j.memory.HeapEstimator.shallowSizeOfInstance
import org.neo4j.memory.HeapEstimator.shallowSizeOfObjectArray
import org.neo4j.memory.HeapMemoryTracker

/**
 * Random access data structure which grows dynamically as elements are added.
 */
class GrowingArray[T <: AnyRef](memoryTracker: HeapMemoryTracker) extends AutoCloseable {

  private var trackedMemory = shallowSizeOfObjectArray(DEFAULT_SIZE)
  memoryTracker.allocateHeap(trackedMemory + SHALLOW_SIZE)
  private var highWaterMark: Int = 0
  private var array: Array[AnyRef] = new Array[AnyRef](DEFAULT_SIZE)

  /**
   * Set an element at a given index, and grows the underlying structure if needed.
   */
  def set(index: Int, t: T): Unit = {
    ensureCapacity(index + 1)
    array(index) = t
  }

  /**
   * Get the element at a given index.
   */
  def get(index: Int): T = {
    array(index).asInstanceOf[T]
  }

  /**
   * Get the element at a given index or null if it doesn't exist.
   */
  def getOrNull(index: Int): T = {
    if (index < highWaterMark) {
      array(index).asInstanceOf[T]
    } else {
      null.asInstanceOf[T]
    }
  }

  /**
   * Get the element at a given index. If the element at that index is `null`,
   * instead compute a new element, set it at the index, and return it.
   *
   * This is useful for storing resources that can be reused depending on their index.
   */
  def computeIfAbsent(index: Int, compute: () => T): T = {
    ensureCapacity(index + 1)
    var t = array(index)
    if (t == null) {
      t = compute()
      array(index) = t
    }
    t.asInstanceOf[T]
  }

  /**
   * Apply the given function `f` once for each element.
   *
   * `f` will not be called for gaps or `null` elements.
   */
  def foreach(f: T => Unit): Unit = {
    var i = 0
    while (i < highWaterMark) {
      val t = get(i)
      if (t != null) {
        f(t)
      }
      i += 1
    }
  }

  /**
   * Return `true` if any element has ever been set.
   */
  def hasNeverSeenData: Boolean = highWaterMark == 0

  /**
   * Return `true` if array contains a non-null element at the given index.
   */
  def isDefinedAt(index: Int): Boolean = array.isDefinedAt(index) && array(index) != null

  override def close(): Unit = {
    if (array != null) {
      memoryTracker.releaseHeap(trackedMemory + SHALLOW_SIZE)
      array = null
    }
  }

  def isClosed(): Boolean = {
    array == null
  }

  private def ensureCapacity(size: Int): Unit = {
    if (this.highWaterMark < size) {
      this.highWaterMark = size
    }

    if (array.length < size) {
      val temp = array
      val oldHeapUsage = trackedMemory
      val newLength = math.max(array.length * 2, size)
      trackedMemory = shallowSizeOfObjectArray(newLength)
      memoryTracker.allocateHeap(trackedMemory)
      array = new Array[AnyRef](newLength)
      System.arraycopy(temp, 0, array, 0, temp.length)
      memoryTracker.releaseHeap(oldHeapUsage)
    }
  }
}

object GrowingArray {
  val DEFAULT_SIZE: Int = 4
  val SHALLOW_SIZE: Long = shallowSizeOfInstance(classOf[GrowingArray[_]])
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy