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

japgolly.microlibs.utils.IMap.scala Maven / Gradle / Ivy

The newest version!
package japgolly.microlibs.utils

import cats.Eq
import japgolly.microlibs.nonempty.NonEmpty
import japgolly.microlibs.stdlib_ext.MutableArray
import japgolly.univeq.UnivEq

object IMap {
  @inline implicit def catsEq[K, V: Eq]: Eq[IMap[K, V]] =
    IMapBase.catsEq[K, V, IMap[K, V]]

  @inline implicit def univEq[K, V](implicit u: UnivEq[Map[K, V]]): UnivEq[IMap[K, V]] =
    IMapBase.univEq[K, V, IMap[K, V]](u)

  implicit def nonEmptyProof[K, V]: NonEmpty.ProofMono[IMap[K, V]] =
    NonEmpty.Proof.testEmptiness(_.isEmpty)

  def empty[K: UnivEq, V](k: V => K): IMap[K, V] =
    new IMap(k, Map.empty)
}

/**
 * Intrinsic-Invariant Map.
 *
 * A map with automatically-managed intrinsic-invariants.
 * The relationship between map-key and value is guaranteed to be consistent.
 *
 * Values are mapped by a subset of themselves.
 */
final class IMap[K: UnivEq, V] private (key: V => K, m: Map[K, V]) extends IMapBase[K, V, IMap[K, V]](m) {

  override protected def stringPrefix = "IMap"
  override protected def setmap(n: M) = new IMap(key, n)
  override protected def _gkey(v: V)  = key(v)

  def get(k: K): Option[V] =
    m.get(k)

  def need(k: K): V = {
    val o = get(k)
    if (o.isEmpty)
      throw new RuntimeException(badKeyMsg(k))
    else
      o.get
  }

  def getAttempt(k: K): Either[String, V] =
    get(k).toRight(badKeyMsg(k))

  private def badKeyMsg(k: K): String = {
    val keyArray = MutableArray(keysIterator().map(_.toString)).sort
    val max = 10
    val keyDesc =
      if (keyArray.length > max)
        keyArray.iterator().take(max).mkString("{", ", ", ", ... }")
      else
        keyArray.iterator().mkString("{", ", ", "}")
    s"Value not found for $k.\nKeys = $keyDesc"
  }

  def modifyValues(f: V => V): This =
    new IMap(key, m.valuesIterator.map(f).map(v => key(v) -> v).toMap)

  def modify(k: K, f: V => V)(implicit ev: V <:< AnyRef): This =
    _mod(k, f, this)

  def modifyOrPut(k: K, f: V => V, put: => V)(implicit ev: V <:< AnyRef): This =
    _mod(k, f, this add put)

  private def _mod(k: K, f: V => V, nomod: => IMap[K, V])(implicit ev: V <:< AnyRef): This =
    m.get(k).fold(nomod)(v => {
      val v2 = f(v)
      if (ev(v) eq ev(v2))
        this
      else {
        val k2 = key(v2)
        var n = m.updated(k2, v2)
        if (k != k2) n -= k
        setmap(n)
      }
    })

  def empty: This =
    IMap.empty(key)
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy