From f9616656120d4959aca2c904b87fad4d68b787a4 Mon Sep 17 00:00:00 2001 From: seonghobae <8172694+seonghobae@users.noreply.github.com> Date: Tue, 1 Sep 2026 20:53:04 +0000 Subject: [PATCH 1/4] =?UTF-8?q?=EC=84=B1=EB=8A=A5=20=EA=B0=9C=EC=84=A0:=20?= =?UTF-8?q?HTML=20=EC=9D=B4=EC=8A=A4=EC=BC=80=EC=9D=B4=ED=94=84=20?= =?UTF-8?q?=ED=95=AB=ED=8C=A8=EC=8A=A4=20=EB=B0=B0=EC=97=B4=20=EB=A3=A9?= =?UTF-8?q?=EC=97=85=20=EC=B5=9C=EC=A0=81=ED=99=94?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - escapeHtml 함수의 when 분기 테이블을 상수 배열 룩업으로 교체 - Constants 객체에 htmlEscapes JvmField 배열 정의 - 100% 테스트 커버리지 유지 (cInt < 128 바운드 체크) --- .jules/bolt.md | 4 ++++ src/main/kotlin/html4tree/main.kt | 21 ++++++++++++--------- 2 files changed, 16 insertions(+), 9 deletions(-) diff --git a/.jules/bolt.md b/.jules/bolt.md index ee124e69..aaad06c6 100644 --- a/.jules/bolt.md +++ b/.jules/bolt.md @@ -62,3 +62,7 @@ ## 2026-08-11 - Array의 toMutableList 할당 오버헤드 최적화 **학습:** 배열을 정렬하기 위해 `.toMutableList()`를 호출하면 새로운 `ArrayList` 객체와 내부 배열 객체가 할당되어 대규모 디렉토리를 순회할 때 가비지 컬렉션(GC) 부하를 유발합니다. 배열 복제가 필요한 경우 `.clone()`을 사용하면 하나의 배열 객체만 새로 할당되므로 더 효율적입니다. **조치:** 디렉토리 파일 배열을 정렬하기 전에 복사할 때 `.toMutableList()` 대신 `.clone()`을 사용하여 불필요한 중간 컬렉션 할당을 제거하고 성능을 향상시켰습니다. + +## 2025-01-25 - HTML 이스케이프 문자 매핑 배열 기반 룩업 최적화 +**학습:** Kotlin에서 `when` 조건문을 사용한 문자 매핑은 핫 패스(hot path)에서 분기 테이블 조회를 수행하므로 오버헤드가 발생합니다. 직접 배열 기반 룩업(`Array`)을 사용하면 훨씬 빠릅니다. +**조치:** `escapeHtml` 함수의 `when` 조건문을 `Constants` 객체에 정의된 `htmlEscapes` 배열 룩업으로 교체했습니다. 배열 초기화 시 Kotlin 1.3 하위 호환성을 위해 타입 파라미터(``)를 명시하고 바운드 체크(`cInt < 128`)를 추가하여 예외를 방지했습니다. diff --git a/src/main/kotlin/html4tree/main.kt b/src/main/kotlin/html4tree/main.kt index 0972fa2c..593cda7a 100644 --- a/src/main/kotlin/html4tree/main.kt +++ b/src/main/kotlin/html4tree/main.kt @@ -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) { - '&' -> "&" - '<' -> "<" - '>' -> ">" - '"' -> """ - '\'' -> "'" - '`' -> "`" - else -> null - } + val cInt = c.toInt() + val replacement = if (cInt < 128) Constants.htmlEscapes[cInt] else null if (replacement != null) { if (sb == null) { sb = StringBuilder(this.length + 16) @@ -496,6 +489,16 @@ fun help() { } private object Constants { + @JvmField + val htmlEscapes: Array = Array(128) { null }.apply { + this['&'.toInt()] = "&" + this['<'.toInt()] = "<" + this['>'.toInt()] = ">" + this['"'.toInt()] = """ + this['\''.toInt()] = "'" + this['`'.toInt()] = "`" + } + @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") From 1110dc953ee47d1b71bc2d8d55019f175cba9d4b Mon Sep 17 00:00:00 2001 From: seonghobae <8172694+seonghobae@users.noreply.github.com> Date: Wed, 2 Sep 2026 00:04:34 +0000 Subject: [PATCH 2/4] =?UTF-8?q?=EC=84=B1=EB=8A=A5=20=EA=B0=9C=EC=84=A0:=20?= =?UTF-8?q?HTML=20=EC=9D=B4=EC=8A=A4=EC=BC=80=EC=9D=B4=ED=94=84=20?= =?UTF-8?q?=ED=95=AB=ED=8C=A8=EC=8A=A4=20=EB=B0=B0=EC=97=B4=20=EB=A3=A9?= =?UTF-8?q?=EC=97=85=20=EC=B5=9C=EC=A0=81=ED=99=94?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - escapeHtml 함수의 when 분기 테이블을 상수 배열 룩업으로 교체 - Constants 객체에 htmlEscapes JvmField 배열 정의 - 100% 테스트 커버리지 유지 (cInt < 128 바운드 체크) From 83a0be97ad9c974423cab4de2125c4d2bd1819f1 Mon Sep 17 00:00:00 2001 From: seonghobae <8172694+seonghobae@users.noreply.github.com> Date: Wed, 2 Sep 2026 08:14:27 +0000 Subject: [PATCH 3/4] =?UTF-8?q?=EC=84=B1=EB=8A=A5=20=EA=B0=9C=EC=84=A0:=20?= =?UTF-8?q?HTML=20=EC=9D=B4=EC=8A=A4=EC=BC=80=EC=9D=B4=ED=94=84=20?= =?UTF-8?q?=ED=95=AB=ED=8C=A8=EC=8A=A4=20=EB=B0=B0=EC=97=B4=20=EB=A3=A9?= =?UTF-8?q?=EC=97=85=20=EC=B5=9C=EC=A0=81=ED=99=94?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - escapeHtml 함수의 when 분기 테이블을 상수 배열 룩업으로 교체 - Constants 객체에 htmlEscapes JvmField 배열 정의 - 100% 테스트 커버리지 유지 (cInt < 128 바운드 체크) From fcf74cae0beb5fd9791969452b70945a5108881a Mon Sep 17 00:00:00 2001 From: seonghobae <8172694+seonghobae@users.noreply.github.com> Date: Wed, 2 Sep 2026 18:13:22 +0000 Subject: [PATCH 4/4] =?UTF-8?q?=EC=84=B1=EB=8A=A5=20=EA=B0=9C=EC=84=A0:=20?= =?UTF-8?q?HTML=20=EC=9D=B4=EC=8A=A4=EC=BC=80=EC=9D=B4=ED=94=84=20?= =?UTF-8?q?=ED=95=AB=ED=8C=A8=EC=8A=A4=20=EB=B0=B0=EC=97=B4=20=EB=A3=A9?= =?UTF-8?q?=EC=97=85=20=EC=B5=9C=EC=A0=81=ED=99=94?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - escapeHtml 함수의 when 분기 테이블을 상수 배열 룩업으로 교체 - Constants 객체에 htmlEscapes JvmField 배열 정의 - 100% 테스트 커버리지 유지 (cInt < 128 바운드 체크)