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

com.rojoma.json.v3.-impl.util.FlatteningIterator.scala Maven / Gradle / Ivy

The newest version!
package com.rojoma.json.v3.`-impl`.util

import scala.collection.GenTraversableOnce

object FlatteningIteratorUtils {
  implicit class Fit[T](val underlying: Iterator[T]) extends AnyVal {
    def **[T2 >: T](that: => GenTraversableOnce[T2]): Iterator[T2] = underlying match {
      case f: FlatteningIterator[T] => f ++ that
      case _ => new FlatteningIterator(underlying, Vector(() => that.toIterator))
    }

    def flatify[A](implicit ev: T <:< GenTraversableOnce[A]): Iterator[A] =
      if(!underlying.hasNext) Iterator.empty
      else {
        val hd = underlying.next().toIterator
        hd ** underlying.flatify
      }
  }
}

object FlatteningIterator {
  def apply[T](its: Iterator[T]*): Iterator[T] = {
    if(its.isEmpty) Iterator.empty
    else {
      val i = its.iterator
      val first = i.next()
      val rest: Vector[() => Iterator[T]] = i.map { x => () => x }.toVector
      new FlatteningIterator(first, rest)
    }
  }
}

import FlatteningIteratorUtils._

final class FlatteningIterator[+T] private [util] (private[this] var first: Iterator[T], private[this] var xs: Vector[() => GenTraversableOnce[T]]) extends AbstractIterator[T] {
  def this(it: Iterator[T]) = this(it, Vector.empty)

  // accessors for shiftIterators to use
  private def firstIterator = first
  private def subIterators = xs

  // Normalize the first iterator to be a not-FlatteningIterator.  It
  // should never be one -- if it is one, we've lost our "never nest"
  // promise.
  if(first.isInstanceOf[FlatteningIterator[_]]) {
    val f = first.asInstanceOf[FlatteningIterator[T]]
    first = f.firstIterator
    xs = vec_++(f.subIterators, xs)
  }

  // Exists because of SI-4442
  private def vec_++[A](a: Vector[A], b: Vector[A]): Vector[A] = {
    def cons = {
      var res = b
      val it = a.reverseIterator
      while(it.hasNext) {
        res = it.next() +: res
      }
      res
    }

    def snoc =  {
      var res = a
      val it = b.iterator
      while(it.hasNext) {
        res = res :+ it.next()
      }
      res
    }

    if(a.size < b.size) cons
    else snoc
  }

  override def ++[T2 >: T](that: =>GenTraversableOnce[T2]): Iterator[T2] =
    new FlatteningIterator(first, xs :+ (() => that))

  override def flatMap[B](f: T => GenTraversableOnce[B]): Iterator[B] =
    map(f).flatify

  def hasNext: Boolean = {
    first.nonEmpty || shiftIterators()
  }

  private def shiftIterators(): Boolean = {
    do {
      // This is a little messy because of the requirement to
      // evaluate xs(i) exactly once.

      val count = xs.size
      var toDrop = 0
      var found: Iterator[T] = null
      while(toDrop != count && found == null) {
        val it = xs(toDrop)().toIterator
        if(it.hasNext) found = it
        toDrop += 1 // yes, we're still going to drop it even if found
      }

      found match {
        case null =>
          xs = Vector.empty
          return false
        case f: FlatteningIterator[T] =>
          first = f.firstIterator // Not itself a flattening iterator
          xs = vec_++(f.subIterators, xs.drop(toDrop))
        case plainIterator =>
          first = plainIterator
          xs = xs.drop(toDrop)
          return true
      }
    } while(first.isEmpty)
    true
  }

  def next(): T = {
    if(!hasNext) Iterator.empty.next()
    first.next()
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy