commonMain.com.ditchoom.buffer.FragmentedReadBuffer.kt Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of buffer-jvm Show documentation
Show all versions of buffer-jvm Show documentation
Multiplatform bytebuffer that delegates to native byte[] or ByteBuffer
package com.ditchoom.buffer
/**
* Provides a single ReadBuffer interface that delegates to multiple buffers.
* While reading from a buffer sometimes you might need more data to complete the decoding operation. This class will
* handle reading from multiple fragmented buffers in memory and provide a simple read api.
*/
class FragmentedReadBuffer(
private val first: ReadBuffer,
private val second: ReadBuffer
) : ReadBuffer {
private val firstInitialLimit = first.limit()
private val secondInitialLimit = second.limit()
private var currentPosition = 0
private var currentLimit = firstInitialLimit + secondInitialLimit
override fun setLimit(limit: Int) {
if (limit <= firstInitialLimit + secondInitialLimit) {
currentLimit = limit
}
}
override fun limit() = firstInitialLimit + secondInitialLimit
override fun position() = currentPosition
override fun position(newPosition: Int) {
currentPosition = newPosition
}
override fun resetForRead() {
currentPosition = 0
}
override fun readByte(): Byte {
return if (currentPosition++ < firstInitialLimit) {
first.readByte()
} else {
second.readByte()
}
}
private fun readSizeIntoBuffer(size: Int, block: (ReadBuffer) -> T): T {
val buffer = if (currentPosition < firstInitialLimit && currentPosition + size <= firstInitialLimit) {
block(first)
} else if (currentPosition < firstInitialLimit && currentPosition + size > firstInitialLimit) {
val firstChunkSize = firstInitialLimit - currentPosition
val secondChunkSize = size - firstChunkSize
val secondBufferLimit = second.limit().toInt()
second.setLimit((second.position() + secondChunkSize).toInt())
val buffer = PlatformBuffer.allocate(size)
buffer.write(first)
buffer.write(second)
second.setLimit(secondBufferLimit)
buffer.resetForRead()
block(buffer)
} else {
block(second)
}
currentPosition += size
return buffer
}
override fun slice(): ReadBuffer {
val first = first.slice()
val second = second.slice()
val buffer = PlatformBuffer.allocate(first.limit() + second.limit())
buffer.write(first)
buffer.write(second)
buffer.resetForRead()
return buffer
}
override fun readByteArray(size: Int): ByteArray {
return readSizeIntoBuffer(size) { it.readByteArray(size) }
}
override fun readShort() = readSizeIntoBuffer(Short.SIZE_BYTES) { it.readShort() }
override fun readInt() = readSizeIntoBuffer(Int.SIZE_BYTES) { it.readInt() }
override fun readLong() = readSizeIntoBuffer(ULong.SIZE_BYTES) { it.readLong() }
override fun readUtf8(bytes: Int) = readSizeIntoBuffer(bytes) { it.readUtf8(bytes) }
override fun readUtf8Line(): CharSequence {
if (currentPosition < firstInitialLimit) {
val initialFirstPosition = first.position()
val firstUtf8 = first.readUtf8Line()
val bytesRead = first.position() - initialFirstPosition
return if (firstUtf8.toString().utf8Length().toLong() == bytesRead.toLong()) {
// read the entire string, check the second one
currentPosition = firstInitialLimit
val secondInitialPosition = second.position()
val secondLine = second.readUtf8Line()
currentPosition += second.position() - secondInitialPosition
StringBuilder(firstUtf8).append(secondLine)
} else {
firstUtf8
}
} else {
val secondInitialPosition = second.position()
val line = second.readUtf8Line()
currentPosition += second.position() - secondInitialPosition
return line
}
}
fun getBuffers(out: MutableList) {
if (first is FragmentedReadBuffer) {
first.getBuffers(out)
} else if (first is PlatformBuffer) {
out += first
}
if (second is FragmentedReadBuffer) {
second.getBuffers(out)
} else if (second is PlatformBuffer) {
out += second
}
}
}
fun List.toComposableBuffer(): ReadBuffer {
return when (size) {
1 -> {
first()
}
else -> {
FragmentedReadBuffer(
first(),
subList(1, size).toComposableBuffer()
)
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy