Skip to content

Remove consumeCommonEdges from histogram diff anchor recursion #109

Description

@mundi4

Summary

run-histogram-diff.tsdiffCore에서 앵커를 찾은 뒤 앵커 전후 서브구간에 대해 consumeCommonEdges를 호출하고 있다. 이 로직은 제거해도 정확성에 영향이 없다.

분석

현재 흐름 (96~117행)

앵커 발견
→ consumeCommonEdges(lhsLower~anchor.lhsStart, direction=2 suffix)  → 재귀
→ 앵커 UNCHANGED 기록
→ consumeCommonEdges(anchor.lhsEnd~lhsUpper, direction=1 prefix)   → 재귀

제거 가능한 이유

  1. ID가 이미 정규화된 buffer 위에서 부여됨: buildDiffInput에서 whitespace === "collapse"이면 공백을 삽입한 buffer를 만들고, buildIdTables는 그 buffer의 raw byte로 ID를 부여한다. 즉 ID 자체가 공백 정규화된 텍스트를 반영.

  2. SA/LCP가 같은 ID를 본다: findAnchor에서 구축하는 SA/LCP는 _lhsIds/_rhsIds 위에서 동작하므로, consumeCommonEdges_lhsIds[i] === _rhsIds[j] 체크가 잡는 것은 SA도 동일하게 잡을 수 있다.

  3. matchPrefixTokens/matchSuffixTokens가 SA를 보완하는 실질적 케이스가 없다: 이 함수들은 토큰 경계를 넘어 char-by-char 비교를 하지만, tokenizer가 결정적(deterministic)이므로 같은 텍스트에서 토큰 분할이 달라지는 경우가 사실상 없다. ignoreWhitespace 모드에서도 마찬가지.

  4. consume의 유일한 효과는 성능 최적화: 앵커 인접 동일 토큰을 O(k) 스캔으로 먹어서 재귀 + SA 재구축(O(n log n))을 피한다. 하지만 재귀로 내려가도 결국 같은 결과에 도달하므로, 코드 복잡성 대비 가치가 낮다.

앵커 미발견 시 consume (120~123행)

if (_ignoreWhitespaces) {
    ([lhsLower, lhsUpper, rhsLower, rhsUpper] = consumeCommonEdges(lhsLower, lhsUpper, rhsLower, rhsUpper, 3));
}

이 부분도 같은 논리로, SA가 앵커를 못 찾은 구간에서 matchPrefixTokens가 추가로 잡는 케이스가 사실상 없다.

변경 범위

  • core/src/diff/run-histogram-diff.ts: consumeCommonEdges 함수 및 호출부 제거
  • core/src/diff/helpers.ts: matchPrefixTokens, matchSuffixTokens export 제거 가능 (다른 곳에서 사용하지 않는 경우)

검증

  • 기존 테스트 통과 확인
  • whitespace: "collapse" / "ignore" 양쪽 모드에서 diff 결과 동일 확인 필요

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions