주입 op 셋(mountInst/unmountInst/disposeInst)으로는 Move/Swap을 아예 표현할
수 없다는 지적에서 시작해 물리 조작 계층 전체를 재설계했다.
층위 정의(사용자): raw*는 그 Slot 스코프 안의 연산(평탄화 전, _elements
인덱스), native*는 확정된 offset/length로 표현되는 물리 트리 연산(평탄화 후,
절대 좌표).
표면 여섯:
nativeInsert (target, offset, elements)
nativeExtract(target, offset, elements, newElements?) -- 빼되 살림
nativeRemove (target, offset, elements, newElements?) -- 빼면서 파괴
nativeMove (target, fromOffset, elements, toOffset)
nativeSwap (target, offsetA, elementsA, offsetB, elementsB)
nativeDispose(element) -- 트리 밖 값 파괴
- Replace는 별도 op이 아니라 newElements가 있는 Remove/Extract(Splice도 동일)
— 제거+삽입을 한 호출로 합쳐 리플로우 2회와 그 사이 인덱스가 어긋난 창을
없앤다
- 파괴/비파괴를 불리언이 아니라 이름으로 가름 — 공개 CRUD의 Remove/Extract
어휘를 물려받고, Roblox의 "Parent=nil 없이 그 자리에서 Destroy" 융합을 연다
- 빠지는 요소는 반드시 배열로 넘김 — (target, offset, count)로 대상을 찾을 수
있는 건 DOM뿐이고 Roblox는 자식이 순서 없는 집합이라 offset 역조회가 안 됨
- nativeSwap은 별도 — Move는 사이를 전부 밀지만 Swap은 가운데 고정
- 미주입이면 에러가 아니라 조합 폴백(addTag 계열과 갈리는 지점)
- 전제: 한 Slot의 물리 자식은 부모 안에서 연속 구간을 차지한다
그 여파로 4라운드 C-7 일반 계약이 역전됨 — "Length를 먼저 올려 밀어내고 그
공간에 넣는다"는 그림은 base에 물리적으로 자리를 비워둘 수단이 없어 성립하지
않는다. 규칙이 "빼기는 물리 먼저/넣기는 부기 먼저" 두 얼굴에서
"자기 자리를 정하는 것(setOffsetSource) 먼저 / 뒤를 미는 것(setLength→
recompute) 나중" 하나로 줄었다. 배치 경로(materializeSlotTree→mountSlotTree)의
부기-전량-먼저는 C6가 요구하는 별개 사안이라 그대로.
원문은 archive/bookkeeping-before-physical-reversed.md.
같이: getOffsetAt을 사용자 의사코드대로 단일 함수 + invalidAfter로 정정
(무효화는 min(invalidAfter, i) 하나, recompute도 그 캐시 위에 얹혀 O(N)).
doc-check.py ERROR 0. 상세는
qa-request/pre-implementation-qa-round5-followup.md의 L절.
Co-authored-by: qwreey <me@qwreey.moe>