Last active
January 18, 2017 20:08
-
-
Save akozhemiakin/da32277668a84718e084063fa9925c4e to your computer and use it in GitHub Desktop.
Moving frame
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import scala.collection.mutable.ArrayBuffer | |
import scala.util.Try | |
class FrameReader[A]( | |
before: Int, | |
after: Int, | |
onNextFrame: (MovingFrame[A], Boolean) => Unit | |
) { | |
private val b: ArrayBuffer[A] = ArrayBuffer() | |
private var cf: Option[MovingFrame[A]] = None | |
private var finished: Boolean = false | |
def feed(a: A, isLast: Boolean = false): Unit = { | |
if (finished) throw new RuntimeException("The FrameReader in finished state can not be used any more") | |
cf = cf.map(_.move(a)).orElse { | |
b += a | |
if (isLast || b.size == after + 1) Some(MovingFrame.initial(b.toVector, before)) else None | |
} | |
if (isLast) { | |
cf.foreach(_.foreach(f => onNextFrame(f, f.move.isEmpty))) | |
finished = true | |
} else cf.foreach(x => onNextFrame(x, false)) | |
} | |
} | |
final case class MovingFrame[A]( | |
current: A, | |
before: Vector[A], | |
beforeLimit: Int, | |
after: Vector[A] | |
) extends Traversable[MovingFrame[A]] { | |
private var moveCache: Option[Option[MovingFrame[A]]] = None | |
def up(n: Int): Option[A] = Try(before(before.size - n)).toOption | |
def down(n: Int): Option[A] = Try(after(n - 1)).toOption | |
def next: Option[A] = down(1) | |
def prev: Option[A] = up(1) | |
def move(a: A): MovingFrame[A] = MovingFrame( | |
next.getOrElse(a), | |
before.takeRight(beforeLimit - 1) :+ current, | |
beforeLimit, | |
if (after.isEmpty) Vector() else after.drop(1) :+ a | |
) | |
def move: Option[MovingFrame[A]] = moveCache.getOrElse { | |
val nv = next.map(a => MovingFrame( | |
a, | |
before.takeRight(beforeLimit - 1) :+ current, | |
beforeLimit, | |
after.drop(1) | |
)) | |
moveCache = Some(nv) | |
nv | |
} | |
override def foreach[U](f: (MovingFrame[A]) => U): Unit = { | |
f(this) | |
move.foreach(_.foreach(f)) | |
} | |
} | |
object MovingFrame { | |
def initial[A](els: Vector[A], beforeLimit: Int): MovingFrame[A] = | |
MovingFrame(els.head, Vector(), beforeLimit, els.tail) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment