flags — 이름 붙은 켬 · 끔을 한 낱말에
켜고 끄는 설정 여럿을 정수 하나에 담아 다룬다. 자리는 비트 번호(0 번, 1 번, 2 번)로 부른다. 이름은 컴파일할 때만 살고, 실행 때 남는 것은 정수 하나다. 설정 화면의 켬 · 끔 항목, 기능 스위치, 더티 표시, 장치의 상태 비트 — 여럿을 따로 들고 다니기는 아깝고 하나로 묶으면 비교가 쉬운 자리다.
fn f_sound output u64 . do return 0 . end
fn f_music output u64 . do return 1 . end
let s0 u64 be flags.with (flags.empty) (f_sound) .
let playing bool be flags.has s0 (f_music) .이 모듈이 지키는 것
requires lt n 64 를 든다. C 의 1u << 64 는 정의되지 않은 동작이고, 여기서는 거절이다. 비용은 0 이다 — 라이브러리로 쓴 코드와 손으로 비트 연산을 쓴 코드의 기계 명령 수가 같다(x86-64 gcc -O2 에서 켜기 17 = 17, 묻기 18 = 18, 부분집합 24 = 24, 시험이 매번 잰다). 자리 번호는 겹치면 안 된다 — 설정을 파일이나 장치에 저장하는 순간 번호는 약속이 된다. 가운데 자리를 지우면 뒤가 밀려 저장된 설정이 조용히 다른 뜻이 되므로, 지운 자리는 비워 두고 재사용하지 않는다.| 하는 일 | op |
|---|---|
| 빈 값 · 그 자리 하나 | empty · of n |
| 켜기 · 끄기 · 뒤집기 · 묻기 | with s n · without s n · toggle s n · has s n |
| 합 · 교 · 차 · 부분집합 | join a b · both a b · minus a b · inside a b |
| 몇 개 · 가장 낮은 자리 | ones s · lowest s(계약 s > 0) |
| 하나라도 · 하나도 · 전부 | has_any s · has_none s · is_full s w(폭 w) · widthmask w |
| 무엇이 바뀌었나 | changes a b · changes_in a b m |
| 기본값과 다른 것만 · 이 자리만 갈아 끼우기 | from_default s d · overlay base over m |
표 50.1 — flags 의 op — 한 낱말(64 자리까지)
64 자리를 넘을 때 는 바이트 배열이고 이름이 다르다 — wide_bits s(바이트 수 × 8), wide_has · wide_with · wide_without · wide_toggle, wide_ones, wide_next s from(다음 선 자리, 빈 바이트는 통째로 건너뛴다). 경계의 값은 재서 적었다 — has s 63 이 17 명령, wide_has s 64 가 26 명령이다. 아홉 명령의 차이는 “어느 바이트인가”(나눗셈 · 색인)와 “그 바이트가 있는가”(경계 검사)의 값이다. 두 구현을 한 이름 뒤에 숨기지 않는 까닭이다. 범위 밖은 값으로 답한다(false · 0) — 폭이 실행 때 정해지므로 계약으로 적을 수 없다.
이름은 옵트인이다. 이름표는 부르는 쪽의 것이고 라이브러리는 문자열을 하나도 들지 않는다. flags.label_in "sound\x00music\x00shadow\x00" 2 는 "shadow", label_count 는 이름 수를 답한다. 이름을 쓰지 않는 프로그램의 바이너리에는 그 글자가 없다 — 시험이 두 방출물의 읽기 전용 영역 크기를 비교한다.
여럿이 같은 낱말을 고칠 때. 이 모듈의 op 은 값을 받아 값을 돌려준다 — 저장된 낱말을 직접 고치지 않는다. 여러 실행 흐름이 set shared (flags.with shared 2) 로 고치면 읽고 → 고치고 → 쓰기 사이에 남의 갱신이 사라진다. 그 자리는 원자적 연산이 답한다 — atomic_or s 0 4(2 번 켜기), atomic_and s 0 251(끄기), atomic_xor s 0 4(뒤집기). 자리가 상수면 마스크도 상수라 기계 명령 하나로 내려간다(27장). 장치 레지스터라면 wire 의 to_set · to_clear 를 쓴다.
반례. 자리를 마스크로 적는다
flags.with (flags.empty) 64 는 마스크 64(= 6 번 자리)를 뜻했지만 이 모듈은 “64 번 자리” 로 읽고, 양쪽이 상수라 컴파일 에러(E-CONTRACT-IMPOSSIBLE)다. 여기서 수는 언제나 번호다. 마스크로 다루려면 wire 를 쓴다.반례. 설정을 지금 값으로만 저장한다
flags.from_default s d 로 차이만 적으면 작고, 기본값이 바뀌어도 뜻이 산다.주의. 폭이 1 을 넘는 필드는 wire 의 일이다. 자리 번호의 자동 관리는 없다 — 번호는 사람이 적고, 두 이름이 같은 자리를 쓰면 개발 저장소의 검사가 잡는다. op 이름이 set · union · count · first 가 아닌 까닭 — 문법 낱말이거나 이미 있는 연산이거나, 다른 파일이 지역 이름으로 쓰고 있었다. first 를 내보내자 lib/regex.low 가 깨졌고 조합 검사가 그것을 잡았다.