Asynchronous I/O library for Kotlin multiplatform providing channels, streams, and byte manipulation utilities optimized for watchOS ARM64
—
Resource management system providing efficient object reuse patterns with configurable capacity and lifecycle management.
Generic object pooling interface extending Closeable for automatic resource management and efficient object reuse.
/**
* Generic object pool interface for efficient resource management.
* Provides object reuse to reduce allocation overhead and garbage collection pressure.
*/
interface ObjectPool<T> : Closeable {
/** Maximum number of objects the pool can hold */
val capacity: Int
/**
* Borrow an object from the pool.
* Creates a new instance if pool is empty and capacity allows.
* @return object instance ready for use
*/
fun borrow(): T
/**
* Return an object to the pool for future reuse.
* Object should be reset to clean state before recycling.
* @param instance object to return to pool
*/
fun recycle(instance: T)
/**
* Dispose all objects in the pool and release resources.
* Pool becomes unusable after disposal.
*/
fun dispose()
/**
* Close the pool (same as dispose).
* Implements Closeable interface for use-with-resources patterns.
*/
override fun close() = dispose()
}Usage Examples:
import io.ktor.utils.io.pool.*
// Create a custom pool for StringBuilder objects
val stringBuilderPool = object : DefaultPool<StringBuilder>(capacity = 10) {
override fun produce(): StringBuilder = StringBuilder()
override fun reset(instance: StringBuilder): StringBuilder {
instance.clear()
return instance
}
}
// Use the pool
val sb = stringBuilderPool.borrow()
try {
sb.append("Hello ")
sb.append("World")
val result = sb.toString()
println(result)
} finally {
stringBuilderPool.recycle(sb)
}
// Pool cleanup
stringBuilderPool.close()Abstract base classes and concrete implementations for different pooling strategies.
/**
* Abstract base class for pools with zero capacity.
* Always creates new instances instead of pooling.
*/
abstract class NoPoolImpl<T> : ObjectPool<T> {
override val capacity: Int = 0
/**
* Create a new instance (not pooled).
* @return new object instance
*/
protected abstract fun produce(): T
override fun borrow(): T = produce()
override fun recycle(instance: T) {} // No-op for zero capacity
override fun dispose() {} // No-op for zero capacity
}
/**
* Abstract pool that produces at most one instance.
* Suitable for expensive-to-create singleton-like objects.
*/
abstract class SingleInstancePool<T> : ObjectPool<T> {
override val capacity: Int = 1
/**
* Create the single instance.
* @return new object instance
*/
protected abstract fun produce(): T
/**
* Reset instance to clean state before reuse.
* @param instance object to reset
* @return reset object (same instance or replacement)
*/
protected abstract fun reset(instance: T): T
override fun borrow(): T
override fun recycle(instance: T)
override fun dispose()
}
/**
* Default pool implementation with configurable capacity.
* Thread-safe implementation optimized for concurrent access.
*/
abstract class DefaultPool<T>(override val capacity: Int) : ObjectPool<T> {
/**
* Create a new instance when pool is empty.
* @return new object instance
*/
protected abstract fun produce(): T
/**
* Reset instance to clean state before recycling.
* @param instance object to reset
* @return reset object (same instance or replacement)
*/
protected open fun reset(instance: T): T = instance
/**
* Validate instance before recycling.
* @param instance object to validate
* @return true if instance can be recycled
*/
protected open fun validateInstance(instance: T): Boolean = true
/**
* Dispose an instance when it cannot be recycled.
* @param instance object to dispose
*/
protected open fun disposeInstance(instance: T) {}
override fun borrow(): T
override fun recycle(instance: T)
override fun dispose()
}Usage Examples:
import io.ktor.utils.io.pool.*
// Custom pool with validation
class ByteArrayPool(capacity: Int, private val arraySize: Int) : DefaultPool<ByteArray>(capacity) {
override fun produce(): ByteArray = ByteArray(arraySize)
override fun reset(instance: ByteArray): ByteArray {
instance.fill(0) // Clear array
return instance
}
override fun validateInstance(instance: ByteArray): Boolean {
return instance.size == arraySize // Ensure correct size
}
}
val pool = ByteArrayPool(capacity = 5, arraySize = 1024)
// Use pool with validation
val array = pool.borrow()
// ... use array ...
pool.recycle(array) // Will be validated and reset
// Single instance pool example
class ExpensiveResourcePool : SingleInstancePool<ExpensiveResource>() {
override fun produce(): ExpensiveResource = ExpensiveResource()
override fun reset(instance: ExpensiveResource): ExpensiveResource {
instance.reset()
return instance
}
}Pre-configured global pool for byte arrays with optimized settings for I/O operations.
/**
* Global byte array pool optimized for I/O operations.
* Provides efficient reuse of byte arrays to reduce allocation overhead.
*/
object ByteArrayPool : ObjectPool<ByteArray> {
override val capacity: Int
/**
* Borrow a byte array from the global pool.
* Array size is implementation-specific and optimized for common I/O operations.
* @return byte array ready for use
*/
override fun borrow(): ByteArray
/**
* Return byte array to the global pool.
* Array will be reused for future borrow() calls.
* @param instance byte array to recycle
*/
override fun recycle(instance: ByteArray)
override fun dispose()
override fun close() = dispose()
}Usage Examples:
import io.ktor.utils.io.pool.*
import io.ktor.utils.io.*
// Use global byte array pool
val buffer = ByteArrayPool.borrow()
try {
// Perform I/O operations with the buffer
val channel: ByteReadChannel = TODO()
val bytesRead = channel.readAvailable(buffer, 0, buffer.size)
// Process data in buffer
processData(buffer, bytesRead)
} finally {
// Always return to pool
ByteArrayPool.recycle(buffer)
}
// Integration with channels
suspend fun efficientCopy(source: ByteReadChannel, dest: ByteWriteChannel) {
val buffer = ByteArrayPool.borrow()
try {
while (!source.isClosedForRead) {
val bytesRead = source.readAvailable(buffer, 0, buffer.size)
if (bytesRead > 0) {
dest.writeFully(buffer, 0, bytesRead)
}
}
} finally {
ByteArrayPool.recycle(buffer)
}
}Utility functions for convenient pool usage with automatic resource management.
/**
* Use an object from the pool with automatic return.
* Ensures object is returned to pool even if block throws exception.
* @param block operation to perform with borrowed object
* @return result of the block operation
*/
inline fun <T : Any, R> ObjectPool<T>.useInstance(block: (T) -> R): RUsage Examples:
import io.ktor.utils.io.pool.*
// Safe pool usage with automatic cleanup
val result = ByteArrayPool.useInstance { buffer ->
// Use buffer safely - it will be automatically returned
performIOOperation(buffer)
"Operation completed"
}
// Custom pool with useInstance
class StringBuilderPool : DefaultPool<StringBuilder>(capacity = 10) {
override fun produce(): StringBuilder = StringBuilder()
override fun reset(instance: StringBuilder): StringBuilder {
instance.clear()
return instance
}
}
val pool = StringBuilderPool()
val formattedString = pool.useInstance { sb ->
sb.append("User: ")
sb.append("Alice")
sb.append(", Age: ")
sb.append(25)
sb.toString()
}
// Multiple nested pool usage
val complexResult = pool.useInstance { outerSb ->
outerSb.append("Outer: ")
val innerResult = pool.useInstance { innerSb ->
innerSb.append("Inner content")
innerSb.toString()
}
outerSb.append(innerResult)
outerSb.toString()
}Configuration options and usage patterns for optimal pool performance.
/**
* No-pool implementation that always creates new instances.
* Use when pooling overhead exceeds benefits.
*/
fun <T> ObjectPool.Companion.NoPool(): ObjectPool<T> where T : Any
/**
* Create a simple pool with basic configuration.
* @param capacity maximum objects to pool
* @param produce factory function for creating instances
* @param reset optional reset function for cleaning instances
* @return configured pool instance
*/
fun <T> ObjectPool.Companion.create(
capacity: Int,
produce: () -> T,
reset: (T) -> T = { it }
): ObjectPool<T>Best Practices Examples:
import io.ktor.utils.io.pool.*
// Choose appropriate pool size based on usage patterns
class OptimizedBufferPool {
// Small pool for frequent, short-lived operations
private val smallBuffers = object : DefaultPool<ByteArray>(capacity = 16) {
override fun produce() = ByteArray(1024)
}
// Larger pool for less frequent, longer-lived operations
private val largeBuffers = object : DefaultPool<ByteArray>(capacity = 4) {
override fun produce() = ByteArray(64 * 1024)
}
fun borrowSmall(): ByteArray = smallBuffers.borrow()
fun recycleSmall(buffer: ByteArray) = smallBuffers.recycle(buffer)
fun borrowLarge(): ByteArray = largeBuffers.borrow()
fun recycleLarge(buffer: ByteArray) = largeBuffers.recycle(buffer)
}
// Pool with validation and cleanup
class ValidatingPool<T>(
capacity: Int,
private val factory: () -> T,
private val validator: (T) -> Boolean,
private val cleaner: (T) -> T
) : DefaultPool<T>(capacity) {
override fun produce(): T = factory()
override fun validateInstance(instance: T): Boolean = validator(instance)
override fun reset(instance: T): T = cleaner(instance)
}
// Thread-safe usage pattern
class ThreadSafePoolUser {
private val pool = object : DefaultPool<StringBuilder>(10) {
override fun produce() = StringBuilder()
override fun reset(instance: StringBuilder) = instance.apply { clear() }
}
fun formatMessage(user: String, message: String): String {
return pool.useInstance { sb ->
sb.append("[")
sb.append(System.currentTimeMillis())
sb.append("] ")
sb.append(user)
sb.append(": ")
sb.append(message)
sb.toString()
}
}
}
// Resource lifecycle management
class ManagedPoolExample : AutoCloseable {
private val pools = mutableListOf<ObjectPool<*>>()
fun <T> createPool(
capacity: Int,
factory: () -> T,
cleaner: (T) -> T = { it }
): ObjectPool<T> {
val pool = object : DefaultPool<T>(capacity) {
override fun produce() = factory()
override fun reset(instance: T) = cleaner(instance)
}
pools.add(pool)
return pool
}
override fun close() {
pools.forEach { it.dispose() }
pools.clear()
}
}Install with Tessl CLI
npx tessl i tessl/maven-io-ktor--ktor-io-watchosarm64