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

speed.impl.Optimizer.scala Maven / Gradle / Ivy

The newest version!
package speed.impl

import scala.annotation.tailrec

trait Optimizer { self: SpeedImpl ⇒
  import c.universe._

  def optimize(chain: OperationChain): OperationChain = {
    @tailrec def optimizeTerminalOnce(chain: OperationChain): OperationChain =
      optimizeTerminal(chain.terminal) match {
        case GenerationChangingTerminal(cons, term) ⇒ optimizeTerminalOnce(OperationChain(cons(chain.generator), term))
        case term @ _                               ⇒ OperationChain(optimizeGen(chain.generator), term)
      }

    optimizeTerminalOnce(chain)
  }

  def optimizeGen(gen: Generator): Generator = gen match {
    case IndexedGenerator(array) ⇒
      val arrayVar = c.fresh(newTermName("array$"))
      val init = q"val $arrayVar = $array"

      optimizeGen(
        InitAddingGenerator(
          MappingGenerator(RangeGenerator(q"0", q"$arrayVar.length", q"1", q"false"), Closure("idx", q"$arrayVar(idx)", q"")),
          Seq(init)))
    case ReverseGenerator(outer)      ⇒ optimizeGen(reverseRoot(optimizeGen(outer)))
    case TakeGenerator(outer, number) ⇒ optimizeTake(number)(outer)
    case i: InnerGenerator            ⇒ i.transformOuter(optimizeGen)
    case _                            ⇒ gen
  }

  def optimizeTerminal(terminal: TerminalOperation): TerminalOperation = terminal match {
    case Sum(num) ⇒ FoldLeft(q"$num.zero", closure2(q"$num.plus(_, _)"))
    case Min(ord) ⇒ minOrMax("min", ord)
    case Max(ord) ⇒ minOrMax("max", ord)
    case Size     ⇒ FoldLeft(q"0", closure2(q"((num, _) => num + 1)"))
    case Count(f) ⇒ GenerationChangingTerminal(FilteringGenerator(_, f), Size)
    case _        ⇒ terminal
  }

  def minOrMax(op: TermName, ord: Tree): TerminalOperation = {
    val Ord = typeOf[Ordering[_]].typeSymbol.asClass
    val OrdT = Ord.typeParams(0).asType.toType
    val cand = OrdT.asSeenFrom(ord.tpe, Ord)

    Reduce(cand, closure2(q"$ord.$op(_, _)"))
  }

  def reverseRoot(outer: Generator): Generator = outer match {
    case i: InnerGenerator                       ⇒ i.transformOuter(reverseRoot)

    // for simple Ranges it's simple...
    case RangeGenerator(start, end, q"1", incl)  ⇒ RangeGenerator(q"if ($incl) $end else $end - 1", start, q"-1", q"true")
    case RangeGenerator(start, end, q"-1", incl) ⇒ RangeGenerator(q"if ($incl) $end else $end + 1", start, q"1", q"true")

    // however when step != +/- 1 we'd need much of the range logic, so we stay from it right now and
    // fall back on the range runtime implementation
    // TODO: one easier possibility to fix it would be to make the RangeGenerator / RangeGeneration itself
    // able to deal with reversion
    case RangeGenerator(start, end, by, incl) ⇒
      range(q"""
        (if ($incl) $start to $end by $by
        else $start until $end by $by).reverse
      """)

    case ListGenerator(l, tpe) ⇒ ListGenerator(q"$l.reverse", tpe)
  }

  def optimizeTake(number: Tree)(outer: Generator): Generator = optimizeGen(outer) match {
    // we optimize only the common cases (also used for array access)
    case RangeGenerator(start, end, q"1", q"false")  ⇒ RangeGenerator(start, q"math.min($start + $number, $end)", q"1", q"false")
    case RangeGenerator(start, end, q"-1", q"false") ⇒ RangeGenerator(start, q"math.max($start - $number, $end)", q"-1", q"false")

    case i: InitAddingGenerator                      ⇒ i.transformOuter(optimizeTake(number))
    case m: MappingGenerator if m.f.isPure           ⇒ m.transformOuter(optimizeTake(number))

    case opt @ _                                     ⇒ TakeGenerator(opt, number)
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy