Skip to content

Instantly share code, notes, and snippets.

@Groostav
Last active August 10, 2016 19:13
Show Gist options
  • Save Groostav/f2b81d567bd85f2c904c5ed395220fd3 to your computer and use it in GitHub Desktop.
Save Groostav/f2b81d567bd85f2c904c5ed395220fd3 to your computer and use it in GitHub Desktop.
Sample from our problem domain, where legacy clalback-based Fortran needs to be converted to a nice coroutine.
package com.empowerops.language
/**
* Created by Geoff on 2016-08-09.
*/
class GeneratorFrontEnd {
fun beginGeneration() = CallbackAdapter().let { it to it.initialPoint }
}
class LibraryUser {
fun doWerk() {
val generator = GeneratorFrontEnd();
val (coRoutine, startInput) = generator.beginGeneration()
var input = startInput;
for(int in 1..100){
input = coRoutine.next();
}
}
}
class CallbackAdapter {
val initialPoint = InputVector(1.0, 2.0, 3.0, 4.0)
private val inputs = generate<InputVector> {
PretendFortran.INSTANCE.__FANCY_NATIVE_SYNTAX { input ->
yield(input) //compiler error: suspension functions can be called only within a coroutine body
}
}.iterator()
fun start() = inputs.next()
fun next(): InputVector{
return inputs.next()
}
}
//region pretend fortran, uneditable code
class PretendFortran{
fun __FANCY_NATIVE_SYNTAX(callback: (InputVector) -> Unit):Unit {
InputVector(1.0, 2.0, 3.0, 4.0).apply(callback)
InputVector(1.1, 2.1, 3.1, 4.1).apply(callback)
InputVector(1.3, 2.3, 3.3, 4.3).apply(callback)
}
companion object {
val INSTANCE = PretendFortran()
}
}
//endregion
data class InputVector(val x: Double, val y: Double, val z: Double, val w: Double)
//region copypasta from kotlinx, will add proper dep later
/**
* Creates a Sequence object based on received coroutine [c].
*
* Each call of 'yield' suspend function within the coroutine lambda generates
* next element of resulting sequence.
*/
fun <T> generate(
coroutine c: GeneratorController<T>.() -> Continuation<Unit>
): Sequence<T> =
object : Sequence<T> {
override fun iterator(): Iterator<T> {
val iterator = GeneratorController<T>()
iterator.setNextStep(c(iterator))
return iterator
}
}
class GeneratorController<T> internal constructor() : AbstractIterator<T>() {
private lateinit var nextStep: Continuation<Unit>
override fun computeNext() {
nextStep.resume(Unit)
}
internal fun setNextStep(step: Continuation<Unit>) {
nextStep = step
}
suspend fun yield(value: T, c: Continuation<Unit>) {
setNext(value)
setNextStep(c)
}
}
//endregion
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment