Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ compile_commands.json
# Generated Doxygen output
docs/html/
docs/latex/
docs/doxygen-warnings.log

# benchmark results
bench_results.csv
20 changes: 19 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,28 @@ This README is the documentation index and recommended reading path.
- Forward-looking roadmap for portability, core tests, CLI utilities,
huge file streaming, and HTTP client support.

3. Doxygen API reference
3. [docs/HASHMAP_ALGORITHMS.md](docs/HASHMAP_ALGORITHMS.md)
- Standalone walkthrough of the algorithms used in the arena-backed hash map.
- Covers Robin Hood probing, cached hashes, growth via rehash, and set specialization.

4. [docs/CORE_MODULES_GUIDE.md](docs/CORE_MODULES_GUIDE.md)
- Guided overview of the foundational modules and how they connect.
- Useful when moving from architecture notes into concrete APIs.

5. Doxygen API reference
- Rendered landing page: [docs/html/index.html](docs/html/index.html)
- Guided authored-doc entry page: [docs/DOXYGEN_MAINPAGE.md](docs/DOXYGEN_MAINPAGE.md)
- Generated output: [docs/html/index.html](docs/html/index.html)
- Configuration: [docs/Doxyfile](docs/Doxyfile)

### Rendered Docs Structure

The rendered Doxygen site now uses a dedicated Markdown landing page so authored design notes and API reference live in one navigation flow.

- Landing page source: `docs/DOXYGEN_MAINPAGE.md`
- Rendered main page: `docs/html/index.html`
- Additional authored guides under `docs/` are included automatically by Doxygen.

### Contributor and project policy

1. [docs/CONTRIBUTING.md](docs/CONTRIBUTING.md)
Expand Down
78 changes: 78 additions & 0 deletions docs/ARCHITECTURE_DECISIONS.md
Original file line number Diff line number Diff line change
Expand Up @@ -192,3 +192,81 @@ Trade-offs:
- `core_portability` owns compiler and standard-library gaps, not OS allocation APIs.

This split is deliberate: compiler portability and operating-system portability are related concerns, but they are not the same layer and should not be collapsed into one module.

## ADR-0005: HashMap Uses Arena-Backed Robin Hood Open Addressing

- Status: Accepted
- Date: 2026-07-13
- Scope: Base hash container design for map and set workloads

### Context

The project needs a low-level hash container that matches the existing arena allocation model and stays efficient for Advent of Code style workloads.

The main constraints are:

- no per-element heap allocation;
- explicit failure reporting via `Result<E,T>` rather than exceptions;
- compatibility with both key-value maps and key-only sets;
- predictable probe behavior under moderately high load factors;
- acceptable performance for both integer keys and byte-string slice keys such as `Str8`.

Separate chaining would introduce extra pointer chasing and allocator pressure. A traditional open-addressing table without probe balancing risks long clusters and unstable lookup costs as load increases.

### Decision

The hash container design uses arena-backed open addressing with Robin Hood insertion.

The current shape is:

1. capacity is always a power of two;
2. indexing uses a bitmask rather than modulo;
3. keys, values, cached hashes, and occupancy control bytes are stored in separate arrays;
4. growth allocates new arena storage and reinserts live entries into the larger table;
5. `HashMap<K, void>` is the set specialization and does not allocate a values array;
6. operations report failures through a dedicated `HashMapE` error enum and `HashMapR<T>` aliases.

### Why we need this

- Robin Hood probing reduces variance in probe lengths and improves worst-case behavior at a given load factor.
- Separate key, value, hash, and control arrays preserve a simple data-oriented layout and match the existing arena model.
- Cached per-slot hashes avoid repeated re-hashing of resident keys during probe walks, which matters for `Str8` keys.
- Arena growth through allocate-and-rehash keeps ownership simple and avoids per-entry lifetime bookkeeping.
- A `void` specialization provides true set semantics without paying for unused value storage.

### Consequences

Positive:

- No general-purpose heap allocator dependency in the hot path.
- Predictable insertion and lookup behavior for the supported workload shape.
- String-key probe chains avoid unnecessary repeated hash computation.
- Map and set behavior share one conceptual implementation strategy.

Trade-offs:

- Growth is monotonic within an arena and does not reclaim prior table storage.
- The current design does not yet support erase.
- The current control-byte scheme is intentionally simple and does not yet use SIMD-friendly fingerprints.
- The fast path assumes trivially copyable key and value types are the intended primary workload.

### Alternatives considered

1. Separate chaining with linked nodes.
- Pros: simpler deletion semantics.
- Cons: worse locality, more pointer chasing, and allocator pressure.

2. Linear probing without Robin Hood balancing.
- Pros: simpler insert logic.
- Cons: longer-tail probe behavior under load.

3. Recompute hashes on every probe step.
- Pros: less storage overhead.
- Cons: avoidable cost for non-trivial key types, especially `Str8`.

### Follow-up actions

- Add focused container tests for insert, overwrite, contains, and rehash behavior.
- Decide whether erase belongs in this container or in a separate higher-level variant.
- Evaluate SIMD-friendly metadata or fingerprint control bytes if probe performance becomes a bottleneck.
- Document supported key/value type expectations more explicitly in API docs.
146 changes: 146 additions & 0 deletions docs/CORE_MODULES_GUIDE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
# Core Modules Guide

This document connects the core modules at a higher level than the generated API pages.

The goal is to answer a simple question:

- if you are trying to understand or extend the base layer, what should you read, and in what order?

## The Core Story

The base layer is built around a small set of modules that each own a distinct concern.

At a high level:

1. `core_types` defines the project's scalar vocabulary.
2. `core_vm` owns operating-system virtual memory boundaries.
3. `core_portability` owns compiler and standard-library portability shims.
4. `core_memory` builds the arena allocator on top of those lower layers.
5. `core_result` and `core_result_s` define explicit success/failure return types.
6. `core_string` provides `Str8`, formatting, and string-centric primitives.
7. `core_hash` defines hashing traits over supported key types.
8. `core_hash_map` builds the arena-backed hash containers.

## Suggested Reading Order

### 1. Scalar and utility base

- [core_types module API](module__core__types.html)
- [core_types file API](core__types_8cppm.html)

Read this first if you want the project's common integer aliases, arithmetic helpers, and shared low-level vocabulary.

### 2. Portability and OS boundaries

- [core_vm module API](module__core__vm.html)
- [core_vm file API](core__vm_8cppm.html)
- [core_portability module API](module__core__portability.html)
- [core_portability file API](core__portability_8cppm.html)

These modules separate two kinds of platform concerns:

- OS-level VM behavior belongs in `core_vm`.
- Compiler and language-model gaps belong in `core_portability`.

That split matters for understanding how the arena remains simple while still being correct.

### 3. Arena allocation

- [core_memory module API](module__core__memory.html)
- [core_memory file API](core__memory_8cppm.html)
- [Arena type page](structbase_1_1mem_1_1Arena.html)

This is the allocation foundation used by most higher-level transient data structures in the project.

If you are reading the hash table, you should understand the arena first.

### 4. Result types

- [core_result module API](module__core__result.html)
- [core_result file API](core__result_8cppm.html)
- [core_result_s module API](module__core__result__s.html)
- [core_result_s file API](core__result__s_8cppm.html)

These modules define the project's explicit error-reporting style.

The hash map uses this pattern directly through `HashMapE` and `HashMapR<T>`.

### 5. Strings and slices

- [core_string module API](module__core__string.html)
- [core_string file API](core__string_8cppm.html)
- [Str8 type page](structbase_1_1str_1_1Str8.html)

`Str8` is one of the most important data types in the project. It is both a common runtime string representation and one of the supported hash-key types.

### 6. Hash traits and containers

- [core_hash module API](module__core__hash.html)
- [core_hash file API](core__hash_8cppm.html)
- [core_hash_map module API](module__core__hash__map.html)
- [core_hash_map file API](core__hash__map_8cppm.html)
- [base::hashmap namespace](namespacebase_1_1hashmap.html)

This is the natural point where the earlier modules come together:

- the arena provides storage;
- result types provide failures;
- strings provide one important key family;
- hash traits bridge key types to the container;
- `core_hash_map` provides map and set behavior.

## How the Pieces Fit Together

### Arena and HashMap

The hash container does not own heap allocations directly.

Instead:

- `core_memory` supplies arena-backed arrays;
- `core_hash_map` stores keys, values, hashes, and control bytes inside those arrays;
- growth means allocate-and-rehash, not per-entry relocation with independent ownership.

### Result and HashMap

The container follows the same explicit-error style as the rest of the codebase.

- low-level helpers return `HashMapR<T>`;
- failures are categorized by `HashMapE`;
- callers are expected to branch on success rather than rely on exceptions.

### Str8 and HashMap

The `Str8` type is a natural fit for this design because it is a non-owning slice.

That means the table can store the slice cheaply, provided the backing bytes outlive the table entry.

## If You Are Focused on HashMap

The fastest path through the core layer is:

1. [HashMap Algorithms](HASHMAP_ALGORITHMS.md)
2. [Architecture Decisions](ARCHITECTURE_DECISIONS.md)
3. [core_memory file API](core__memory_8cppm.html)
4. [core_hash file API](core__hash_8cppm.html)
5. [core_hash_map file API](core__hash__map_8cppm.html)

That gives you:

- algorithmic intuition,
- design rationale,
- allocator model,
- trait model,
- and final implementation details.

## If You Are Extending the Base Layer

Use this rule of thumb:

- add OS-facing behavior to `core_vm`;
- add compiler or standard-library shims to `core_portability`;
- add allocation policy to `core_memory`;
- add shared data representation to `core_string` or similar domain modules;
- add container-specific logic to the container module itself.

Keeping those boundaries sharp is what makes the rest of the documentation readable.
94 changes: 94 additions & 0 deletions docs/DOXYGEN_MAINPAGE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
# AOC Documentation Guide

Welcome to the rendered documentation entry point for this project.

This page exists so the generated Doxygen site is not only an API dump. It provides a guided path through the authored design notes and the generated API reference.

## Recommended Reading Order

### 1. Architecture decisions

- [Architecture Decisions](ARCHITECTURE_DECISIONS.md)
- Durable project decisions for arena allocation, portability boundaries, and hash-container design.

### 2. HashMap algorithm guide

- [HashMap Algorithms](HASHMAP_ALGORITHMS.md)
- Tutorial-style walkthrough of Robin Hood hashing, cached hashes, growth by rehash, and the `HashMap<K, void>` set specialization.

### 2.5. Core modules guide

- [Core Modules Guide](CORE_MODULES_GUIDE.md)
- High-level map of the foundational modules and how memory, strings, results, and hash containers fit together.

### 3. Future roadmap

- [Future Enhancements](FUTURE_ENHANCEMENTS.md)
- Follow-up ideas for the hash container, platform work, tests, streaming, and other infrastructure.

### 4. Contributor guidance

- [Contributing](CONTRIBUTING.md)
- Project rules, coding expectations, and workflow guidance.

### 5. API reference

- Use the generated file, module, namespace, and type navigation in the Doxygen sidebar and index pages.
- The hash container implementation itself is documented in [core_hash_map.cppm API](core__hash__map_8cppm.html).
- The generated module page for the container is [core_hash_map module](module__core__hash__map.html).
- The generated namespace page is [base::hashmap namespace](namespacebase_1_1hashmap.html).
- The generated type pages are [HashMap<K,V>](structbase_1_1hashmap_1_1HashMap.html) and [HashMap<K,void>](structbase_1_1hashmap_1_1HashMap_3_01K_00_01void_01_4.html).

## Documentation Layers

This project intentionally uses two complementary documentation layers.

### Authored guides

These are Markdown documents under `docs/`.

They answer questions like:

- Why was this design chosen?
- What algorithmic tradeoffs matter here?
- What should future work improve?

### API reference

These are generated from Doxygen comments in source.

They answer questions like:

- What fields and functions exist?
- What arguments and return values do they use?
- What invariants or preconditions apply?

## Current Highlights

- Arena allocation is explicit and low-level.
- Portability and VM boundaries are separated into dedicated core modules.
- The hash container uses Robin Hood open addressing with cached hashes.
- Hash-set behavior is provided through `HashMap<K, void>`.

## Quick Links Into Rendered API

If you want to jump directly into generated reference material, these are the most useful entry points:

- [Arena API](core__memory_8cppm.html)
- [String API](core__string_8cppm.html)
- [Result API](core__result_8cppm.html)
- [Hash traits API](core__hash_8cppm.html)
- [HashMap file API](core__hash__map_8cppm.html)
- [HashMap module API](module__core__hash__map.html)
- [HashMap namespace API](namespacebase_1_1hashmap.html)

## Navigating HashMap Material

If your focus is the hash container specifically, the fastest path is:

1. [HashMap Algorithms](HASHMAP_ALGORITHMS.md)
2. [Architecture Decisions](ARCHITECTURE_DECISIONS.md)
3. [core_hash_map module API](module__core__hash__map.html)
4. [HashMap<K,V> type page](structbase_1_1hashmap_1_1HashMap.html)

That sequence gives you the algorithm, then the design constraints, then the exact implementation surface.
Loading