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-keys map, std::map).
  • A u64 running counter total_ops.
  • incr(k, by): total_ops += 1; add by to (or create) counters[k].
  • decr(k, by): total_ops += 1; if k is missing, stop. Otherwise remove the entry if by >= 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 and total_ops == 3.
  • decr_saturates_and_removes: incr(1, 5); decr(1, 3); decr(1, 100) leaves the map empty with total_ops == 3.
  • decr_on_missing_is_visible_op: decr(42, 1) on an empty store leaves total_ops == 1 and no entry for 42.

Things to watch for

  • u64 underflow: never compute current - by without the current <= by check 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. Use find.

Acceptance

cargo test --release --lib tests::incr_accumulates and the matching Go / C++ tests all pass.