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

scala.scalajs.js.WrappedDictionary.scala Maven / Gradle / Ivy

The newest version!
/*
 * Scala.js (https://www.scala-js.org/)
 *
 * Copyright EPFL.
 *
 * Licensed under Apache License 2.0
 * (https://www.apache.org/licenses/LICENSE-2.0).
 *
 * See the NOTICE file distributed with this work for
 * additional information regarding copyright ownership.
 */

package scala.scalajs.js

import scala.language.implicitConversions

import scala.scalajs.js
import scala.scalajs.js.annotation._

import scala.collection.mutable
import mutable.Builder

import scala.collection.generic.CanBuildFrom

/** Wrapper to use a js.Dictionary as a scala.mutable.Map */
@inline
final class WrappedDictionary[A](private val dict: js.Dictionary[A])
    extends mutable.AbstractMap[String, A]
       with mutable.Map[String, A]
       with mutable.MapLike[String, A, js.WrappedDictionary[A]] {

  import WrappedDictionary._

  def get(key: String): Option[A] = {
    if (contains(key))
      Some(rawApply(key))
    else
      None
  }

  override def apply(key: String): A = {
    if (contains(key))
      rawApply(key)
    else
      throw new NoSuchElementException("key not found: " + key)
  }

  override def getOrElse[V1 >: A](key: String, default: => V1): V1 = {
    if (contains(key))
      rawApply(key)
    else
      default
  }

  override def getOrElseUpdate(key: String, op: => A): A = {
    if (contains(key)) {
      rawApply(key)
    } else {
      val v = op
      update(key, v)
      v
    }
  }

  @inline
  private def rawApply(key: String): A =
    dict.asInstanceOf[DictionaryRawApply[A]].rawApply(key)

  override def contains(key: String): Boolean = {
    /* We have to use a safe version of hasOwnProperty, because
     * "hasOwnProperty" could be a key of this dictionary.
     */
    safeHasOwnProperty(dict, key)
  }

  def -=(key: String): this.type = {
    if (contains(key))
      js.special.delete(dict, key)
    this
  }

  override def update(key: String, value: A): Unit =
    dict.asInstanceOf[DictionaryRawApply[A]].rawUpdate(key, value)

  def +=(kv: (String, A)): this.type = {
    dict(kv._1) = kv._2
    this
  }

  def iterator: scala.collection.Iterator[(String, A)] =
    new DictionaryIterator(dict)

  @inline
  override def keys: scala.collection.Iterable[String] =
    js.Object.keys(dict.asInstanceOf[js.Object])

  override def empty: js.WrappedDictionary[A] =
    new js.WrappedDictionary(Dictionary.empty)

}

object WrappedDictionary {
  // Note: We can't extend MutableMapFactory[WrappedDictionary] since
  // it requires support for any type of key

  private object Cache {
    val safeHasOwnProperty =
      js.Dynamic.global.Object.prototype.hasOwnProperty
        .asInstanceOf[js.ThisFunction1[js.Dictionary[_], String, Boolean]]
  }

  @inline
  private def safeHasOwnProperty(dict: js.Dictionary[_], key: String): Boolean =
    Cache.safeHasOwnProperty(dict, key)

  @js.native
  private trait DictionaryRawApply[A] extends js.Object {
    /** Reads a field of this object by its name.
     *
     *  This must not be called if the dictionary does not contain the key.
     */
    @JSBracketAccess
    def rawApply(key: String): A = js.native

    /** Writes a field of this object. */
    @JSBracketAccess
    def rawUpdate(key: String, value: A): Unit = js.native
  }

  private final class DictionaryIterator[+A](
      dict: js.Dictionary[A]) extends scala.collection.Iterator[(String, A)] {

    private[this] val keys = js.Object.keys(dict.asInstanceOf[js.Object])
    private[this] var index: Int = 0

    def hasNext: Boolean = index < keys.length

    def next(): (String, A) = {
      val key = keys(index)
      index += 1
      (key, dict(key))
    }
  }

  def empty[A]: js.WrappedDictionary[A] =
    new js.WrappedDictionary(js.Dictionary.empty)

  implicit def canBuildFrom[A]: CanBuildFrom[js.WrappedDictionary[_], (String, A), js.WrappedDictionary[A]] = {
    new CanBuildFrom[js.WrappedDictionary[_], (String, A), js.WrappedDictionary[A]] {
      def apply(from: js.WrappedDictionary[_]): Builder[(String, A), js.WrappedDictionary[A]] =
        new WrappedDictionaryBuilder[A]
      def apply(): Builder[(String, A), js.WrappedDictionary[A]] =
        new WrappedDictionaryBuilder[A]
    }
  }

  private final class WrappedDictionaryBuilder[A]
      extends Builder[(String, A), js.WrappedDictionary[A]] {

    private[this] var dict: js.Dictionary[A] = js.Dictionary.empty

    def +=(elem: (String, A)): this.type = {
      dict(elem._1) = elem._2
      this
    }

    def clear(): Unit =
      dict = js.Dictionary.empty

    def result(): js.WrappedDictionary[A] =
      new js.WrappedDictionary(dict)
  }

  implicit def toJSDictionary[A](wrappedDict: js.WrappedDictionary[A]): js.Dictionary[A] =
    wrappedDict.dict

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy