// Package maplab contains the runnable experiments for Chapter 7: // Maps — Swiss Tables, Growth, and Permanent Memory. // // Baseline: Go 1.24+, whose built-in map is a Swiss Tables implementation. // // Inspect behavior: // // go test -run TestIterationOrder -v . # iteration start is randomized // go test -run TestMapRetention -v . # delete/clear do not return memory // // Run the benchmarks: // // go test -bench=. -benchmem -count=10 . package maplab // N is the entry count for the retention experiment. const N = 1 << 20 // 1,048,576 entries // --------------------------------------------------------------------------- // Retention (Experiments 1 & 5). A map grows but never shrinks: delete and // clear empty it logically but keep the table memory; only dropping the map // (and letting it be collected) returns memory to the runtime. // --------------------------------------------------------------------------- // FilledMap returns a map with N entries. func FilledMap() map[int]int { m := make(map[int]int) for i := 0; i < N; i++ { m[i] = i } return m } // DeleteAll removes every key with delete(). The table memory stays allocated. func DeleteAll(m map[int]int) { for k := range m { delete(m, k) } } // --------------------------------------------------------------------------- // clear vs delete-loop (Experiment 2). Both empty the map; clear() resets the // control words in bulk, the delete loop visits every entry. Neither frees the // table. // --------------------------------------------------------------------------- func ClearMap(m map[int]int) { clear(m) } func DeleteLoop(m map[int]int) { for k := range m { delete(m, k) } } // --------------------------------------------------------------------------- // Pre-sizing (Experiment 4). Telling make() the final size avoids the // intermediate table grows (and their rehash copies) during insertion. // --------------------------------------------------------------------------- func InsertNoPresize(n int) map[int]int { m := make(map[int]int) for i := 0; i < n; i++ { m[i] = i } return m } func InsertPresize(n int) map[int]int { m := make(map[int]int, n) for i := 0; i < n; i++ { m[i] = i } return m } // --------------------------------------------------------------------------- // Lookups (Experiment 3). LookupSum probes the map once per key. On Go 1.24+ // each probe scans 8 slots in parallel via the group's control word. // --------------------------------------------------------------------------- func LookupSum(m map[int]int, keys []int) int { s := 0 for _, k := range keys { s += m[k] } return s } // --------------------------------------------------------------------------- // Iteration order (Experiment 6). Each range over a map starts at a randomized // position, so FirstKey is (almost certainly) different across calls. // --------------------------------------------------------------------------- func FirstKey(m map[int]int) int { for k := range m { return k } return -1 }