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

scala.reactive.calc.Bijection.scala Maven / Gradle / Ivy

The newest version!
package scala.reactive
package calc






/** A bijective function between values of two types `T` and `S`.
 *
 *  A bijection maps every element of type `T` into exactly one
 *  element of type `S`, and every element of type `S` into exactly
 *  one element of type `T`.
 *  It is a function and its inverse bundled together.
 *  Additionally, it has the property that `b.inv(b.apply(x)) == x`
 *  and `b.apply(b.inv(x)) == x`.
 *
 *  '''Note:'''
 *  Bijection is specialized.
 *  Boxing is avoided for primitive values if both the source type
 *  and the target type are integers, longs or doubles.
 *
 *  @param T      the source type `T`
 *  @param S      the target type `S`
 */
trait Bijection[@spec(Int, Long, Double) T, @spec(Int, Long, Double) S] {
  /** Maps an element of type `T` to `S`.
   */
  def apply(t: T): S

  /** Inverse mapping from `S` to `T`.
   */
  def invert(s: S): T

  /** Produces a new bijection that is the inverse of this bijection --
   *  i.e. it swaps the arguments around.
   *  
   *  This is unlike `inv` which just inverse-maps an element.
   *  To just map in the inverse direction, use `inv`.
   */
  def inverse: Bijection[S, T] = this match {
    case Bijection.Inverted(b) => b
    case b => Bijection.Inverted(b)
  }

  /** Returns the function version of this bijection.
   *
   *  To get the inverse function, call `f.inverse.function`.
   */
  def function: T => S = (x: T) => apply(x)
}


/** Contains factory methods for bijection instances.
 */
object Bijection {

  /** Creates a new bijection from two function instances.
   *
   *  @tparam T       the source type `T`
   *  @tparam S       the source type `S`
   *  @param f        the function for the bijection
   *  @param i        the inverse for the bijection
   *  @return         the new bijection instance
   */
  def apply[@spec(Int, Long, Double) T, @spec(Int, Long, Double) S](f: T => S, i: S => T) = new Bijection.Default[T, S](f, i)

  private[reactive] class Default[@spec(Int, Long, Double) T, @spec(Int, Long, Double) S]
    (val f: T => S, val i: S => T)
  extends Bijection[T, S] {    
    def apply(t: T): S = f(t)
    def invert(s: S): T = i(s)
  }

  /** The inversion of a bijection.
   *
   *  @tparam T       the source type `T`
   *  @tparam S       the target type `S`
   *  @param b        the bijection being inverted.
   */
  case class Inverted[@spec(Int, Long, Double) T, @spec(Int, Long, Double) S](b: Bijection[T, S])
  extends Bijection[S, T] {
    def apply(s: S) = b.invert(s)
    def invert(t: T) = b.apply(t)
  }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy