Skip to content

Instantly share code, notes, and snippets.

@akozhemiakin
Last active January 18, 2017 20:08
Show Gist options
  • Save akozhemiakin/da32277668a84718e084063fa9925c4e to your computer and use it in GitHub Desktop.
Save akozhemiakin/da32277668a84718e084063fa9925c4e to your computer and use it in GitHub Desktop.
Moving frame
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