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

com.velocidi.apso.iterator.CompositeIterator.scala Maven / Gradle / Ivy

The newest version!
package com.velocidi.apso.iterator

import scala.collection.{AbstractIterator, BufferedIterator, Iterator}

/** An iterator that wraps a list of other iterators and iterates over its elements sequentially. It handles
  * compositions of a large number of iterators in a more efficient way than simply concatenating them, avoiding stack
  * overflows in particular. It supports appending of new iterators while keeping its efficiency.
  * @param iterators
  *   the list of iterators to compose
  * @tparam A
  *   the type of the elements to iterate over
  */
@deprecated("The stack overflow caused by Iterator.++ should be fixed in recent Scala versions.", "0.15.0")
class CompositeIterator[A](
    private[iterator] var current: Iterator[A] = Iterator.empty,
    private[iterator] var iterators: IndexedSeq[Iterator[A]] = Vector()
) extends Iterator[A] { self =>

  def hasNext: Boolean = {
    if (!current.hasNext) {
      iterators = iterators.dropWhile { it =>
        current = it
        !current.hasNext
      }
      if (iterators.nonEmpty) iterators = iterators.drop(1)
    }

    current.hasNext
  }

  def next(): A =
    if (hasNext) current.next()
    else throw new NoSuchElementException("next on empty iterator")

  // This forces the head to be stored only on the current iterator
  override def buffered: BufferedIterator[A] = {
    current = current.buffered
    iterators = iterators.map(_.buffered)
    new AbstractIterator[A] with BufferedIterator[A] { buff =>
      def head: A =
        if (hasNext) current.asInstanceOf[BufferedIterator[A]].head
        else throw new NoSuchElementException("next on empty iterator")
      def next(): A = self.next()
      def hasNext: Boolean = self.hasNext

      // Methods that implement their own buffering strategy, therefore need to be overriden
      override def filter(p: (A) => Boolean): Iterator[A] =
        new CompositeIterator[A](current.filter(p), iterators.map(_.filter(p)))

      override def takeWhile(p: A => Boolean): Iterator[A] = new AbstractIterator[A] {
        def hasNext: Boolean = buff.hasNext && p(buff.head)
        def next(): A =
          if (hasNext) buff.next()
          else throw new NoSuchElementException("next on empty iterator")
      }

      override def dropWhile(p: A => Boolean): Iterator[A] = new AbstractIterator[A] {
        def hasNext: Boolean = {
          current = current.dropWhile(p)
          if (!current.hasNext) {
            iterators = iterators.dropWhile { it =>
              current = it.dropWhile(p)
              !current.hasNext
            }
            if (iterators.nonEmpty) iterators = iterators.drop(1)
          }
          current.hasNext
        }
        def next(): A =
          if (hasNext) current.next()
          else throw new NoSuchElementException("next on empty iterator")
      }

    }
  }
}

/** Companion object containing a factory for composite iterators.
  */
object CompositeIterator {
  @deprecated("The stack overflow caused by Iterator.++ should be fixed in recent Scala versions.", "0.15.0")
  def apply[A](its: Iterator[A]*): CompositeIterator[A] =
    its.headOption
      .map { head =>
        val zero =
          if (head.isInstanceOf[CompositeIterator[_]]) head.asInstanceOf[CompositeIterator[A]]
          else new CompositeIterator(iterators = Vector(head))

        its.tail.foldLeft(zero) { case (c, it) =>
          if (it.isInstanceOf[CompositeIterator[_]]) {
            val composite = it.asInstanceOf[CompositeIterator[A]]
            val iterators = composite.current +: composite.iterators

            new CompositeIterator(current = c.current, iterators = c.iterators ++ iterators)

          } else {
            new CompositeIterator(current = c.current, iterators = c.iterators :+ it)
          }
        }
      }
      .getOrElse(new CompositeIterator[A]())
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy