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

org.apache.clerezza.scala.utils.CollectedIter.scala Maven / Gradle / Ivy

/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor  license  agreements.  See the NOTICE file distributed
 * with this work  for  additional  information  regarding  copyright
 * ownership.  The ASF  licenses  this file to you 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 org.apache.clerezza.scala.utils

import java.util.concurrent.locks.Lock
import java.util.{ConcurrentModificationException, Iterator}

import _root_.scala.collection.JavaConversions._
import scala.collection.immutable
import scala.collection.mutable._

/**
  *
  * A Collection that groups the elements of an iterator, giving a view over it as over a
  * sequence.
  *
  * The collection takes a function returning an iterator, in order to allow for cases where the
  * iterator needs to be called from the beginning again. i.e. when a ConcurrentModificationException
  * occurs and the iteration is repeated in a section used using the provided readLock.
  */
class CollectedIter[T](iterCreator: () => Iterator[T], readLock: Lock) extends immutable.Seq[T] {

    def this(jList: java.util.List[T], readLock: Lock) = this(() => jList.iterator(), readLock)

    def this() = this(() => java.util.Collections.emptyList[T].iterator(), null)

    var iter = iterCreator()
    var firstIter = true

    private val collectedElems = new ArrayBuffer[T]()

    /**
      * This method allows the position to be expressed between parenthesis
      */
    def apply(pos: Int) = {
        ensureReadTill(pos)
        collectedElems(pos)
    }


    /**
      * returns a new fully expanded and sorted CollectediterCreator
      */
    def sort(lt: (T, T) => Boolean) = {
        val sortedElems = iterator.toList.sortWith(lt)
        //TODO this re-expands everything, return sorted-list directly
        new CollectedIter[T](sortedElems, readLock)

    }

    /**
      * Operator style syntax to access a position.
      */
    def %(pos: Int) = apply(pos)

    private def ensureReadTill(pos: Int) {
        try {

            while (iter.hasNext && (collectedElems.length - 1 <= pos)) {
                val next = iter.next()
                if (firstIter || !collectedElems.contains(next)) {
                    collectedElems += next
                }
            }
        } catch {
            case e: ConcurrentModificationException => {
                readLock.lock()
                try {
                    iter = iterCreator()
                    firstIter = false
                    //going beyond pos, do reduce chance we have to aquire another lock
                    val biggerPos = if (pos < (Integer.MAX_VALUE - 100)) {
                        pos + 100
                    } else {
                        Integer.MAX_VALUE
                    }
                    while (iter.hasNext && (collectedElems.length - 1 <= biggerPos)) {
                        val next = iter.next()
                        if (!collectedElems.contains(next)) {
                            collectedElems += next
                        }
                    }
                } finally {
                    readLock.unlock()
                }
            }
            case e: Exception => throw e
        }
    }

    override def length: Int = {
        length(Integer.MAX_VALUE)
    }

    /**
      * The value returned is same or less than the length of the collection,
      * the underlying Iterator isn't expanded till more than max. If
      * the result is smaller than max it is the length of the collection.
      */
    def length(max: Int): Int = {
        ensureReadTill(max)
        collectedElems.length
    }

    override def toString() = {
        if (length(1) > 0) {
            apply(0).toString
        } else {
            "empty"
        }
    }

    override def iterator = {
        ensureReadTill(Integer.MAX_VALUE)
        collectedElems.iterator
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy