Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .jules/bolt.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
## 2024-07-14 - Optimize Hex Color Parsing and Formatting in KMP Hot Paths
**Learning:** In Kotlin Multiplatform hot paths (such as hex color serialization and parsing), manual character array manipulation and bitwise shifts are substantially faster (up to 25x faster for serialization and 10x faster for parsing) than using standard library string methods like `toString(16).padStart()`, `uppercase()`, or `substring().toLong(16).toInt()`. This approach avoids platform-specific string allocation overhead.
**Action:** When working in KMP hot paths, avoid standard library string manipulations that instantiate multiple objects per call. Favor `CharArray`, manual index iteration, bitwise shifts, and `concatToString()` to minimize allocations and latency.

## 2025-01-22 - Optimize Linearized Color Conversion using Lookup Tables
**Learning:** In Kotlin Multiplatform, when mathematical operations depend strictly on a small, discrete domain (e.g., converting 8-bit color components 0-255 from sRGB to linear space), utilizing pre-computed arrays or lookup tables (like `DoubleArray(256)`) instead of redundant on-the-fly computation (divisions, conditionals, `.pow()`) significantly improves performance in hot paths like HCT or XYZ conversions.
**Action:** Always check if mathematical operations within performance-critical functions operate on a limited, discrete set of inputs. If so, prefer instantiating a lookup array during initialization to replace complex calculations like branching and exponents with simple array index lookups.
Original file line number Diff line number Diff line change
Expand Up @@ -85,15 +85,19 @@ internal object ColorUtils {
return 116.0 * labF(y / 100.0) - 16.0
}

fun linearized(rgbComponent: Int): Double {
private val LINEARIZED_LUT = DoubleArray(256) { rgbComponent ->
val normalized = rgbComponent / 255.0
return if (normalized <= 0.040449936) {
if (normalized <= 0.040449936) {
normalized / 12.92 * 100.0
} else {
((normalized + 0.055) / 1.055).pow(2.4) * 100.0
}
}

fun linearized(rgbComponent: Int): Double {
return LINEARIZED_LUT[MathUtils.clampInt(0, 255, rgbComponent)]
}

fun delinearized(rgbComponent: Double): Int {
val normalized = rgbComponent / 100.0
val delinearized: Double = if (normalized <= 0.0031308) {
Expand Down
Loading