ast.Node 가 이름이 무엇으로 해석됐는지 들고, Map 이 저장소를 유지한 채 키만 잊는다. 스코프가 끝날 때 표를 다음 스코프에 넘기는 것이 리졸버가 원하는 모양이다 -- 함수마다가 아니라 중첩 단계마다 표 하나. bind 는 Name 노드의 남는 a 필드를 재활용할 수도 있었지만 명시적인 쪽을 골랐다. 노드가 32 에서 36 바이트가 되는 값으로 그 자리가 무엇인지 이름이 말한다. clear 는 아무도 부르지 않는 채로 들어와 있었다. maps.fe 가 이제 부른다: 키가 사라지고, 방은 64 로 남고, 그 위에 다시 채워도 버퍼를 새로 잡지 않는다. cleared 0 room 64 gone 0 / refilled 3 / balanced GOAL.md 를 더했다. 외부 감사와, 그 항목들을 실제로 빌드해서 확인한 결과를 합친 P0~P4 다. 228/228, 32/32.
71 lines
2.1 KiB
Plaintext
71 lines
2.1 KiB
Plaintext
// EXIT:0
|
|
// OUTPUT:count 5
|
|
// OUTPUT:fn 2 let 3 missing 0
|
|
// OUTPUT:grown 64
|
|
// OUTPUT:after 40
|
|
// OUTPUT:cleared 0 room 64 gone 0
|
|
// OUTPUT:refilled 3
|
|
// OUTPUT:balanced
|
|
unit maps;
|
|
import std.io;
|
|
import std.map;
|
|
import std.fmt;
|
|
import std.sys;
|
|
|
|
fn run() -> !void {
|
|
var seen: map.Map(i32) = try map.Map(i32).with_capacity(4);
|
|
try seen.put("unit", 1);
|
|
try seen.put("fn", 2);
|
|
try seen.put("let", 3);
|
|
try seen.put("struct", 4);
|
|
try seen.put("return", 5);
|
|
@print("count {}\n", seen.count_of());
|
|
@print("fn {} let {} missing {}\n", seen.get("fn", 0), seen.get("let", 0),
|
|
seen.get("nope", 0));
|
|
// Enough keys to make it grow more than once.
|
|
var buf: [8]u8 = undefined;
|
|
var i: usize = 0;
|
|
while i < 40 {
|
|
let n: usize = fmt.fmt_i32(buf[..], i as i32);
|
|
try seen.put(buf[0..n], (i as i32) + 100);
|
|
i = i + 1;
|
|
}
|
|
@print("grown {}\n", seen.room());
|
|
var found: usize = 0;
|
|
i = 0;
|
|
while i < 40 {
|
|
let n: usize = fmt.fmt_i32(buf[..], i as i32);
|
|
if seen.get(buf[0..n], 0) == (i as i32) + 100 { found = found + 1; }
|
|
i = i + 1;
|
|
}
|
|
@print("after {}\n", found);
|
|
|
|
// `clear` forgets every key and keeps the storage, which is what a scope
|
|
// that ends wants: hand the table to the next one without going back to
|
|
// the allocator. The room has to survive and the keys have to not.
|
|
let room: usize = seen.room();
|
|
seen.clear();
|
|
var gone: usize = 0;
|
|
i = 0;
|
|
while i < 40 {
|
|
let n: usize = fmt.fmt_i32(buf[..], i as i32);
|
|
if seen.has(buf[0..n]) { gone = gone + 1; }
|
|
i = i + 1;
|
|
}
|
|
@print("cleared {} room {} gone {}\n", seen.count_of(), room, gone);
|
|
|
|
// And it is usable again afterwards, reusing the same buffers.
|
|
try seen.put("a", 1);
|
|
try seen.put("b", 2);
|
|
try seen.put("c", 3);
|
|
@print("refilled {}\n", seen.count_of());
|
|
return;
|
|
}
|
|
|
|
fn main() -> i32 {
|
|
run() catch |e| { @print("failed\n"); return 1; };
|
|
if sys.allocs() != sys.frees() { @print("leaked\n"); return 2; }
|
|
@print("balanced\n");
|
|
return 0;
|
|
}
|