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

monix.execution.internal.collection.JSArrayQueue.scala Maven / Gradle / Ivy

The newest version!
/*
 * Copyright (c) 2014-2019 by The Monix Project Developers.
 * See the project homepage at: https://monix.io
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package monix.execution.internal.collection

import monix.execution.internal.math._
import scala.collection.mutable
import scala.scalajs.js

/** A Javascript Array based queue.
  *
  * Inspired by: http://code.stephenmorley.org/javascript/queues/
  */
private[monix] final class JSArrayQueue[A] private (_size: Int, triggerEx: Int => Throwable = null)
  extends EvictingQueue[A] with LowLevelConcurrentQueue[A] {

  private[this] var queue = new js.Array[A]()
  private[this] var offset = 0
  private[this] val bufferSize =
    if (_size <= 0) 0 else nextPowerOf2(_size)

  override def capacity: Int =
    if (bufferSize == 0) Int.MaxValue else bufferSize
  override def isAtCapacity: Boolean =
    queue.length - offset >= capacity
  override def length: Int =
    queue.length - offset
  override def isEmpty: Boolean =
    queue.length - offset == 0

  def fenceOffer(): Unit = ()
  def fencePoll(): Unit = ()

  def offer(elem: A): Int = {
    if (elem == null) throw new NullPointerException("Null not supported")
    if (bufferSize > 0 && queue.length - offset >= capacity) {
      if (triggerEx != null) throw triggerEx(capacity)
      1 // rejecting new element as we are at capacity
    } else {
      queue.push(elem)
      0
    }
  }

  def poll(): A = {
    if (queue.length == 0) null.asInstanceOf[A]
    else {
      val item = queue(offset)
      offset += 1

      if (offset * 2 >= queue.length) {
        queue = queue.jsSlice(offset)
        offset = 0
      }

      item
    }
  }

  def offerMany(seq: A*): Long = {
    val iterator = seq.iterator
    var acc = 0L
    while (iterator.hasNext) acc += offer(iterator.next())
    acc
  }

  def drainToArray(array: Array[A], offset: Int): Int = {
    var idx = offset
    var continue = true

    while (continue && idx < array.length) {
      val elem = poll()
      if (elem != null) {
        array(idx) = elem
        idx += 1
      } else {
        continue = false
      }
    }

    idx - offset
  }

  override def drainToBuffer(buffer: mutable.Buffer[A], limit: Int): Int = {
    var count = 0
    var continue = true

    while (continue && count < limit) {
      val elem = poll()
      if (elem != null) {
        buffer += elem
        count += 1
      } else {
        continue = false
      }
    }

    count
  }

  def clear(): Unit = {
    queue = new js.Array[A]()
    offset = 0
  }

  def iterator: Iterator[A] = {
    val clone = queue.jsSlice(0)
    clone.iterator
  }
}

private[monix] object JSArrayQueue {
  def unbounded[A]: JSArrayQueue[A] =
    new JSArrayQueue[A](0)

  def bounded[A](bufferSize: Int, triggerEx: Int => Throwable = null): JSArrayQueue[A] =
    new JSArrayQueue[A](bufferSize, triggerEx)
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy