/* __ *\
** ________ ___ / / ___ Scala API **
** / __/ __// _ | / / / _ | (c) 2006-2010, LAMP/EPFL **
** __\ \/ /__/ __ |/ /__/ __ | http://www.scala-lang.org/ **
** /____/\___/_/ |_/____/_/ | | **
** |/ **
\* */
package scala.collection
/** <p>
* A collection of implicit conversions supporting interoperability between
* Scala and Java collections.
* </p>
* <p>
* The following conversions are supported:
* </p>
* <ul>
* <li><code>scala.collection.Iterable</code> <=> <code>java.lang.Iterable</code></li>
* <li><code>scala.collection.Iterable</code> <=> <code>java.util.Collection</code></li>
* <li><code>scala.collection.Iterator</code> <=> <code>java.util.{ Iterator, Enumeration }</code></li>
* <li><code>scala.collection.mutable.Buffer</code> <=> <code>java.util.List</code></li>
* <li><code>scala.collection.mutable.Set</code> <=> <code>java.util.Set</code></li>
* <li><code>scala.collection.mutable.Map</code> <=> <code>java.util.Map</code></li>
* <li><code>scala.collection.mutable.ConcurrentMap</code> <=> <code>java.util.concurrent.ConcurrentMap</code></li>
* <li><code>java.util.Properties</code></li> => <code>scala.collection.mutable.Map[String, String]</code></li>
* </ul>
* <p>
* In all cases, converting from a source type to a target type and back
* again will return the original source object, eg.
* </p>
* <pre>
* <b>import</b> scala.collection.JavaConversions._
*
* <b>val</b> sl = <b>new</b> scala.collection.mutable.ListBuffer[Int]
* <b>val</b> jl : java.util.List[Int] = sl
* <b>val</b> sl2 : scala.collection.mutable.Buffer[Int] = jl
* assert(sl eq sl2)g</pre>
* <p>
* In addition, the following one way conversions are provided:
* </p>
* <ul>
* <li><code>scala.collection.IndexedSeq => <code>java.util.List }</code></li>
* <li><code>scala.collection.mutable.IndexedSeq => <code>java.util.List</code></li>
* <li><code>scala.collection.Set</code> => <code>java.util.Set</code></li>
* <li><code>scala.collection.Map</code> => <code>java.util.Map</code></li>
* </ul>
* Note that no conversion is provided from <code>scala.collection.immutable.List</code>
* to <code>java.util.List</code>. Instead it is convertible to an immutable
* <code>java.util.Collection</code> which provides size and interaction
* capabilities, but not access by index as would be provided by
* <code>java.util.List</code>.<br/>
* This is intentional: in combination the implementation of
* <code>scala.collection.immutable.List</code> and the typical usage
* patterns of <code>java.util.List</code> would perform extremely poorly.
* </p>
*
* @author Miles Sabin
* @since 2.8
*/
object JavaConversions {
import java.{ lang => jl, util => ju }
import java.util.{ concurrent => juc }
import scala.reflect.ClassManifest
// Scala => Java
/**
* Implicitly converts a Scala <code>Iterator</code> to a Java <code>Iterator</code>.
* The returned Java <code>Iterator</code> is backed by the provided Scala
* <code>Iterator</code> and any side-effects of using it via the Java interface will
* be visible via the Scala interface and vice versa.
* <p>
* If the Scala <code>Iterator</code> was previously obtained from an implicit or
* explicit call of <code>asIterator(java.util.Iterator)</code> then the original
* Java <code>Iterator</code> will be returned.
*
* @param i The <code>Iterator</code> to be converted.
* @return A Java <code>Iterator</code> view of the argument.
*/
implicit def asIterator[A](i : Iterator[A]): ju.Iterator[A] = i match {
case JIteratorWrapper(wrapped) => wrapped
case _ => IteratorWrapper(i)
}
/**
* Implicitly converts a Scala <code>Iterator</code> to a Java <code>Enumeration</code>.
* The returned Java <code>Enumeration</code> is backed by the provided Scala
* <code>Iterator</code> and any side-effects of using it via the Java interface will
* be visible via the Scala interface and vice versa.
* <p>
* If the Scala <code>Iterator</code> was previously obtained from an implicit or
* explicit call of <code>asIterator(java.util.Enumeration)</code> then the
* original Java <code>Enumeration</code> will be returned.
*
* @param i The <code>Iterator</code> to be converted.
* @return A Java <code>Enumeration</code> view of the argument.
*/
implicit def asEnumeration[A](i : Iterator[A]): ju.Enumeration[A] = i match {
case JEnumerationWrapper(wrapped) => wrapped
case _ => IteratorWrapper(i)
}
/**
* Implicitly converts a Scala <code>Iterable</code> to a Java <code>Iterable</code>.
* The returned Java <code>Iterable</code> is backed by the provided Scala
* <code>Iterable</code> and any side-effects of using it via the Java interface will
* be visible via the Scala interface and vice versa.
* <p>
* If the Scala <code>Iterable</code> was previously obtained from an implicit or
* explicit call of <code>asIterable(java.lang.Iterable)</code> then the original
* Java <code>Iterable</code> will be returned.
*
* @param i The <code>Iterable</code> to be converted.
* @return A Java <code>Iterable</code> view of the argument.
*/
implicit def asIterable[A](i : Iterable[A]): jl.Iterable[A] = i match {
case JIterableWrapper(wrapped) => wrapped
case _ => IterableWrapper(i)
}
/**
* Implicitly converts a Scala <code>Iterable</code> to an immutable Java
* <code>Collection</code>.
* <p>
* If the Scala <code>Iterable</code> was previously obtained from an implicit or
* explicit call of <code>asSizedIterable(java.util.Collection)</code> then the original
* Java <code>Collection</code> will be returned.
*
* @param i The <code>SizedIterable</code> to be converted.
* @return A Java <code>Collection</code> view of the argument.
*/
implicit def asCollection[A](i : Iterable[A]): ju.Collection[A] = i match {
case JCollectionWrapper(wrapped) => wrapped
case _ => new IterableWrapper(i)
}
/**
* Implicitly converts a Scala mutable <code>Buffer</code> to a Java <code>List</code>.
* The returned Java <code>List</code> is backed by the provided Scala
* <code>Buffer</code> and any side-effects of using it via the Java interface will
* be visible via the Scala interface and vice versa.
* <p>
* If the Scala <code>Buffer</code> was previously obtained from an implicit or
* explicit call of <code>asBuffer(java.util.List)</code> then the original
* Java <code>List</code> will be returned.
*
* @param b The <code>Buffer</code> to be converted.
* @return A Java <code>List</code> view of the argument.
*/
implicit def asList[A](b : mutable.Buffer[A]): ju.List[A] = b match {
case JListWrapper(wrapped) => wrapped
case _ => new MutableBufferWrapper(b)
}
/**
* Implicitly converts a Scala mutable <code>Seq</code> to a Java <code>List</code>.
* The returned Java <code>List</code> is backed by the provided Scala
* <code>Seq</code> and any side-effects of using it via the Java interface will
* be visible via the Scala interface and vice versa.
* <p>
* If the Scala <code>Seq</code> was previously obtained from an implicit or
* explicit call of <code>asSeq(java.util.List)</code> then the original
* Java <code>List</code> will be returned.
*
* @param b The <code>Seq</code> to be converted.
* @return A Java <code>List</code> view of the argument.
*/
implicit def asList[A](b : mutable.IndexedSeq[A]): ju.List[A] = b match {
case jlw: JListWrapper[_] => jlw.underlying.asInstanceOf[ju.List[A]]
case _ => new MutableIndexedSeqWrapper(b)
}
/**
* Implicitly converts a Scala <code>Seq</code> to a Java <code>List</code>.
* The returned Java <code>List</code> is backed by the provided Scala
* <code>Seq</code> and any side-effects of using it via the Java interface will
* be visible via the Scala interface and vice versa.
* <p>
* If the Scala <code>Seq</code> was previously obtained from an implicit or
* explicit call of <code>asSeq(java.util.List)</code> then the original
* Java <code>List</code> will be returned.
*
* @param b The <code>Seq</code> to be converted.
* @return A Java <code>List</co *
de> view of the argument.
*/
implicit def asList[A](b : IndexedSeq[A]): ju.List[A] = b match {
case jlw: JListWrapper[_] => jlw.underlying.asInstanceOf[ju.List[A]]
case _ => new IndexedSeqWrapper(b)
}
/**
* Implicitly converts a Scala mutable <code>Set</code> to a Java <code>Set</code>.
* The returned Java <code>Set</code> is backed by the provided Scala
* <code>Set</code> and any side-effects of using it via the Java interface will
* be visible via the Scala interface and vice versa.
* <p>
* If the Scala <code>Set</code> was previously obtained from an implicit or
* explicit call of <code>asSet(java.util.Set)</code> then the original
* Java <code>Set</code> will be returned.
*
* @param s The <code>Set</code> to be converted.
* @return A Java <code>Set</code> view of the argument.
*/
implicit def asSet[A](s : mutable.Set[A])(implicit m : ClassManifest[A]): ju.Set[A] = s match {
case JSetWrapper(wrapped) => wrapped
case _ => new MutableSetWrapper(s)(m)
}
/**
* Implicitly converts a Scala <code>Set</code> to a Java <code>Set</code>.
* The returned Java <code>Set</code> is backed by the provided Scala
* <code>Set</code> and any side-effects of using it via the Java interface will
* be visible via the Scala interface and vice versa.
* <p>
* If the Scala <code>Set</code> was previously obtained from an implicit or
* explicit call of <code>asSet(java.util.Set)</code> then the original
* Java <code>Set</code> will be returned.
*
* @param s The <code>Set</code> to be converted.
* @return A Java <code>Set</code> view of the argument.
*/
implicit def asSet[A](s: Set[A]): ju.Set[A] = s match {
case JSetWrapper(wrapped) => wrapped
case _ => new SetWrapper(s)
}
/**
* Implicitly converts a Scala mutable <code>Map</code> to a Java <code>Map</code>.
* The returned Java <code>Map</code> is backed by the provided Scala
* <code>Map</code> and any side-effects of using it via the Java interface will
* be visible via the Scala interface and vice versa.
* <p>
* If the Scala <code>Map</code> was previously obtained from an implicit or
* explicit call of <code>asMap(java.util.Map)</code> then the original
* Java <code>Map</code> will be returned.
*
* @param m The <code>Map</code> to be converted.
* @return A Java <code>Map</code> view of the argument.
*/
implicit def asMap[A, B](m : mutable.Map[A, B])(implicit ma : ClassManifest[A]): ju.Map[A, B] = m match {
//case JConcurrentMapWrapper(wrapped) => wrapped
case JMapWrapper(wrapped) => wrapped
case _ => new MutableMapWrapper(m)(ma)
}
/**
* Implicitly converts a Scala <code>Map</code> to a Java <code>Map</code>.
* The returned Java <code>Map</code> is backed by the provided Scala
* <code>Map</code> and any side-effects of using it via the Java interface will
* be visible via the Scala interface and vice versa.
* <p>
* If the Scala <code>Map</code> was previously obtained from an implicit or
* explicit call of <code>asMap(java.util.Map)</code> then the original
* Java <code>Map</code> will be returned.
*
* @param m The <code>Map</code> to be converted.
* @return A Java <code>Map</code> view of the argument.
*/
implicit def asMap[A, B](m : Map[A, B])(implicit ma : ClassManifest[A]): ju.Map[A, B] = m match {
//case JConcurrentMapWrapper(wrapped) => wrapped
case JMapWrapper(wrapped) => wrapped
case _ => new MapWrapper(m)
}
/**
* Implicitly converts a Scala mutable `ConcurrentMap` to a Java `ConcurrentMap`.
* The returned Java `ConcurrentMap` is backed by the provided Scala `ConcurrentMap`
* and any side-effects of using it via the Java interface will be visible
* via the Scala interface and vice versa.
* <p>
* If the Scala <code>ConcurrentMap</code> was previously obtained from an implicit or
* explicit call of <code>asConcurrentMap(java.util.concurrect.ConcurrentMap)</code> then the original
* Java <code>ConcurrentMap</code> will be returned.
*/
implicit def asConcurrentMap[A, B](m: mutable.ConcurrentMap[A, B])
(implicit ma: ClassManifest[A], mb: ClassManifest[B]): juc.ConcurrentMap[A, B] = m match {
case JConcurrentMapWrapper(wrapped) => wrapped
case _ => new ConcurrentMapWrapper(m)(ma, mb)
}
// Java => Scala
/**
* Implicitly converts a Java <code>Iterator</code> to a Scala <code>Iterator</code>.
* The returned Scala <code>Iterator</code> is backed by the provided Java
* <code>Iterator</code> and any side-effects of using it via the Scala interface will
* be visible via the Java interface and vice versa.
* <p>
* If the Java <code>Iterator</code> was previously obtained from an implicit or
* explicit call of <code>asIterator(scala.collection.Iterator)</code> then the original
* Scala <code>Iterator</code> will be returned.
*
* @param i The <code>Iterator</code> to be converted.
* @return A Scala <code>Iterator</code> view of the argument.
*/
implicit def asIterator[A](i : ju.Iterator[A]): Iterator[A] = i match {
case IteratorWrapper(wrapped) => wrapped
case _ => JIteratorWrapper(i)
}
/**
* Implicitly converts a Java <code>Enumeration</code> to a Scala <code>Iterator</code>.
* The returned Scala <code>Iterator</code> is backed by the provided Java
* <code>Enumeration</code> and any side-effects of using it via the Scala interface will
* be visible via the Java interface and vice versa.
* <p>
* If the Java <code>Enumeration</code> was previously obtained from an implicit or
* explicit call of <code>asEnumeration(scala.collection.Iterator)</code> then the
* original Scala <code>Iterator</code> will be returned.
*
* @param i The <code>Enumeration</code> to be converted.
* @return A Scala <code>Iterator</code> view of the argument.
*/
implicit def asIterator[A](i : ju.Enumeration[A]): Iterator[A] = i match {
case IteratorWrapper(wrapped) => wrapped
case _ => JEnumerationWrapper(i)
}
/**
* Implicitly converts a Java <code>Iterable</code> to a Scala <code>Iterable</code>.
* The returned Scala <code>Iterable</code> is backed by the provided Java
* <code>Iterable</code> and any side-effects of using it via the Scala interface will
* be visible via the Java interface and vice versa.
* <p>
* If the Java <code>Iterable</code> was previously obtained from an implicit or
* explicit call of <code>asIterable(scala.collection.Iterable)</code> then the original
* Scala <code>Iterable</code> will be returned.
*
* @param i The <code>Iterable</code> to be converted.
* @return A Scala <code>Iterable</code> view of the argument.
*/
implicit def asIterable[A](i : jl.Iterable[A]): Iterable[A] = i match {
case IterableWrapper(wrapped) => wrapped
case _ => JIterableWrapper(i)
}
/**
* Implicitly converts a Java <code>Collection</code> to an Scala <code>Iterable</code>.
* <p>
* If the Java <code>Collection</code> was previously obtained from an implicit or
* explicit call of <code>asCollection(scala.collection.SizedIterable)</code> then
* the original Scala <code>SizedIterable</code> will be returned.
*
* @param i The <code>Collection</code> to be converted.
* @return A Scala <code>SizedIterable</code> view of the argument.
*/
implicit def asIterable[A](i : ju.Collection[A]): Iterable[A] = i match {
case IterableWrapper(wrapped) => wrapped
case _ => JCollectionWrapper(i)
}
/**
* Implicitly converts a Java <code>List</code> to a Scala mutable <code>Buffer</code>.
* The returned Scala <code>Buffer</code> is backed by the provided Java
* <code>List</code> and any side-effects of using it via the Scala interface will
* be visible via the Java interface and vice versa.
* <p>
* If the Java <code>List</code> was previously obtained from an implicit or
* explicit call of <code>asList(scala.collection.mutable.Buffer)</code> then the original
* Scala <code>Buffer</code> will be returned.
*
* @param l The <code>List</code> to be converted.
* @return A Scala mutable <code>Buffer</code> view of the argument.
*/
implicit def asBuffer[A](l : ju.List[A]): mutable.Buffer[A] = l match {
case MutableBufferWrapper(wrapped) => wrapped
case _ =>new JListWrapper(l)
}
/**
* Implicitly converts a Java <code>Set</code> to a Scala mutable <code>Set</code>.
* The returned Scala <code>Set</code> is backed by the provided Java
* <code>Set</code> and any side-effects of using it via the Scala interface will
* be visible via the Java interface and vice versa.
* <p>
* If the Java <code>Set</code> was previously obtained from an implicit or
* explicit call of <code>asSet(scala.collection.mutable.Set)</code> then the original
* ScalaThe reported problems have to do with dependent method types, which is currently an experimental feature in Scala and is still under development. We emphasize that these problems are related to type-inference and, as stated in the paper, it is possible to run and type-check the programs with additional annotations. <code>Set</code> will be returned.
*
* @param s The <code>Set</code> to be converted.
* @return A Scala mutable <code>Set</code> view of the argument.
*/
implicit def asSet[A](s : ju.Set[A]): mutable.Set[A] = s match {
case MutableSetWrapper(wrapped) => wrapped
case _ =>new JSetWrapper(s)
}
/**
* Implicitly converts a Java <code>Map</code> to a Scala mutable <code>Map</code>.
* The returned Scala <code>Map</code> is backed by the provided Java
* <code>Map</code> and any side-effects of using it via the Scala interface will
* be visible via the Java interface and vice versa.
* <p>
* If the Java <code>Map</code> was previously obtained from an implicit or
* explicit call of <code>asMap(scala.collection.mutable.Map)</code> then the original
* Scala <code>Map</code> will be returned.
*
* @param m The <code>Map</code> to be converted.
* @return A Scala mutable <code>Map</code> view of the argument.
*/
implicit def asMap[A, B](m : ju.Map[A, B]): mutable.Map[A, B] = m match {
//case ConcurrentMapWrapper(wrapped) => wrapped
case MutableMapWrapper(wrapped) => wrapped
case _ => new JMapWrapper(m)
}
/**
* Implicitly converts a Java <code>ConcurrentMap</code> to a Scala mutable <code>ConcurrentMap</code>.
* The returned Scala <code>ConcurrentMap</code> is backed by the provided Java
* <code>ConcurrentMap</code> and any side-effects of using it via the Scala interface will
* be visible via the Java interface and vice versa.
* <p>
* If the Java <code>ConcurrentMap</code> was previously obtained from an implicit or
* explicit call of <code>asConcurrentMap(scala.collection.mutable.ConcurrentMap)</code> then the original
* Scala <code>ConcurrentMap</code> will be returned.
*
* @param m The <code>ConcurrentMap</code> to be converted.
* @return A Scala mutable <code>ConcurrrentMap</code> view of the argument.
*/
implicit def asConcurrentMap[A, B](m: juc.ConcurrentMap[A, B]): mutable.ConcurrentMap[A, B] = m match {
case ConcurrentMapWrapper(wrapped) => wrapped
case _ => new JConcurrentMapWrapper(m)
}
/**
* Implicitly converts a Java <code>Properties</code> to a Scala mutable <code>Map[String, String]</code>.
* The returned Scala <code>Map[String, String]</code> is backed by the provided Java
* <code>Properties</code> and any side-effects of using it via the Scala interface will
* be visible via the Java interface and vice versa.
*
* @param m The <code>Properties</code> to be converted.
* @return A Scala mutable <code>Map[String, String]</code> view of the argument.
*/
implicit def asMap(p: ju.Properties): mutable.Map[String, String] = p match {
case _ => new JPropertiesWrapper(p)
}
// Private implementations ...
case class IteratorWrapper[A](underlying : Iterator[A]) extends ju.Iterator[A] with ju.Enumeration[A] {
def hasNext = underlying.hasNext
def next = underlying.next
def hasMoreElements = underlying.hasNext
def nextElement = underlying.next
def remove = throw new UnsupportedOperationException
}
case class JIteratorWrapper[A](underlying : ju.Iterator[A]) extends Iterator[A] {
def hasNext = underlying.hasNext
def next = underlying.next
}
case class JEnumerationWrapper[A](underlying : ju.Enumeration[A]) extends Iterator[A] {
def hasNext = underlying.hasMoreElements
def next = underlying.nextElement
}
case class IterableWrapper[A](underlying : Iterable[A]) extends ju.AbstractCollection[A] {
def iterator = underlying.iterator
def size = underlying.size
override def isEmpty = underlying.isEmpty
}
case class JIterableWrapper[A](underlying : jl.Iterable[A]) extends Iterable[A] {
def iterator = underlying.iterator
def newBuilder[B] = new mutable.ArrayBuffer[B]
}
case class JCollectionWrapper[A](underlying : ju.Collection[A]) extends Iterable[A] {
def iterator = underlying.iterator
override def size = underlying.size
override def isEmpty = underlying.isEmpty
def newBuilder[B] = new mutable.ArrayBuffer[B]
}
case class IndexedSeqWrapper[A](underlying : IndexedSeq[A]) extends ju.AbstractList[A] {
def size = underlying.length
def get(i : Int) = underlying(i)
}
case class MutableIndexedSeqWrapper[A](underlying : mutable.IndexedSeq[A]) extends ju.AbstractList[A] {
def size = underlying.length
def get(i : Int) = underlying(i)
override def set(i : Int, elem: A) = { val p = underlying(i) ; underlying(i) = elem ; p }
}
case class MutableBufferWrapper[A](underlying : mutable.Buffer[A]) extends ju.AbstractList[A] {
def size = underlying.length
def get(i : Int) = underlying(i)
override def set(i : Int, elem: A) = { val p = underlying(i) ; underlying(i) = elem ; p }
override def add(elem : A) = { underlying.append(elem) ; true }
override def remove(i : Int) = underlying.remove(i)
}
case class JListWrapper[A](val underlying : ju.List[A]) extends mutable.Buffer[A] {
def length = underlying.size
override def isEmpty = underlying.isEmpty
override def iterator : Iterator[A] = underlying.iterator
def apply(i : Int) = underlying.get(i)
def update(i : Int, elem : A) = underlying.set(i, elem)
def +=:(elem : A) = { underlying.subList(0, 0).add(elem) ; this }
def +=(elem : A): this.type = { underlying.add(elem); this }
def insertAll(i : Int, elems : Traversable[A]) = { val ins = underlying.subList(0, i) ; elems.foreach(ins.add(_)) }
def remove(i : Int) = underlying.remove(i)
def clear = underlying.clear
def result = this
}
class SetWrapper[A](underlying: Set[A]) extends ju.AbstractSet[A] {
self =>
def size = underlying.size
def iterator = new ju.Iterator[A] {
val ui = underlying.iterator
var prev : Option[A] = None
def hasNext = ui.hasNext
def next = { val e = ui.next ; prev = Some(e) ; e }
def remove = prev match {
case Some(e) =>
self match {
case ms: mutable.Set[a] =>
ms.remove(e.asInstanceOf[a])
prev = None
case _ =>
throw new UnsupportedOperationException("remove")
}
case _ => throw new IllegalStateException("next must be called at least once before remove")
}
}
}
case class MutableSetWrapper[A](underlying : mutable.Set[A])(m : ClassManifest[A]) extends SetWrapper[A](underlying) {
override def add(elem: A) = { val sz = underlying.size ; underlying += elem ; sz < underlying.size }
override def remove(elem : AnyRef) = {
m.erasure.isInstance(elem) && {
val sz = underlying.size
underlying -= elem.asInstanceOf[A]
sz > underlying.size
}
}
}
case class JSetWrapper[A](underlying : ju.Set[A]) extends mutable.Set[A] with mutable.SetLike[A, JSetWrapper[A]] {
override def size = underlying.size
def iterator = underlying.iterator
def contains(elem: A): Boolean = underlying.contains(elem)
def +=(elem: A): this.type = { underlying.add(elem); this }
def -=(elem: A): this.type = { underlying.remove(elem); this }
override def add(elem: A): Boolean = underlying.add(elem)
override def remove(elem: A): Boolean = underlying.remove(elem)
override def clear = underlying.clear
override def empty = JSetWrapper(new ju.HashSet[A])
}
class MapWrapper[A, B](underlying: Map[A, B]) extends ju.AbstractMap[A, B] { self =>
override def size = underlying.size
override def entrySet: ju.Set[ju.Map.Entry[A, B]] = new ju.AbstractSet[ju.Map.Entry[A, B]] {
def size = self.size
def iterator = new ju.Iterator[ju.Map.Entry[A, B]] {
val ui = underlying.iterator
var prev : Option[A] = None
def hasNext = ui.hasNext
def next = {
val (k, v) = ui.next
prev = Some(k)
new ju.Map.Entry[A, B] {
def getKey = k
def getValue = v
def setValue(v1 : B) = self.put(k, v1)
override def equals(other : Any) = other match {
case e : ju.Map.Entry[_, _] => k == e.getKey && v == e.getValue
case _ => false
}
}
}
def remove = prev match {
case Some(k) =>
self match {
case mm: mutable.Map[a, _] =>
val v = mm.remove(k.asInstanceOf[a])
prev = None
v
case _ =>
throw new UnsupportedOperationException("remove")
}
case _ =>
throw new IllegalStateException("next must be called at least once before remove")
}
}
}
}
abstract class MutableMapWrapperCommon[A, B](underlying: mutable.Map[A, B])(m: ClassManifest[A])
extends MapWrapper[A, B](underlying) {
override def put(k : A, v : B) = underlying.put(k, v) match {
case Some(v1) => v1
case None => null.asInstanceOf[B]
}
override def remove(k : AnyRef) = {
if (!m.erasure.isInstance(k))
null.asInstanceOf[B]
else {
val k1 = k.asInstanceOf[A]
underlying.get(k1) match {
case Some(v) => underlying -= k1 ; v
case None => null.asInstanceOf[B]
}
}
}
}
case class MutableMapWrapper[A, B](underlying : mutable.Map[A, B])(m : ClassManifest[A])
extends MutableMapWrapperCommon[A, B](underlying)(m)
trait JMapWrapperLike[A, B, +Repr <: mutable.MapLike[A, B, Repr] with mutable.Map[A, B]]
extends mutable.Map[A, B] with mutable.MapLike[A, B, Repr] {
def underlying: ju.Map[A, B]
override def size = underlying.size
def get(k : A) = {
val v = underlying.get(k)
if (v != null)
Some(v)
else if(underlying.containsKey(k))
Some(null.asInstanceOf[B])
else
None
}
def +=(kv: (A, B)): this.type = { underlying.put(kv._1, kv._2); this }
def -=(key: A): this.type = { underlying.remove(key); this }
override def put(k : A, v : B): Option[B] = {
val r = underlying.put(k, v)
if (r != null) Some(r) else None
}
override def update(k : A, v : B) { underlying.put(k, v) }
override def remove(k : A): Option[B] = {
val r = underlying.remove(k)
if (r != null) Some(r) else None
}
def iterator = new Iterator[(A, B)] {
val ui = underlying.entrySet.iterator
def hasNext = ui.hasNext
def next = { val e = ui.next ; (e.getKey, e.getValue) }
}
override def clear = underlying.clear
override def empty: Repr = null.asInstanceOf[Repr]
}
case class JMapWrapper[A, B](val underlying : ju.Map[A, B])
extends JMapWrapperLike[A, B, JMapWrapper[A, B]] {
override def empty = JMapWrapper(new ju.HashMap[A, B])
}
case class ConcurrentMapWrapper[A, B](underlying: mutable.ConcurrentMap[A, B])
(m: ClassManifest[A], mv: ClassManifest[B])
extends MutableMapWrapperCommon[A, B](underlying)(m) with juc.ConcurrentMap[A, B] {
self =>
override def remove(k : AnyRef) = {
if (!m.erasure.isInstance(k))
null.asInstanceOf[B]
else {
val k1 = k.asInstanceOf[A]
underlying.remove(k1) match {
case Some(v) => v
case None => null.asInstanceOf[B]
}
}
}
def putIfAbsent(k: A, v: B) = underlying.putIfAbsent(k, v) match {
case Some(v) => v
case None => null.asInstanceOf[B]
}
def remove(k: AnyRef, v: AnyRef) = {
if (!m.erasure.isInstance(k) || !mv.erasure.isInstance(v))
false
else {
val k1 = k.asInstanceOf[A]
val v1 = v.asInstanceOf[B]
underlying.remove(k1, v1)
}
}
def replace(k: A, v: B): B = underlying.replace(k, v) match {
case Some(v) => v
case None => null.asInstanceOf[B]
}
def replace(k: A, oldval: B, newval: B) = underlying.replace(k, oldval, newval)
}
case class JConcurrentMapWrapper[A, B](val underlying: juc.ConcurrentMap[A, B])
extends JMapWrapperLike[A, B, JConcurrentMapWrapper[A, B]] with mutable.ConcurrentMap[A, B] {
override def get(k: A) = {
val v = underlying.get(k)
if (v != null) Some(v)
else None
}
override def empty = new JConcurrentMapWrapper(new juc.ConcurrentHashMap[A, B])
def putIfAbsent(k: A, v: B): Option[B] = {
val r = underlying.putIfAbsent(k, v)
if (r != null) Some(r) else None
}
def remove(k: A, v: B): Boolean = underlying.remove(k, v)
def replace(k: A, v: B): Option[B] = {
val prev = underlying.replace(k, v)
if (prev != null) Some(prev) else None
}
def replace(k: A, oldvalue: B, newvalue: B): Boolean = underlying.replace(k, oldvalue, newvalue)
}
case class JPropertiesWrapper(underlying: ju.Properties)
extends mutable.Map[String, String] with mutable.MapLike[String, String, JPropertiesWrapper] {
override def size = underlying.size
def get(k : String) = {
val v = underlying.get(k)
if (v != null)
Some(v.asInstanceOf[String])
else
None
}
def +=(kv: (String, String)): this.type = { underlying.put(kv._1, kv._2); this }
def -=(key: String): this.type = { underlying.remove(key); this }
override def put(k : String, v : String): Option[String] = {
val r = underlying.put(k, v)
if (r != null) Some(r.asInstanceOf[String]) else None
}
override def update(k : String, v : String) { underlying.put(k, v) }
override def remove(k : String): Option[String] = {
val r = underlying.remove(k)
if (r != null) Some(r.asInstanceOf[String]) else None
}
def iterator = new Iterator[(String, String)] {
val ui = underlying.entrySet.iterator
def hasNext = ui.hasNext
def next = { val e = ui.next ; (e.getKey.asInstanceOf[String], e.getValue.asInstanceOf[String]) }
}
override def clear = underlying.clear
override def empty = JPropertiesWrapper(new ju.Properties)
def getProperty(key: String) = underlying.getProperty(key)
def getProperty(key: String, defaultValue: String) = underlying.getProperty(key, defaultValue)
def setProperty(key: String, value: String) = underlying.setProperty(key, value)
}
}