Skip to content

Instantly share code, notes, and snippets.

@yakamoto69
Created December 7, 2012 12:13
Show Gist options
  • Select an option

  • Save yakamoto69/4232911 to your computer and use it in GitHub Desktop.

Select an option

Save yakamoto69/4232911 to your computer and use it in GitHub Desktop.
A Pager, Handles Sequential Data as a Link of Pages.
class Pager[A](seq: Sequential[A], chunkSize: Int) {
self =>
import Pager._
private val ls: GrowingList[Chunk[A]] = mkGrowingList(seq, chunkSize)
var pageNo: Int = _
def hasNext: Boolean = {
ls.get(pageNo + 1).isDefined
}
def next() {
pageNo += 1
}
def prev() {
pageNo -= 1
}
def get: Option[Chunk[A]] = {
ls.get(pageNo)
}
def isValid: Boolean = ls.get(pageNo).isDefined
// Iterator.continually or Iterator.iterate maybe make it more readable.
def iterator: Iterator[Chunk[A]] = {
new Iterator[Chunk[A]] {
def hasNext = self.isValid
def next() = {
get match {
case Some(chunk) => {
self.next()
chunk
}
case None => throw new IllegalStateException()
}
}
}
}
}
class GrowingList[N <: Node[N]](root: N, nextF: N => Option[N]) {
/* TODO
* At this moment, if a node is made once, it will never be changed.
* I want to implement some validation feature, in which if a node is judged as invalid, the node will be recreated on demand.
*/
def get(ix: Int): Option[N] = {
val nodes = Iterator.iterate(nextOf(root)) { prev =>
prev flatMap nextOf
}
// If None continues, though this is a bit inefficient, never mind it!
nodes.drop(ix).next()
}
private def nextOf(n: N): Option[N] = {
n.next(nextF(n))
}
}
trait Node[N <: Node[N]] {
def next(init: => Option[N]): Option[N]
}
trait Sequential[A] {
/**
* If `from` is None, returns first elements.
*/
def getGt(from: Option[A], max: Int): Seq[A]
}
/**
* If a chunk is the root, `lst` must be None.
* Otherwise, `fst` and `lst` never be None.
* It's ugly... What wrong happened?
*/
class Chunk[A](val fst: Option[A],
val lst: Option[A]) extends Node[Chunk[A]] {
// TODO This is a cache, use any caching library if exists.
var n: Option[Option[Chunk[A]]] = None
def next(init: => Option[Chunk[A]]): Option[Chunk[A]] = {
// I don't like this. This looks too imperative.
n getOrElse {
val a = init
n = Some(a)
a
}
}
override def toString = "fst:"+fst+",lst:"+lst
}
object Pager {
def mkGrowingList[A](seq: Sequential[A], chunkSize: Int): GrowingList[Chunk[A]] = {
val root = new Chunk[A](None, None)
def nextF(prev: Chunk[A]): Option[Chunk[A]] = {
// Whether can I convert List -> Option on any natural way?
val data = seq.getGt(prev.lst, chunkSize)
if (data.isEmpty)
None
else {
val fst = Some(data.head)
val lst = data.tail.lastOption orElse fst // fst and lst should have a value
val c = new Chunk[A](fst, lst)
Some(c)
}
}
new GrowingList(root, nextF)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment