Я пытаюсь использовать макрос, чтобы устранить необходимость в scala для создания объекта функции, передаваемого вниз. Этот код используется во внутренних циклах нашей системы, и мы не хотим, чтобы внутренний цикл просто бесконечно выделял объекты. Это создает для нас проблемы с производительностью.
Наш исходный код был таким:
dis.withBitLengthLimit(newLimit){... body ...}
И тело было функцией, которая была передана как функциональный объект.
У меня проблема в том, что исходная версия без макросов относится к «этому». Мой обходной путь ниже заключается в том, чтобы каждое место, где вызывается макрос, передавали «этот» объект в качестве другого аргумента. то есть, уродливый, как:
dis.withBitLengthLimit(dis, newLimit){... body ...}
Это не ужасно, но кажется, что передача dis
не нужна.
Есть ли более чистый способ?
Вот макрос ниже.
object IOMacros {
/**
* Used to temporarily vary the bit length limit.
*
* Implementing as a macro eliminates the creation of a downward function object every time this
* is called.
*
* ISSUE: this macro really wants to use a self reference to `this`. But when a macro is expanded
* the object that `this` represents changes. Until a better way to do this comes about, we have to pass
* the `this` object to the `self` argument, which makes calls look like:
* dis.withBitLengthLimit(dis, newLimit){... body ...}
* That looks redundant, and it is, but it's more important to get the allocation of this downward function
* object out of inner loops.
*/
def withBitLengthLimitMacro(c: Context)(self: c.Tree, lengthLimitInBits: c.Tree)(body: c.Tree) = {
import c.universe._
q"""{
import edu.illinois.ncsa.daffodil.util.MaybeULong
val ___dStream = $self
val ___newLengthLimit = $lengthLimitInBits
val ___savedLengthLimit = ___dStream.bitLimit0b
if (!___dStream.setBitLimit0b(MaybeULong(___dStream.bitPos0b + ___newLengthLimit))) false
else {
try {
$body
} finally {
___dStream.resetBitLimit0b(___savedLengthLimit)
}
true
}
}"""
}