summaryrefslogblamecommitdiff
path: root/src/library/scala/collection/generic/MutableMapTemplate.scala
blob: 989e29aa0dc6551e7a7b0caffc994e2992f632bd (plain) (tree)





































































































                                                                                                                                                                              
                                                                                 





































































                                                                              
/*                     __                                               *\
**     ________ ___   / /  ___     Scala API                            **
**    / __/ __// _ | / /  / _ |    (c) 2003-2009, LAMP/EPFL             **
**  __\ \/ /__/ __ |/ /__/ __ |    http://scala-lang.org/               **
** /____/\___/_/ |_/____/_/ | |                                         **
**                          |/                                          **
\*                                                                      */

// $Id: Map.scala 16884 2009-01-09 16:52:09Z cunei $


package scala.collection.generic

/** A generic template for maps from keys of type A to values of type B.
 *  To implement a concrete map, you need to provide implementations of the following methods:
 *  (where This is the type of the map in question):
 *
 *   def get(key: A): Option[B]
 *   def elements: Iterator[(A, B)]
 *   def update(key: A, value: B)
 *   def -(key: A): This
 *
 * If you wish that methods like, take, drop, filter return the same kind of map, you should also
 * override:
 *
 *   def empty: This
 *
 * It is also good idea to override methods foreach and size for efficiency.
 */
trait MutableMapTemplate[A, B, +This <: MutableMapTemplate[A, B, This] with mutable.Map[A, B]]
  extends MapTemplate[A, B, This]
     with Builder[(A, B), This, Any]
     with Growable[(A, B)]
     with Shrinkable[A]
     with Cloneable[This]
{ self =>

  override protected[this] def newBuilder: Builder[(A, B), This, Any] = new MutableMapBuilder[A, B, This](empty.asInstanceOf[This]) // !!! concrete overrides abstract problem

  /** This method allows one to add a new mapping from <code>key</code>
   *  to <code>value</code> to the map. If the map already contains a
   *  mapping for <code>key</code>, it will be overridden by this
   *  function.
   *
   * @param key    The key to update
   * @param value  The new value
   */
  def update(key: A, value: B)

  /** Add a key/vaue pair to this map, and return the map itself
   */
  def add(key: A, value: B): this.type = { update(key, value); this }

  /** Map <code>key</code> to <code>elem</code> in this map and return the element
   *  that the key was previously mapped to (if any).
   */
  def put(key: A, elem: B): Option[B] = {
    val ret = get(key)
    this(key) = elem
    ret
  }

  /** Add a key/value pair to this map.
   *  @param    kv the key/value pair.
   */
  def += (kv: (A, B)) { update(kv._1, kv._2) }

  /** A default implementation of addition where the value is not of the same type as
   *  the current map value type. This will always create a new immutable Map.
   */
  def add[B1 >: B](key: A, value: B1): collection.Map[A, B1] =
    Map[A, B1]() ++ thisCollection + ((key, value))

  /** Adds a single element to this collection and returns
   *  either the collection itself (if it is mutable), or a new collection
   *  with the added element.
   *
   *  @param elem  the element to add.
   */
  //override
   def +(kv: (A, B)): this.type = add(kv._1, kv._2)

  /** Adds two or more elements to this collection and returns
   *  either the collection itself (if it is mutable), or a new collection
   *  with the added elements.
   *
   *  @param elem1 the first element to add.
   *  @param elem2 the second element to add.
   *  @param elems the remaining elements to add.
   */
  //override
  def +(elem1: (A, B), elem2: (A, B), elems: (A, B)*): this.type =
    this + elem1 + elem2 ++ Iterable.fromOld(elems)

  /** Adds a number of elements provided by an iterable object
   *  via its <code>elements</code> method and returns
   *  either the collection itself (if it is mutable), or a new collection
   *  with the added elements.
   *
   *  @param iter     the iterable object.
   */
  //override
  def ++(iter: Traversable[(A, B)]): this.type = { (this /: iter) (_ + _); this }

  /** Adds a number of elements provided by an iterator
   *  via its <code>elements</code> method and returns
   *  either the collection itself (if it is mutable), or a new collection
   *  with the added elements.
   *
   *  @param iter   the iterator
   */
  //override
  def ++(iter: Iterator[(A, B)]): this.type = { (this /: iter) (_ + _); this }

  /** Remove a key from this map, noop if key is not presentg.
   *  @param    key the key to be removed
   */
  def -= (key: A)

  def -(key: A): This = { -=(key); thisCollection }

  def removeKey(key: A): Option[B] = {
    val ret = get(key)
    this -= key
    ret
  }

  // todo: add other -'s

  /** Removes all elements from the set. After this operation is completed,
   *  the set will be empty.
   */
  def clear() { for ((k, v) <- elements) -=(k) }

  /** Check if this map maps <code>key</code> to a value.
    * Return that value if it exists, otherwise put <code>default</code>
    * as that key's value and return it.
    */
  def getOrElseUpdate(key: A, default: => B): B =
    get(key) match {
      case Some(v) => v
      case None => val d = default; this(key) = d; d
    }

  /** This function transforms all the values of mappings contained
   *  in this map with function <code>f</code>.
   *
   * @param f  The transformation to apply
   */
  def transform(f: (A, B) => B): this.type = {
    elements foreach {
      case (key, value) => update(key, f(key, value))
    }
    this
  }

  /** This method retains only those mappings for which the predicate
   *  <code>p</code> returns <code>true</code>.
   *
   * @param p  The test predicate
   * @deprecated cannot be type inferred because if retain in Iterable.
   */
  def retain(p: (A, B) => Boolean): this.type = {
    for ((k, v) <- this) if (!p(k, v)) -=(k)
    this
  }

  override def clone(): This =
    empty ++ thisCollection

  /** The result when this map is used as a builder */
  def result: This = thisCollection
}