add future implementation

This commit is contained in:
Raffaele Mignone 2020-03-29 18:12:08 +02:00
parent 48849063a4
commit 4782ec428f
Signed by: norangebit
GPG Key ID: F5255658CB220573
6 changed files with 187 additions and 1 deletions

View File

@ -503,7 +503,7 @@ style:
MagicNumber:
active: true
excludes: "**/test/**,**/androidTest/**,**/*.Test.kt,**/*.Spec.kt,**/*.Spek.kt"
ignoreNumbers: '-1,0,1,2,100,500,1000'
ignoreNumbers: '-1,0,1,2,3,42,100,500,1000,4242'
ignoreHashCodeFunction: true
ignorePropertyDeclaration: false
ignoreLocalVariableDeclaration: false

View File

@ -0,0 +1,66 @@
package util.future
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking
interface Future<T> {
suspend fun get(): T
suspend fun get(timeout: Long): T?
fun isDone(): Boolean
fun cancel()
fun isCancelled(): Boolean
}
class CoFuture<T>(private val func: suspend () -> T) : Future<T> {
private var value: T? = null
private var job = GlobalScope.launch {
value = func()
}
override suspend fun get(): T {
job.join()
return value!!
}
override suspend fun get(timeout: Long): T? {
delay(timeout)
return value
}
override fun isDone(): Boolean = job.isCompleted
override fun cancel() {
job.cancel()
}
override fun isCancelled(): Boolean = job.isCancelled
}
fun <T> future(func: suspend () -> T): Future<T> = CoFuture(func)
fun <T> delayedEcho(value: T, delay: Long = 1000): Future<T> = future {
delay(delay)
value
}
class MathFuture {
fun add(a: Int, b: Int): Future<Int> = future { a + b }
}
fun main() = runBlocking {
val future = delayedEcho(42, delay = 2000)
println("do other work.")
println(future.get())
val math = MathFuture()
val sums = (0 until 100)
.map { math.add(it, it * 2) }
println("End all sums.")
sums.forEach {
println(it.get())
}
}

View File

@ -0,0 +1,45 @@
package util.future
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.Job
import kotlinx.coroutines.isActive
import kotlinx.coroutines.launch
import java.lang.reflect.InvocationHandler
import java.lang.reflect.Method
import java.lang.reflect.Proxy
import java.util.concurrent.LinkedBlockingQueue
import java.util.concurrent.TimeUnit
class FutureHandler(private val target: Any) : InvocationHandler {
private val queue = LinkedBlockingQueue<LatchFuture<*>>()
override fun invoke(proxy: Any?, method: Method?, args: Array<out Any>?): Any {
val future = method!!.invoke(target, *args!!) as LatchFuture<*>
queue.add(future)
return future
}
fun start(): Job {
return GlobalScope.launch {
while (isActive || queue.isNotEmpty()) {
queue.poll(100, TimeUnit.MILLISECONDS)
?.exec()
}
}
}
}
fun <T> Any.toFutureHandler(inter: Class<T>): Pair<T, Job> {
val futureHandler = FutureHandler(this)
val job = futureHandler.start()
return Pair(
Proxy.newProxyInstance(
this::class.java.classLoader,
arrayOf(inter),
futureHandler
) as T, job
)
}

View File

@ -0,0 +1,38 @@
package util.future
import java.util.concurrent.CountDownLatch
import java.util.concurrent.Future
import java.util.concurrent.TimeUnit
class LatchFuture<T>(private val func: () -> T) : Future<T> {
private val latch = CountDownLatch(1)
private var isCancelled = false
private var value: T? = null
override fun isDone(): Boolean = value != null
override fun get(): T {
latch.await()
return value!!
}
override fun get(p0: Long, p1: TimeUnit): T? {
p1.sleep(p0)
return value
}
override fun cancel(p0: Boolean): Boolean {
isCancelled = true
latch.countDown()
return isCancelled
}
override fun isCancelled(): Boolean = isCancelled
fun exec() {
if (!isCancelled) {
value = func()
latch.countDown()
}
}
}

View File

@ -0,0 +1,24 @@
package util.future
import kotlinx.coroutines.cancelAndJoin
import kotlinx.coroutines.runBlocking
import java.util.concurrent.Future
import kotlin.time.ExperimentalTime
import kotlin.time.measureTime
@ExperimentalTime
fun main() = runBlocking {
val (math, job) = FutureMathImpl().toFutureHandler(FutureMath::class.java)
lateinit var sums: List<Future<Int>>
val elapsed = measureTime {
sums = (0 until 100).map { math.add(it, it * 2) }
}
println("Elapsed time: $elapsed")
sums.forEach { println(it.get()) }
job.cancelAndJoin()
}

View File

@ -0,0 +1,13 @@
package util.future
import java.util.concurrent.Future
interface FutureMath {
fun add(a: Int, b: Int): Future<Int>
}
class FutureMathImpl : FutureMath {
override fun add(a: Int, b: Int): Future<Int> {
return LatchFuture { a + b }
}
}