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

com.github.j5ik2o.intervals.IntervalMap.scala Maven / Gradle / Ivy

There is a newer version: 1.0.59
Show newest version
package com.github.j5ik2o.intervals

import scala.collection.Iterator
import scala.collection.immutable.Map

/** 区間に対して値をマッピングする抽象クラス。
  *
  * @tparam A
  *   キーとなる区間の型
  * @tparam B
  *   値の型
  */
class IntervalMap[A, B](val values: Map[Interval[A], B]) {

  /** 要素が空のインスタンスを生成する。
    */
  def this() = this(Map.empty[Interval[A], B])

  override def toString: String = values.toString

  private def directPut(
      source: Map[Interval[A], B],
      intervalSequence: Seq[Interval[A]],
      value: B
  ): Map[Interval[A], B] = {
    val keyValues = collection.mutable.Map.empty[Interval[A], B]
    keyValues ++= source
    intervalSequence.foreach { e =>
      keyValues += (e -> value)
    }
    keyValues.toMap
  }

  def contains(key: LimitValue[A]): Boolean =
    findKeyIntervalContaining(key).isDefined

  def containsIntersectingKey(otherInterval: Interval[A]): Boolean =
    intersectingKeys(otherInterval).nonEmpty

  private def findKeyIntervalContaining(key: LimitValue[A]): Option[Interval[A]] =
    values.keys.find(_.includes(key))

  /** この写像が保持するキーとしての区間のうち、指定した区間 `otherInterval`と共通部分を持つ 区間の列を取得する。
    *
    * 戻り値の列は、区間の自然順にソートされている。
    *
    * @param otherInterval
    *   対象区間
    * @return
    *   指定した区間と共通部分を持つ区間の列
    */
  private def intersectingKeys(otherInterval: Interval[A]): Seq[Interval[A]] =
    values.keys.flatMap {
      case e if e.intersects(otherInterval) => Some(e)
      case _                                => None
    }.toSeq

  def put[B1 >: B](kv: (Interval[A], B1)): IntervalMap[A, B1] = {
    val removed = remove(kv._1)
    val result  = removed.values.+(kv)
    new IntervalMap(result)
  }

  def +[B1 >: B](kv: (Interval[A], B1)): IntervalMap[A, B1] = put(kv)

  def get(key: Interval[A]): Option[B] = values.get(key)

  def get(key: LimitValue[A]): Option[B] =
    findKeyIntervalContaining(key) match {
      case Some(key) => values.get(key)
      case None      => None
    }

  def remove(key: Interval[A]): IntervalMap[A, B] = {
    val intervalSeq = intersectingKeys(key)
    var currentMap  = values
    intervalSeq.foreach { oldInterval =>
      val oldValue = currentMap(oldInterval)
      currentMap -= oldInterval
      val complementIntervalSeq = key.complementRelativeTo(oldInterval)
      currentMap = directPut(currentMap, complementIntervalSeq, oldValue)
    }
    new IntervalMap(currentMap)
  }

  def -(key: Interval[A]): IntervalMap[A, B] = remove(key)

  def iterator: Iterator[(Interval[A], B)] = values.iterator

  def toMap: Map[Interval[A], B] = values

}

/** `IntervalMap`コンパニオンオブジェクト。
  */
object IntervalMap {

  /** インスタンスを生成する。
    *
    * @tparam A
    *   キーの型
    * @tparam B
    *   値の型
    * @return
    *   [[IntervalMap]]
    */
  def apply[A, B]: IntervalMap[A, B] =
    new IntervalMap()

  /** ファクトリメソッド。
    *
    * @tparam A
    *   キーの型
    * @tparam B
    *   値の型
    * @return
    *   [[IntervalMap]]
    */
  def apply[A, B](values: Map[Interval[A], B]): IntervalMap[A, B] =
    new IntervalMap(values)

  /** 抽出子メソッド。
    *
    * @tparam A
    *   キーの型
    * @tparam B
    *   値の型
    * @return
    *   [[LinearIntervalMap]]
    */
  def unapply[A, B](self: IntervalMap[A, B]): Option[Map[Interval[A], B]] =
    Some(self.values)

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy