project/BufferableGenerator.scala (50 lines of code) (raw):
package bijection
object BufferableGenerator {
val pkg = "package com.twitter.bijection"
/* Example of the code generated:
implicit def tuple2[A,B](implicit ba: Bufferable[A], bb: Bufferable[B]): Bufferable[(A,B)] =
new AbstractBufferable[(A,B)] {
def put(bytebuf: ByteBuffer, tup: (A,B)) = {
var nextBb = bytebuf
nextBb = reallocatingPut(nextBb) { ba.put(_, tup._1) }
nextBb = reallocatingPut(nextBb) { bb.put(_, tup._2) }
nextBb
}
// this should perform better than for comprehension
def get(bytebuf: ByteBuffer) = attempt(bytebuf) { bytebuf =>
val (bufa, a) = ba.unsafeGet(bytebuf)
val (bufb, b) = bb.unsafeGet(bufa)
(bufb, (a,b))
}
}
*/
val lowerLetters = ('a' to 'z').toIndexedSeq
val upperLetters = ('A' to 'Z').toIndexedSeq
def bufferableParam(idx: Int) =
"b" + lowerLetters(idx) + ": Bufferable[" + upperLetters(idx) + "]"
def typeList(cnt: Int) =
upperLetters.slice(0, cnt) map { _.toString } mkString (",")
def tupleTypeList(cnt: Int) = "Tuple" + cnt + "[" + typeList(cnt) + "]"
def reallocatingPut(idx: Int) =
"nextBb = reallocatingPut(nextBb) { b" + lowerLetters(idx) + ".put(_, tup._" + (idx + 1) + ") }"
def bufferGet(idx: Int) = {
val getFrom = if (idx == 0) "bytebuf" else ("buf" + lowerLetters(idx - 1))
val lowlet = lowerLetters(idx)
"val (buf%s, %s) = b%s.unsafeGet(%s)".format(lowlet, lowlet, lowlet, getFrom)
}
def bufferableType(idx: Int) = "Bufferable[" + upperLetters(idx) + "]"
// Here we put it all together:
def implicitTuple(cnt: Int): String =
" implicit def tuple" + cnt + "[" + typeList(cnt) + "](implicit " +
((0 until cnt) map { bufferableParam(_) } mkString (", ")) + "):\n" +
" Bufferable[" + tupleTypeList(cnt) + "] = new AbstractBufferable[" + tupleTypeList(
cnt
) + "] {\n" +
" def put(bytebuf: ByteBuffer, tup: " + tupleTypeList(cnt) + ") = {\n" +
" var nextBb = bytebuf\n" +
" " + ((0 until cnt) map { reallocatingPut(_) }).mkString("", "\n ", "\n") +
" nextBb\n" +
" }\n" +
" def get(bytebuf: ByteBuffer) = attempt(bytebuf) { bytebuf =>\n" +
" " + ((0 until cnt) map { bufferGet(_) }).mkString("", "\n ", "\n") +
" val res = Tuple" + cnt + (0 until cnt)
.map { lowerLetters(_) }
.mkString("(", ", ", ")") + "\n" +
" (buf" + lowerLetters(cnt - 1) + ", res)\n" +
" }\n" +
" }"
def generate = {
val b = new StringBuffer
b.append("// Autogenerated code DO NOT EDIT BY HAND\n")
b.append(pkg).append("\n")
b.append("import Bufferable.reallocatingPut\n")
b.append("import java.nio.ByteBuffer\n")
b.append("import com.twitter.bijection.Inversion.attempt\n")
b.append("\ntrait GeneratedTupleBufferable {\n")
(1 to 22).foreach { cnt => b.append(implicitTuple(cnt)).append("\n") }
b.append("}")
b.toString
}
}