Add defer support to memScope
This commit is contained in:
committed by
SvyatoslavScherbina
parent
9609a10e09
commit
2217be4003
@@ -36,12 +36,41 @@ object nativeHeap : NativeFreeablePlacement {
|
|||||||
override fun free(mem: NativePtr) = nativeMemUtils.free(mem)
|
override fun free(mem: NativePtr) = nativeMemUtils.free(mem)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private typealias Deferred = () -> Unit
|
||||||
|
|
||||||
|
open class DeferScope {
|
||||||
|
|
||||||
|
@PublishedApi
|
||||||
|
internal var topDeferred: Deferred? = null
|
||||||
|
|
||||||
|
internal fun executeAllDeferred() {
|
||||||
|
topDeferred?.let {
|
||||||
|
it.invoke()
|
||||||
|
topDeferred = null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inline fun defer(crossinline block: () -> Unit) {
|
||||||
|
val currentTop = topDeferred
|
||||||
|
topDeferred = {
|
||||||
|
try {
|
||||||
|
block()
|
||||||
|
} finally {
|
||||||
|
// TODO: it is possible to implement chaining without recursion,
|
||||||
|
// but it would require using an anonymous object here
|
||||||
|
// which is not yet supported in Kotlin Native inliner.
|
||||||
|
currentTop?.invoke()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: implement optimally
|
// TODO: implement optimally
|
||||||
class Arena(private val parent: NativeFreeablePlacement = nativeHeap) : NativePlacement {
|
open class ArenaBase(private val parent: NativeFreeablePlacement = nativeHeap) : NativePlacement, DeferScope() {
|
||||||
|
|
||||||
private val allocatedChunks = ArrayList<NativePointed>()
|
private val allocatedChunks = ArrayList<NativePointed>()
|
||||||
|
|
||||||
override fun alloc(size: Long, align: Int): NativePointed {
|
final override fun alloc(size: Long, align: Int): NativePointed {
|
||||||
val res = parent.alloc(size, align)
|
val res = parent.alloc(size, align)
|
||||||
try {
|
try {
|
||||||
allocatedChunks.add(res)
|
allocatedChunks.add(res)
|
||||||
@@ -52,7 +81,10 @@ class Arena(private val parent: NativeFreeablePlacement = nativeHeap) : NativePl
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun clear() {
|
@PublishedApi
|
||||||
|
internal fun clearImpl() {
|
||||||
|
this.executeAllDeferred()
|
||||||
|
|
||||||
allocatedChunks.forEach {
|
allocatedChunks.forEach {
|
||||||
parent.free(it)
|
parent.free(it)
|
||||||
}
|
}
|
||||||
@@ -62,6 +94,10 @@ class Arena(private val parent: NativeFreeablePlacement = nativeHeap) : NativePl
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class Arena(parent: NativeFreeablePlacement = nativeHeap) : ArenaBase(parent) {
|
||||||
|
fun clear() = this.clearImpl()
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Allocates variable of given type.
|
* Allocates variable of given type.
|
||||||
*
|
*
|
||||||
@@ -355,18 +391,14 @@ fun CPointer<ByteVar>.toKString(): String {
|
|||||||
return decodeFromUtf8(bytes)
|
return decodeFromUtf8(bytes)
|
||||||
}
|
}
|
||||||
|
|
||||||
class MemScope : NativePlacement {
|
class MemScope : ArenaBase() {
|
||||||
|
|
||||||
private val arena = Arena()
|
val memScope: MemScope
|
||||||
|
|
||||||
override fun alloc(size: Long, align: Int) = arena.alloc(size, align)
|
|
||||||
|
|
||||||
fun clear() = arena.clear()
|
|
||||||
|
|
||||||
val memScope: NativePlacement
|
|
||||||
get() = this
|
get() = this
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: consider renaming `memScoped` because it now supports `defer`.
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Runs given [block] providing allocation of memory
|
* Runs given [block] providing allocation of memory
|
||||||
* which will be automatically disposed at the end of this scope.
|
* which will be automatically disposed at the end of this scope.
|
||||||
@@ -376,7 +408,7 @@ inline fun <R> memScoped(block: MemScope.()->R): R {
|
|||||||
try {
|
try {
|
||||||
return memScope.block()
|
return memScope.block()
|
||||||
} finally {
|
} finally {
|
||||||
memScope.clear()
|
memScope.clearImpl()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user