Step 01 — Counter Store
Goal
Implement a CounterStore in each of three languages with byte-identical
semantics for incr, decr, and get. The data structure is intentionally
small — three operations, two pieces of state — so we can focus on the
edge cases that make cross-language byte-identity hard.
What to build
A type/struct/class CounterStore with:
- An ordered map
i64 -> u64(BTreeMap, sorted-keysmap,std::map). - A
u64running countertotal_ops. incr(k, by):total_ops += 1; addbyto (or create)counters[k].decr(k, by):total_ops += 1; ifkis missing, stop. Otherwise remove the entry ifby >= current, else subtract.get(k) -> Option<u64>/(u64, bool)/std::optional<u64>.
Tests this step should pass
incr_accumulates: three incrs across two keys leave the right per-key values andtotal_ops == 3.decr_saturates_and_removes:incr(1, 5); decr(1, 3); decr(1, 100)leaves the map empty withtotal_ops == 3.decr_on_missing_is_visible_op:decr(42, 1)on an empty store leavestotal_ops == 1and no entry for 42.
Things to watch for
u64underflow: never computecurrent - bywithout thecurrent <= bycheck first.- Go's map: a missing key reads back as the zero value with
ok=false. Use the comma-ok form explicitly. - C++
std::map::operator[]: avoid it on the read path — it inserts a zero entry as a side effect. Usefind.
Acceptance
cargo test --release --lib tests::incr_accumulates and the matching
Go / C++ tests all pass.