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

pl.iterators.stir.util.TupleOps.scala Maven / Gradle / Ivy

The newest version!
package pl.iterators.stir.util

import scala.annotation.nowarn

class TupleOps[T](val tuple: T) extends AnyVal {
  import TupleOps._

  /**
   * Appends the given value to the tuple producing a tuple of arity n + 1.
   */
  def append[S](value: S)(implicit ao: AppendOne[T, S]): ao.Out = ao(tuple, value)

  /**
   * Left-Folds over the tuple using the given binary poly-function.
   */
  def foldLeft[In](zero: In)(op: BinaryPolyFunc)(implicit fold: FoldLeft[In, T, op.type]): fold.Out = fold(zero, tuple)

  /**
   * Appends the given tuple to the underlying tuple producing a tuple of arity n + m.
   */
  def join[S](suffixTuple: S)(implicit join: Join[T, S]): join.Out = join(tuple, suffixTuple)
}

object TupleOps {
  @nowarn
  implicit def enhanceTuple[T: Tuple](tuple: T): TupleOps[T] = new TupleOps(tuple)

  trait AppendOne[P, S] {
    type Out
    def apply(prefix: P, last: S): Out
  }
  object AppendOne extends TupleAppendOneInstances

  trait FoldLeft[In, T, Op] {
    type Out
    def apply(zero: In, tuple: T): Out
  }
  object FoldLeft extends TupleFoldInstances

  trait Join[P, S] {
    type Out
    def apply(prefix: P, suffix: S): Out
  }
  type JoinAux[P, S, O] = Join[P, S] { type Out = O }
  object Join extends LowLevelJoinImplicits {
    // O(1) shortcut for the Join[Unit, T] case to avoid O(n) runtime in this case
    implicit def join0P[T]: JoinAux[Unit, T, T] =
      new Join[Unit, T] {
        type Out = T
        def apply(prefix: Unit, suffix: T): Out = suffix
      }
    // we implement the join by folding over the suffix with the prefix as growing accumulator
    object Fold extends BinaryPolyFunc {
      implicit def step[T, A](
          implicit append: AppendOne[T, A]): BinaryPolyFunc.Case[T, A, Fold.type] { type Out = append.Out } =
        at[T, A](append(_, _))
    }
  }
  sealed abstract class LowLevelJoinImplicits {
    implicit def join[P, S](implicit fold: FoldLeft[P, S, Join.Fold.type]): JoinAux[P, S, fold.Out] =
      new Join[P, S] {
        type Out = fold.Out
        def apply(prefix: P, suffix: S): Out = fold(prefix, suffix)
      }
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy