Skip to content

Commit

Permalink
Documents the RLE class & adds RLE.Companion.emit (#1642)
Browse files Browse the repository at this point in the history
  • Loading branch information
soywiz authored May 30, 2023
1 parent 3485567 commit d509af3
Showing 1 changed file with 24 additions and 7 deletions.
31 changes: 24 additions & 7 deletions kds/src/commonMain/kotlin/korlibs/datastructure/algo/RLE.kt
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,26 @@ package korlibs.datastructure.algo

import korlibs.datastructure.IntArrayList

/**
* Run-Length Encoding. Allows to generate and emit RLE chunks.
*/
class RLE(val capacity: Int = 7) {
/** RAW data in chunks of three values: start, count and data */
val data = IntArrayList(capacity)

/** Number of RLE chunks */
val count get() = data.size / 3

/** Emits an RLE chunk starting in [start] with [count] elements repeated of the specified [value] */
fun emit(start: Int, count: Int, value: Int) {
this.data.add(start, count, value)
}
/** Resets this RLE to start from scratch */
fun clear() {
data.clear()
}

/** Iterates over the RLE chunks emitting in function [block] the number of the chunk, the start of the chunk, its size, and the repeated value */
inline fun fastForEach(block: (n: Int, start: Int, count: Int, value: Int) -> Unit) {
for (n in 0 until count) {
block(n, data[n * 3 + 0], data[n * 3 + 1], data[n * 3 + 2])
Expand All @@ -33,29 +44,35 @@ class RLE(val capacity: Int = 7) {
append(")")
}

fun clear() {
data.clear()
}

companion object {
/** Generates a [RLE] sequence based on the [data] in the segment [start] and [end]. When providing [out], that RLE is reused. */
inline fun compute(data: IntArray, start: Int = 0, end: Int = data.size, out: RLE = RLE()): RLE =
compute(end - start, out) { data[start + it] }

/** Generates a new [RLE] or reuses [out], from a sequence of [count] items, generated by the [gen] function. Emitted value can be filtered with the [filter] function. */
inline fun compute(count: Int, out: RLE = RLE(), filter: (value: Int) -> Boolean = { true }, gen: (index: Int) -> Int): RLE {
out.clear()
emit(count, emit = { _, start, count, value ->
if (filter(value)) out.emit(start, count, value)
}, gen = gen)
return out
}

/** Processes a RLE sequence of [count] elements generated by the [gen] function, and calls [emit] function for every [RLE] segment */
inline fun emit(count: Int, emit: (n: Int, start: Int, count: Int, value: Int) -> Unit, gen: (index: Int) -> Int) {
var lastValue = 0
var currentStart = 0
var nchunk = 0
for (n in 0 until count + 1) {
val value = if (n == count) lastValue + 1 else gen(n)
if (n == 0 || value != lastValue) {
if (currentStart != n && filter(lastValue)) {
out.emit(currentStart, n - currentStart, lastValue)
if (currentStart != n) {
emit(nchunk++, currentStart, n - currentStart, lastValue)
}
currentStart = n
}
lastValue = value
}
return out
}
}
}

0 comments on commit d509af3

Please sign in to comment.