본문으로 건너뛰기

행렬 선언 — 1급 엔티티 검토

문서 목록으로

상태: 도입되었습니다. 이 문서는 결정의 근거이고, 표기와 구현 상태는 매트릭스 선언에 있습니다.

결정을 가른 것은 2절의 인코딩이 아니라 5.1절의 표기였습니다. 6절이 재어 둔 대로 비용은 코드 생성에 몰렸고, 형식 · 런타임 · 익스포터 · 히스토리는 한 파일도 닿지 않았습니다.

table · enum · const · struct 옆에 matrix를 다섯 번째 선언 종류로 두는 것을 검토합니다. 기대하는 것은 둘입니다 — M×N이라는 구조에서 오는 인코딩 이득과, 그 구조를 아는 생성 코드.


결론 요약

확인한 것결과
인코딩이 줄어드는가거의 아닙니다. 격자는 이미 배열 컬럼 하나로 실리고, 그 스트림은 스칼라 컬럼과 같은 인코딩을 전부 받습니다
인코딩 이득이 있는 자리는 어디인가축의 선택입니다 — 행 우선으로 펼치는 것이 지금 고정되어 있습니다. 이것은 선언 종류 없이 인코더에서 됩니다
표기가 나아지는가예. 이것이 가장 큰 이득입니다 — 지금은 「이름이 정수인 컬럼」이라는 판독 규칙이고, 그래서 두 번째 축이 정수 키로 제한됩니다. 선언이 있으면 축의 키는 그 축의 타입입니다
생성 코드가 나아지는가둘이 나아집니다 — 두 축 조회가 한 번이 되고, 두 테이블이 같이 배포되어야 하는 제약이 없어집니다
구현 비용코드 생성에 거의 전부 몰립니다. 와이어 kind를 두지 않으면 형식 · 런타임 · 익스포터 · 히스토리가 전부 무변경입니다 — 6절
권고엔티티는 보류합니다. 9절의 순서로 진행하고, 그 결과가 부족할 때 다시 봅니다

1. 지금 격자를 표현하는 방법

셋이 이미 있습니다.

방법형태어디에
행 + 위치 배열{ id, value: T[N] } × M행, 그리고 컬럼 id를 담은 옆 테이블매트릭스 표. 이름 기반 레이아웃에 구현되어 있습니다
복합 키key="attacker,defender" 로 M×N행주 레이아웃 §3.5
배열의 배열한 행에 T[][]다중 중첩

매트릭스 표가 이미 답한 것이 이 검토의 출발점입니다 — 그 문서의 결론은 「매트릭스는 새 형태가 아니라 이미 표현할 수 있는 테이블의 다른 표기」 였고, 그래서 코어가 한 줄도 바뀌지 않았습니다. 이 검토는 그 판단을 뒤집을 근거가 생겼는지를 봅니다.

로드맵에 있는 것과 구분합니다. 주 레이아웃의 매트릭스 표읽기가 한쪽 레이아웃에만 있다는 문제이고, 선언 종류와 무관합니다. 그쪽이 사용자가 실제로 막히는 자리입니다.

2. 인코딩 — 새 선언 종류가 줄이는 바이트

219 × 482 = 105,558칸 격자를 기준으로 셉니다.

파일에 실리는 것지금matrix kind가 있으면차이
값 105,558개배열 컬럼 하나의 원소 스트림. 스칼라와 동일한 후보 전부(DELTA · RLE · DICT · BITPACK · 접두사 공유)같습니다0
행 길이 219개길이 스트림 → 모든 행이 같은 길이이므로 런 하나없어집니다약 3바이트
행 id 219개정수 컬럼 하나kind가 있어도 필요합니다0
컬럼 id 482개옆 테이블 한 장kind 안으로 들어갈 뿐 없어지지 않습니다테이블 헤더·이름 몇백 바이트

값 스트림이 그대로인 것이 핵심입니다. v104가 배열 블록에 스칼라와 같은 인코딩 후보를 주었고, v107이 길이 스트림을 런 하나로 접었습니다. 격자에서 아낄 것이 남아 있다면 그것은 원소 스트림 안인데, 새 선언 종류는 그 스트림을 건드리지 않습니다.

컬럼 id 표가 없어지지 않는다는 점도 중요합니다. id에서 자리를 찾는 대응은 격자의 정의에 들어 있는 정보이므로, 테이블로 두든 kind 안에 두든 파일이 담아야 합니다.

판정: 새 선언 종류의 인코딩 이득은 105,558칸에서 1 KB 미만입니다. 이것이 도입 근거가 되지 않습니다.

3. 인코딩 이득이 실제로 있는 자리 — 축의 선택

원소 스트림 안에 남아 있는 것이 하나 있습니다. 펼치는 순서가 행 우선으로 고정되어 있습니다.

배열 컬럼은 행마다 원소를 이어 붙이므로 스트림은 행0의 N개, 행1의 N개, … 입니다. 그런데 DELTA와 RLE가 일하는 것은 값이 닮은 방향이고, 격자에서 그 방향은 시트마다 다릅니다 — 교역품별 가격표라면 같은 교역품(컬럼)끼리 닮고, 지역별 보정치라면 같은 지역(행)끼리 닮습니다. 닮지 않은 축으로 펼치면 DELTA도 RLE도 런을 만들지 못합니다.

후보무엇이득비용
전치 후보길이가 모두 같은 배열 컬럼에서 열 우선 펼치기도 측정해 작은 쪽을 고릅니다시트에 따라 큽니다. 축이 어긋나 있으면 지금은 인코딩이 통째로 RAW에 남습니다형식 개정 하나 + 모든 런타임의 읽기 형태
대칭·삼각두 축이 같은 축일 때 절반만 싣습니다값 스트림 절반검출은 쉽지만, 복호가 행마다 반사 재배치입니다. 커서 방식과 맞지 않습니다
기본값 + 예외성긴 격자를 기본값과 예외 목록으로RLE가 이미 거의 같은 것을 합니다 — 실측 격자는 105,558칸 중 빈 칸이 482개뿐이었습니다얻는 것이 적습니다

셋 모두 선언 종류를 요구하지 않습니다. 인코더가 보는 조건은 「길이가 모든 행에서 같은 배열 컬럼」 하나이고, 그것은 TcbColumnEncoder.EncodeArray가 이미 손에 들고 있는 정보입니다.

전치가 읽기에서 성립하는지

성립합니다. 생성된 읽기 코드는 행을 먼저 전부 만들고 컬럼 블록을 하나씩 채웁니다. 커서는 순차적이지만(RLE 런과 DELTA 누산기), 채우는 순서는 생성 코드가 정합니다.

지금 for i in 행: for j in 0..N: rows[i].value[j] = cursor.Next()
전치 for j in 0..N: for i in 행: rows[i].value[j] = cursor.Next()

커서는 여전히 앞에서 뒤로 한 번 지나가고, 바뀌는 것은 대입 대상뿐입니다. 다만 배열을 먼저 전부 할당해야 하므로 길이 스트림을 먼저 다 읽는 두 번 훑기가 되고, 그 형태를 모든 언어 템플릿에 더해야 합니다.

4. 생성물 — 새 선언 종류가 되살리는 문제

v107이 고정 길이 배열 kind를 형식에서 지운 이유가 그대로 걸립니다.

길이가 파일에 한 번만 적히면 그 길이는 생성 코드에 상수로 남고, 그러면 컬럼을 하나 더하는 것이 데이터 패치가 아니라 코드 배포가 됩니다.

matrix의 M과 N은 그 선언의 형태 자체입니다. 생성된 접근자가 N을 상수로 들면 컬럼 하나를 추가하는 것이 다시 코드 배포가 되고, v107이 없앤 자리가 그대로 돌아옵니다. 피하려면 형태를 데이터가 싣게 해야 하는데, 그렇게 하고 나면 남는 것은 지금의 배열 컬럼과 같습니다.

언어 표면에서 확인해야 할 것도 있습니다.

언어확인할 것
C2차원 표면이 없습니다. 지금처럼 평평한 배열 + 폭이 그대로 답일 수 있습니다
Lua첨자가 1부터입니다. at을 그대로 쓰면 어긋납니다
Unreal중첩 TArrayUPROPERTY로 노출되지 않습니다. 래퍼 구조체가 필요한지 확인해야 합니다

5. 새 선언 종류만이 주는 것

공정하게 적습니다. 다음은 지금의 두 테이블 방식으로는 얻을 수 없습니다.

얻는 것지금의 문제
배포 단위 하나매트릭스 표의 마지막 주의 — 값 테이블과 컬럼 테이블이 같이 나가야 합니다. 한쪽만 새것이면 다른 칸을 읽고, 그것이 오류로 드러나지 않습니다
두 축 조회 한 번지금은 컬럼 테이블에서 at을 찾고 배열을 다시 첨자합니다. m.At(rowId, colId) 한 번이 됩니다
자르기 금지가 타입의 성질지금은 레이아웃이 자르기를 끄는 것을 기억해야 합니다. 잊으면 행마다 길이가 달라지고 value[at]이 성립하지 않습니다
행 벌의 대응 이름이 정식 자리를 가짐코어에 들어간 「벌끼리 맞출 때 쓰는 이름」이 격자를 위해 있는 것인데, 코어는 격자를 모릅니다
모든 행이 N칸이라는 것이 검사가 아니라 표현지금은 규칙이고, 어기면 런타임에 드러납니다

첫 줄이 가장 무겁습니다. 나머지 넷은 불편이지만, 배포가 어긋났을 때 다른 값을 읽는 것은 오류로 보고되지 않는 종류의 문제입니다. 다만 그 항목은 6.4절에서 절반이 닫힙니다.

5.1 표기가 얻는 것 — 두 번째 축의 키 타입

여기에 하나가 더 있고, 2절과 3절의 바이트 이야기보다 이쪽이 큽니다.

매트릭스 표의 판독 규칙은 「이름이 정수인 컬럼이 하나라도 있을 때」 입니다. 격자를 격자로 알아보는 방법이 컬럼 이름의 생김새뿐이므로, 따라오는 제약이 둘입니다.

제약결과
두 번째 축의 키가 정수여야 합니다enum 라벨 · 문자열 코드 · 참조로 축을 적을 수 없습니다
격자인지 아닌지를 추론합니다의도와 다르게 판독되는 경우를 규칙으로 막아야 하고, 그 규칙이 늘어납니다

선언 셀이 있으면 둘 다 없어집니다. 컬럼 머리 행이 「이름」이 아니라 「그 축의 키 값」 이라고 선언되므로, 축의 키는 그 축의 타입이 받는 것 전부입니다 — 정수 · 문자열 · enum 라벨 · 다른 테이블로의 참조. 추론도 사라집니다.

표기 설계는 매트릭스 선언에 따로 적었습니다.

6. 구현 비용 — 번지는 곳과 번지지 않는 곳

정정. 이 절은 처음에 「150개를 넘습니다」로 적혀 있었고, 그것은 새 와이어 kind를 두는 전제로 센 것이었습니다. 그 전제가 필요 없습니다 — 1절의 「행 + 위치 배열」 표현을 그대로 쓰고 선언만 새로 두면 됩니다.

6.1 번지지 않는 곳

고리왜 0인가
형식과 모든 언어 런타임(lib/)파일에 실리는 것이 지금과 같은 테이블 둘입니다
json · csv · DB 익스포터같은 이유입니다
히스토리 지문 · 스냅숏 비교 · 매니페스트테이블 단위로 도는 것들이고, 테이블이 둘 있을 뿐입니다
Model의 엔티티 목록List<Matrix>를 두지 않습니다. 테이블 둘과 그 사이의 링크입니다

마지막 줄이 특히 중요합니다. 다섯 번째 엔티티를 만들면 「선언 종류」를 분기하는 모든 switch에 축이 하나 늘고 이후 모든 기능이 다섯 갈래를 갖게 되는데, 링크로 두면 그것이 없습니다.

6.2 남는 곳

자리무엇규모
레이아웃 파서:matrix 문법. 헤더 행의 셀을 이름이 아니라 그 축 타입의 값으로 파싱하는 경로가 새로 생깁니다파서 1개 + 메시지 1개
쿠커선언 하나에서 테이블 둘. 이미 그렇게 하는 곳이 있습니다 — 이름 기반 레이아웃의 매트릭스 판독분기 몇 개
모델「이 배열의 자리는 저 테이블의 at이다」 링크필드 2~3개
코드 생성모든 언어의 뷰 · 생성기 · 템플릿에 접근자 하나여기가 비용의 대부분
골든 · 적합성 하네스전 언어 재기록과 컴파일 게이트스위트 시간

코드 생성도 생각보다 작습니다. 접근자가 이미 생성된 조회 둘의 합성이기 때문입니다.

At(rowKey, colKey) => FindByTown(rowKey).Value[ FindByGoods(colKey).At ]

두 조회는 지금도 생성됩니다. 더할 것은 뷰가 계획 하나를 더 들고 템플릿이 블록 하나를 더 쓰는 것이고, 그 형태는 KeyPlans가 복합 키에 대해 이미 하는 것과 같습니다 — 「뷰가 계획 목록을 들고 템플릿이 계획마다 조회를 하나 쓴다」.

6.3 실측 기준과의 비교

작업성격src + lib 파일
다형 타입(15f0aec1~434a716e)엔티티 하나 추가. 언어마다 합 타입 표면 전체112
v107(bd6e4f1d~c2459dcc)와이어 kind 제거. 런타임 전부 포함73
matrix(이 설계)선언 + 접근자. 런타임 무변경언어당 3파일 정도 + 파서 · 모델 · 쿠커

다형 타입은 언어마다 판별 합집합 · 변종별 접근자 · 묘비까지 냈고 그것이 112개였습니다. 매트릭스가 언어마다 내는 것은 메서드 두셋입니다.

6.4 5절에서 줄어드는 항목 하나

배포 단위 하나는 얻지 못합니다. 파일에 테이블 둘로 남으므로, 값 테이블과 축 테이블이 따로 배포될 수 있다는 사실이 그대로입니다.

대신 감지되지 않던 읽기 오류를 보고되는 오류로 바꾸는 것은 코드 생성만으로 됩니다 — 로드 시 ColKeys의 개수와 값 배열의 길이가 다르면 그 자리에서 실패시킵니다. 5절의 첫 줄이 무거웠던 이유가 「오류로 드러나지 않는다」였으므로, 무거운 부분은 여기서 닫힙니다.

7. 중간안 — 선언 셀 없이 컬럼 속성만

6절의 계산이 나온 뒤에도 중간안은 남습니다. 다른 것은 레이아웃 파서 하나입니다.

:matrix 선언컬럼 속성만
레이아웃 파서의 새 문법있습니다없습니다 — 타입 칸의 괄호 메타 하나
축의 키 타입정수 아닌 것도 됩니다(5.1)정수뿐입니다 — 판독 규칙이 그대로이므로
접근자와 길이 검사얻습니다얻습니다
시트 작성자가 격자를 적을 수 있는가아니오. 이미 격자로 적힌 것을 받을 뿐입니다

마지막 줄이 둘을 가릅니다. 표기가 목적이면 선언 셀이 필요하고, 접근자만이 목적이면 컬럼 속성으로 충분합니다.

8. 값 타입으로서의 행렬 — 다른 질문

mat3 · mat4 처럼 한 칸에 적는 변환 행렬은 위와 완전히 다른 사안이고, 훨씬 쌉니다. 합성 값 타입의 구조가 이미 그것입니다 — vec3f · quat · color 가 파싱 동안만 타입이고, 쿠커가 컴포넌트마다 컬럼 하나로 펼칩니다.

들어가는 것나오는 것
CompositeType.All에 항목 하나mat4는 컴포넌트 16개 → 컬럼 16개
표기 파서가 받는 튜플 길이identity가 이름을 갖습니다 — TakesIdentity가 이미 있습니다

코어 아래로는 아무것도 새로 배우지 않습니다. 다만 mat4 한 칸이 컬럼 16개가 되는 것이 받아들일 만한지는 따로 판단해야 하고, 시트에 실제로 변환 행렬을 적는 사례가 있는지를 먼저 확인해야 합니다.

9. 권고 순서

  1. 주 레이아웃의 매트릭스 읽기를 먼저 끝냅니다. 로드맵에 이미 있고, 사용자가 실제로 막히는 자리입니다. 선언 종류와 무관합니다.
  2. 전치 후보를 측정합니다. Choose(평평)Choose(전치) 를 나란히 재어 보고서로만 냅니다. 형식도 런타임도 건드리지 않고 숫자가 먼저 나옵니다.
  3. 그 숫자가 크면 v108로 전치 후보를 넣습니다. 3절의 읽기 형태 변경이 비용의 전부입니다.
  4. 접근자 불편이 남으면 7절의 컬럼 속성을 넣습니다.
  5. 선언 종류는 5.1절(축의 키 타입)이 값을 할 때 도입합니다. 비용이 코드 생성에 몰려 있으므로 언어를 하나씩 늘리는 방식이 됩니다 — 다형 타입이 C#부터 시작해 언어를 더해 간 것과 같은 순서입니다. 설계의 첫 제약은 4절의 「형태를 데이터가 싣는다」이고, 표기는 매트릭스 선언이 정본입니다.

바뀐 무게추 하나. 이 문서는 인코딩 이득을 근거로 출발했고 그것은 없다는 것이 2절입니다. 남은 근거는 표기와 배포 단위이며, 그 둘은 바이트가 아니라 시트 작성자가 적을 수 있는 것틀렸을 때 보고되는가입니다. 도입을 결정한다면 근거를 그쪽으로 적어야 합니다.