Last active
August 10, 2016 19:13
-
-
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.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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