ByteBufferPoolExt.kt
package org.knio.core.context
import java.nio.*
import kotlin.jvm.Throws
private val DUMMY_BUFFER = ByteBuffer.wrap(byteArrayOf(0))
/**
* Interface representing a buffer that can be released back to a pool.
*
* @param T the type of buffer
*/
internal interface ReleasableBuffer<T: Buffer> {
/**
* Whether the buffer has been released.
*/
val released: Boolean
/**
* The buffer contained in the ReleasableBuffer. It should be noted that the buffer
* may be swapped out for a new buffer if the buffer is resized or released. If you
* assign this value to a variable, be conscious of the fact that the buffer may be
* replaced.
*
*
* @throws IllegalStateException if the buffer has been released
*/
@get:Throws(IllegalStateException::class)
val value: T
/**
* Releases the buffer back to the pool.
*/
fun release()
/**
* Resizes the buffer.
*
* @param newSize the new size of the buffer
*
* @throws BufferOverflowException if the new size is smaller than the current size and the buffer has more data
* available than the new buffer's size
* @throws IllegalStateException if the buffer has been released
*/
@Throws(BufferOverflowException::class, IllegalStateException::class)
fun resize(newSize: Int)
}
/**
* Generic implementation of ReleasableBuffer.
*
* @param T the type of buffer
* @property buffer the ByteBuffer instance
* @property pool the ByteBufferPool to release the buffer to
* @property transformer a function to transform the ByteBuffer to the desired buffer type
*/
internal class ReleasableBufferImpl<T: Buffer>(
private val pool: ByteBufferPool,
size: Int,
private val bytesPerUnit: Int,
private val transformer: (ByteBuffer) -> T
) : ReleasableBuffer<T> {
override var released = false
private set
private var buffer = pool.acquire(getBufferSize(size, bytesPerUnit))
override var value: T = transformer(buffer)
get() {
if (released) {
throw IllegalStateException("Buffer has been released")
}
return field
}
private set
/**
* Releases the ByteBuffer back to the pool.
*/
override fun release() {
if (!released) {
val buffer = buffer
this.buffer = DUMMY_BUFFER
this.value = transformer(DUMMY_BUFFER)
pool.release(buffer)
released = true
}
}
/**
* Resizes the buffer.
*
* This method will acquire a new buffer from the pool, copy the contents of the current buffer to the new buffer,
* and release the current buffer back to the pool.
*
* @param newSize the new size of the buffer
*/
override fun resize(newSize: Int) {
if (released) {
throw IllegalStateException("Buffer has been released")
}
val oldValue = value
val valuePosition = oldValue.position()
val valueLimit = oldValue.limit()
val valueLimitDelta = valueLimit - valuePosition
buffer.position(valuePosition * bytesPerUnit)
buffer.limit(valueLimit * bytesPerUnit)
val newBuffer = pool.acquire(getBufferSize(newSize, bytesPerUnit))
newBuffer.put(buffer)
newBuffer.position(0)
newBuffer.limit(newBuffer.capacity())
val newValue = transformer(newBuffer)
newValue.limit(valueLimitDelta)
buffer = newBuffer
value = newValue
pool.release(buffer)
}
}
private fun asByteBuffer(buffer: ByteBuffer): ByteBuffer = buffer
/**
* Transforms a ByteBuffer into a CharBuffer.
*
* @param buffer the ByteBuffer to transform
* @return the resulting CharBuffer
*/
private fun asCharBuffer(buffer: ByteBuffer): CharBuffer = buffer.asCharBuffer()
/**
* Acquires a releasable ByteBuffer from the pool.
*
* @param size the size of the ByteBuffer to acquire
* @return a ReleasableBuffer containing the acquired ByteBuffer
*/
internal fun ByteBufferPool.acquireReleasableByteBuffer(size: Int): ReleasableBuffer<ByteBuffer> =
ReleasableBufferImpl(this, size, BYTES_PER_BYTE, ::asByteBuffer)
/**
* Acquires a releasable CharBuffer from the pool.
*
* For internal use only. The pools shouldn't be used outsize of the context of the Knio.
*
* @param size the size, in chars, of the CharBuffer to acquire.
* @return a ReleasableBuffer containing the acquired CharBuffer
*/
internal fun ByteBufferPool.acquireReleasableCharBuffer(size: Int): ReleasableBuffer<CharBuffer> =
ReleasableBufferImpl(this, size, BYTES_PER_CHAR, ::asCharBuffer)