This file provides guidance to coding agents collaborating on this repository.
Ordered is a sorted-collection library for Zig. It provides in-memory data structures that keep their elements sorted: two set types (value-only) and four map types (key-value), all exposing a small, uniform API for insertion, lookup, removal, and in-order iteration. Priorities, in order:
- Correctness of ordering, iteration, and memory management across insertions and removals.
- Minimal public API that is consistent across every container type.
- Zero non-Zig dependencies, maintainable, and well-tested code.
- Cross-platform support (Linux, macOS, and Windows).
- Use English for code, comments, docs, and tests.
- Prefer small, focused changes over large refactoring.
- Add comments only when they clarify non-obvious behavior.
- Do not add features, error handling, or abstractions beyond what is needed for the current task.
- Keep the project dependency-free: no external Zig packages or C libraries unless explicitly agreed.
- Use Oxford commas in inline lists: "a, b, and c" not "a, b, c".
- Do not use em dashes. Restructure the sentence, or use a colon or semicolon instead.
- Avoid colorful adjectives and adverbs. Write "TCP proxy" not "lightweight TCP proxy", "scoring components" not "transparent scoring components".
- Use noun phrases for checklist items, not imperative verbs. Write "redundant index detection" not "detect redundant indexes".
- Headings in Markdown files must be in the title case: "Build from Source" not "Build from source". Minor words (a, an, the, and, but, or, for, in, on, at, to, by, of, is, are, was, were, be) stay lowercase unless they are the first word.
src/lib.zig: Public API entry point. Re-exportsSortedSet,RedBlackTreeSet,BTreeMap,SkipListMap,TrieMap, andCartesianTreeMap.src/ordered/sorted_set.zig:SortedSet(insertion-sortedstd.ArrayListbacked by a linear scan for insert and removal).src/ordered/red_black_tree_set.zig:RedBlackTreeSet(self-balancing BST; takes an explicit three-way comparison function, consistent with the other generic-key containers).src/ordered/btree_map.zig:BTreeMap(cache-friendly B-tree with configurable branching factor).src/ordered/skip_list_map.zig:SkipListMap(probabilistic skip list with a per-instance PRNG).src/ordered/trie_map.zig:TrieMap(prefix tree, specialised for[]const u8keys).src/ordered/cartesian_tree_map.zig:CartesianTreeMap(treap combining BST ordering with max-heap priorities; takes an explicit key-comparison function).examples/: Self-contained example programs (e1_btree_map.zigthroughe6_cartesian_tree_map.zig) built as executables viabuild.zig.benches/: Benchmark programs (b1_btree_map.zigthroughb6_cartesian_tree_map.zig) built inReleaseFast.benches/util/timer.zig: Internal compatibility shim for the removedstd.time.Timer, backed bystd.Io.Timestamp..github/workflows/: CI workflows (tests.ymlfor unit tests on Linux, macOS, and Windows,docs.yml,lints.yml, andbenches.yml).build.zig/build.zig.zon: Zig build configuration and package metadata.Makefile: GNU Make wrapper aroundzig buildtargets.docs/: Generated API docs land indocs/api/(produced bymake docs).
Every map exposes init(allocator), deinit(), count(), contains(key), get(key), getPtr(key), put(key, value),
remove(key), and iterator(). Every set exposes the same shape with value-only variants. New containers should
adopt this surface instead of inventing new method names.
Iterators return entries in the natural sort order of the underlying structure. Modifying a container during iteration is undefined behaviour; each container's docstring states this explicitly. New iterators should follow the same convention and document the contract.
SkipListMap and CartesianTreeMap use randomness internally (levels and priorities, respectively). Each instance
owns its own std.Random.DefaultPrng, seeded at init from an ASLR-derived hash of a stack address, which is
sufficient randomness for skip-list level selection and treap priority generation. Callers do not need to provide
a seed. Tests that require deterministic behaviour should use the explicit *WithPriority / level-setting API
on the container rather than seeding the PRNG directly.
Everything re-exported from src/lib.zig is part of the public API. Changes to names, signatures, or semantics
there are breaking. The rest of src/ordered/ is internal and may be refactored freely as long as the public
surface and its behavior are preserved.
Ordered has no external Zig or C dependencies.
The only build.zig.zon entries should be Ordered itself.
Please do not add dependencies without prior discussion.
- Zig version: 0.16.0 (as declared in
build.zig.zonand the Makefile'sZIG_LOCALpath). - Formatting is enforced by
zig fmt. Runmake formatbefore committing. - Naming follows Zig standard-library conventions:
camelCasefor functions (e.g.getPtr,keysWithPrefix),snake_casefor local variables and struct fields,PascalCasefor types and structs, andSCREAMING_SNAKE_CASEfor top-level compile-time constants.
Run the relevant targets for any change:
| Target | Command | What It Runs |
|---|---|---|
| Unit tests | make test |
Inline test blocks across src/lib.zig and src/ordered/*.zig |
| Lint | make lint |
Checks Zig formatting with zig fmt --check src examples |
| Single example | make run EXAMPLE=e1_btree_map |
Builds and runs one example program |
| All examples | make run |
Builds and runs every example under examples/ |
| Single benchmark | make bench BENCHMARK=b1_btree_map |
Builds (ReleaseFast) and runs one benchmark program |
| All benchmarks | make bench |
Builds and runs every benchmark under benches/ |
| Docs | make docs |
Generates API docs into docs/api |
| Everything | make all |
Runs build, test, lint, and docs |
- Read the relevant module under
src/ordered/(often one container file per change). - Implement the smallest change that covers the requirement.
- Add or update inline
testblocks in the changed Zig module to cover the new behavior. - Run
make testandmake lint. - If the change could affect performance, also run the corresponding benchmark with
make bench BENCHMARK=bN_*.
Good first tasks:
- New example under
examples/demonstrating a container method, listed inexamples/README.md. - Additional inline
testblock covering a boundary case (empty container, single element, duplicate key, unicode key). - Performance improvement in an existing container, paired with benchmark output before/after.
- Documentation refinement in a container module's top-level docstring.
- Unit and regression tests live as inline
testblocks in the module they cover (src/lib.zigandsrc/ordered/*.zig). There is no separatetests/directory. - Tests are discovered automatically via
std.testing.refAllDecls(@This())insrc/lib.zig, so newtestblocks only need to live in a module that is reachable fromlib.zig. - Every new public function or container branch must ship with at least one
testblock that exercises it, including the error paths where applicable. - Memory tests should use
std.testing.allocatorso leaks are caught automatically. - No public API change is complete without a test covering the new or changed behavior.
Before coding:
- Modules affected by the change (which container file, or
lib.zigif the public surface moves). - Whether the change alters ordering, iteration, or removal semantics, and therefore needs explicit test coverage.
- Public API impact, i.e. whether the change adds to or alters anything re-exported from
src/lib.zig, and is therefore additive or breaking. - Cross-platform implications, especially for anything that touches timing, the filesystem, or non-deterministic ordering.
Before submitting:
make testpasses.make lintpasses.make benchstill succeeds for any benchmark whose container was touched, with a note on whether performance moved.- Docs updated (
make docs) if the public API surface changed, andREADME.mdticked or updated if a container was added or removed.
- Keep commits scoped to one logical change.
- PR descriptions should include:
- Behavioral change summary.
- Tests added or updated.
- Whether benchmarks were run locally (yes/no), and on which OS, with before/after numbers when relevant.