CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/maven-io-ktor--ktor-io-watchosarm64

Asynchronous I/O library for Kotlin multiplatform providing channels, streams, and byte manipulation utilities optimized for watchOS ARM64

Pending
Overview
Eval results
Files

object-pooling.mddocs/

Object Pooling

Resource management system providing efficient object reuse patterns with configurable capacity and lifecycle management.

Capabilities

ObjectPool Interface

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()

Pool Implementation Classes

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
    }
}

ByteArrayPool Object

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)
    }
}

Pool Utility Functions

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): R

Usage 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()
}

Pool Configuration and Best Practices

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

docs

async-channels.md

byte-order.md

character-encoding.md

index.md

memory-management.md

object-pooling.md

packet-io.md

tile.json