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

org.sisioh.baseunits.scala.intervals.IntervalMap.scala Maven / Gradle / Ivy

There is a newer version: 0.1.22
Show newest version
/*
 * Copyright 2011 Sisioh Project and the Others.
 * lastModified : 2011/04/22
 *
 * This file is part of Tricreo.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
 * either express or implied. See the License for the specific language
 * governing permissions and limitations under the License.
 */
package org.sisioh.baseunits.scala.intervals

import scala.collection.Iterator
import scala.collection.immutable.{ Map, MapLike }

/**
 * 区間に対して値をマッピングする抽象クラス。
 *
 * @author j5ik2o
 * @tparam A キーとなる区間の型
 * @tparam B 値の型
 */
abstract class IntervalMap[A <% Ordered[A], +B]
    extends Map[Interval[A], B]
    with MapLike[Interval[A], B, IntervalMap[A, B]] {

  protected val intervalMap: Map[Interval[A], B]

  override def empty: IntervalMap[A, B] = new LinearIntervalMap

  /**
   * Add a key/value pair to this map.
   * @param key the key
   * @param value the value
   * @return A new map with the new binding added to this map
   */
  override def updated[B1 >: B](key: Interval[A], value: B1): IntervalMap[A, B1] =
    new LinearIntervalMap(intervalMap.updated(key, value))

  def get(key: LimitValue[A]): Option[B]

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

  /**
   * 指定した区間と共通部分を持つ区間に対するマッピングがマップに含まれている場合に `true` を返す。
   * @param interval 区間
   * @return 指定した区間と共通部分を持つ区間に対するマッピングがマップに含まれている場合は`true`、そうでない場合は`false`
   */
  def containsIntersectingKey(interval: Interval[A]): Boolean

}

class LinearIntervalMap[A <% Ordered[A], B](protected val intervalMap: Map[Interval[A], B])
    extends IntervalMap[A, B] {

  /**
   * インスタンスを生成する。
   *
   * `intervalMap`は空を利用する。
   */
  def this() = this(Map.empty[Interval[A], B])

  override def toString(): String = intervalMap.toString

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

  private def directPut(source: Map[Interval[A], B], intervalSequence: Seq[Interval[A]], value: 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

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

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

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

  def +[B1 >: B](kv: (Interval[A], B1)): LinearIntervalMap[A, B1] = {
    val removed = this.-(kv._1)
    val result = removed.intervalMap.+(kv)
    new LinearIntervalMap(result)
  }

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

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

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

}

/**
 * `LinearIntervalMap`コンパニオンオブジェクト。
 *
 * @author j5ik2o
 */
object LinearIntervalMap {

  /**
   * インスタンスを生成する。
   *
   * @tparam A キーの型
   * @tparam B 値の型
   * @return [[org.sisioh.baseunits.scala.intervals.LinearIntervalMap]]
   */
  def apply[A <% Ordered[A], B]: LinearIntervalMap[A, B] = new LinearIntervalMap

  /**
   * ファクトリメソッド。
   *
   * @tparam A キーの型
   * @tparam B 値の型
   * @return [[org.sisioh.baseunits.scala.intervals.LinearIntervalMap]]
   */
  def apply[A <% Ordered[A], B](intervalMap: Map[Interval[A], B]): LinearIntervalMap[A, B] =
    new LinearIntervalMap(intervalMap)

  /**
   * 抽出子メソッド。
   *
   * @tparam A キーの型
   * @tparam B 値の型
   * @return [[org.sisioh.baseunits.scala.intervals.LinearIntervalMap]]
   */
  def unapply[A <% Ordered[A], B](linearIntervalMap: LinearIntervalMap[A, B]): Option[Map[Interval[A], B]] =
    Some(linearIntervalMap.intervalMap)

}





© 2015 - 2025 Weber Informatics LLC | Privacy Policy