Skip to content
Open
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
Expand Up @@ -62,3 +62,7 @@
## 2026-08-11 - Array의 toMutableList 할당 오버헤드 최적화
**학습:** 배열을 정렬하기 위해 `.toMutableList()`를 호출하면 새로운 `ArrayList` 객체와 내부 배열 객체가 할당되어 대규모 디렉토리를 순회할 때 가비지 컬렉션(GC) 부하를 유발합니다. 배열 복제가 필요한 경우 `.clone()`을 사용하면 하나의 배열 객체만 새로 할당되므로 더 효율적입니다.
**조치:** 디렉토리 파일 배열을 정렬하기 전에 복사할 때 `.toMutableList()` 대신 `.clone()`을 사용하여 불필요한 중간 컬렉션 할당을 제거하고 성능을 향상시켰습니다.

## 2025-01-25 - HTML 이스케이프 문자 매핑 배열 기반 룩업 최적화
**학습:** Kotlin에서 `when` 조건문을 사용한 문자 매핑은 핫 패스(hot path)에서 분기 테이블 조회를 수행하므로 오버헤드가 발생합니다. 직접 배열 기반 룩업(`Array<String?>`)을 사용하면 훨씬 빠릅니다.
**조치:** `escapeHtml` 함수의 `when` 조건문을 `Constants` 객체에 정의된 `htmlEscapes` 배열 룩업으로 교체했습니다. 배열 초기화 시 Kotlin 1.3 하위 호환성을 위해 타입 파라미터(`<String?>`)를 명시하고 바운드 체크(`cInt < 128`)를 추가하여 예외를 방지했습니다.
21 changes: 12 additions & 9 deletions src/main/kotlin/html4tree/main.kt
Original file line number Diff line number Diff line change
Expand Up @@ -236,15 +236,8 @@ fun String.escapeHtml(): String {
var sb: StringBuilder? = null
for (i in 0 until this.length) {
val c = this[i]
val replacement = when (c) {
'&' -> "&amp;"
'<' -> "&lt;"
'>' -> "&gt;"
'"' -> "&quot;"
'\'' -> "&#x27;"
'`' -> "&#x60;"
else -> null
}
val cInt = c.toInt()
val replacement = if (cInt < 128) Constants.htmlEscapes[cInt] else null
Comment on lines +239 to +240

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📝 Info: Escaping behavior remains equivalent

htmlEscapes preserves all six mappings. Kotlin characters cannot be negative, and the upper-bound guard leaves every non-ASCII character unchanged.

Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

if (replacement != null) {
if (sb == null) {
sb = StringBuilder(this.length + 16)
Expand Down Expand Up @@ -496,6 +489,16 @@ fun help() {
}

private object Constants {
@JvmField
val htmlEscapes: Array<String?> = Array<String?>(128) { null }.apply {
this['&'.toInt()] = "&amp;"
this['<'.toInt()] = "&lt;"
this['>'.toInt()] = "&gt;"
this['"'.toInt()] = "&quot;"
this['\''.toInt()] = "&#x27;"
this['`'.toInt()] = "&#x60;"
}

@JvmField
val defaultSensitiveFiles = listOf(".git", ".env", ".ssh", ".htpasswd", ".htaccess", "id_rsa", "id_ed25519", "secrets.yml", ".html4ignore", ".DS_Store", ".aws", ".kube", ".npmrc", ".gnupg", "config.json", "credentials.json")

Expand Down
Loading