From 32f4ba166d297e9c8409ad2dd16f542c83bd628a Mon Sep 17 00:00:00 2001 From: Daniel Polo <106583643+danielPoloWork@users.noreply.github.com> Date: Sun, 14 Jun 2026 11:53:36 +0200 Subject: [PATCH 1/2] docs(api): publish Doxygen API reference to GitHub Pages + ADR-0027 (M7.1) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Closes ROADMAP item 7.1 — the rendering half ADR-0013 §4–§5 deferred to this milestone. The public-header Doxygen contract is now built into a dependency-free static HTML site, gated warn-as-error on every PR and published to GitHub Pages on push to master. - ADR-0027 records the pipeline decision: Doxygen HTML -> GitHub Pages via the official Pages Actions, no external doc toolchain (MkDocs/Sphinx unified site deferred post-v1.0), version single-sourced from version.hpp, and a gate that validates documentation correctness (doc-rot, stale @param, broken refs) rather than ceremonial exhaustiveness — refining ADR-0013 §5. - docs/doxygen/Doxyfile: checked-in partial config (EXTRACT_PRIVATE=NO, public headers only, WARN_AS_ERROR=FAIL_ON_WARNINGS, HAVE_DOT=NO, treeview). - docs/doxygen/mainpage.md: hand-written landing page linking out to the GitHub-rendered narrative. - .github/workflows/docs-site.yml: build gate on PRs (no deploy), build+deploy on master via upload-pages-artifact / deploy-pages. - Three header comments use the Doxygen % auto-link escape (::%operator new / ::%operator delete) to silence spurious unresolved-link warnings. Comment-only. - Doc sync: ROADMAP 7.1 flipped, ADR index row, README badge + API-reference pointer, CHANGELOG Unreleased. Verified locally with Doxygen 1.10.0: zero warnings, build/doxygen/html/index.html generated. One-time maintainer action: enable GitHub Pages (Source: GitHub Actions) before the first master deploy; the PR gate is unaffected. Co-Authored-By: Claude Opus 4.8 (1M context) --- .github/workflows/docs-site.yml | 80 +++++++++++++ CHANGELOG.md | 21 ++++ README.md | 5 +- ROADMAP.md | 2 +- ...ygen-html-site-and-publication-pipeline.md | 82 ++++++++++++++ docs/adr/README.md | 1 + docs/doxygen/Doxyfile | 106 ++++++++++++++++++ docs/doxygen/mainpage.md | 45 ++++++++ src/main/cpp/it/d4np/memorypool/memory_pool.h | 2 +- .../cpp/it/d4np/memorypool/pool_allocator.hpp | 6 +- 10 files changed, 344 insertions(+), 6 deletions(-) create mode 100644 .github/workflows/docs-site.yml create mode 100644 docs/adr/0027-doxygen-html-site-and-publication-pipeline.md create mode 100644 docs/doxygen/Doxyfile create mode 100644 docs/doxygen/mainpage.md diff --git a/.github/workflows/docs-site.yml b/.github/workflows/docs-site.yml new file mode 100644 index 0000000..f9cb5ce --- /dev/null +++ b/.github/workflows/docs-site.yml @@ -0,0 +1,80 @@ +name: docs-site + +# Builds the Doxygen API-reference site and publishes it to GitHub Pages +# (ADR-0027). On pull requests the build runs as a warn-as-error gate only +# (ADR-0013 §5) — no deploy, so PRs are never blocked by Pages configuration. +# On push to master the same build's output is published to Pages. + +on: + pull_request: + paths: + - 'src/main/cpp/it/d4np/memorypool/**.h' + - 'src/main/cpp/it/d4np/memorypool/**.hpp' + - 'docs/doxygen/**' + - '.github/workflows/docs-site.yml' + push: + branches: [master] + paths: + - 'src/main/cpp/it/d4np/memorypool/**.h' + - 'src/main/cpp/it/d4np/memorypool/**.hpp' + - 'docs/doxygen/**' + - '.github/workflows/docs-site.yml' + workflow_dispatch: + +permissions: + contents: read + +jobs: + build: + name: Build API docs (warn-as-error gate) + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: Install Doxygen + run: | + sudo apt-get update + sudo apt-get install -y --no-install-recommends doxygen + doxygen --version + + - name: Generate API reference (PROJECT_NUMBER from version.hpp) + run: | + set -euo pipefail + ver=$(sed -n 's/.*PBR_MEMORY_POOL_VERSION_STRING[^"]*"\([^"]*\)".*/\1/p' \ + src/main/cpp/it/d4np/memorypool/version.hpp) + if [ -z "$ver" ]; then + echo "::error::could not extract PBR_MEMORY_POOL_VERSION_STRING from version.hpp" + exit 1 + fi + echo "Building docs for version $ver" + # WARN_AS_ERROR = FAIL_ON_WARNINGS in the Doxyfile makes any doc + # warning fail this step — the M7.1 / ADR-0013 §5 gate. + ( cat docs/doxygen/Doxyfile; echo "PROJECT_NUMBER = $ver" ) | doxygen - + test -f build/doxygen/html/index.html + + - name: Upload Pages artifact + if: github.event_name != 'pull_request' + uses: actions/upload-pages-artifact@v3 + with: + path: build/doxygen/html + + deploy: + name: Deploy to GitHub Pages + # Deploy only off master / manual dispatch — never from a PR. + if: github.event_name != 'pull_request' + needs: build + runs-on: ubuntu-latest + # Serialize deploys; never cancel an in-progress deployment. + concurrency: + group: pages + cancel-in-progress: false + permissions: + pages: write + id-token: write + environment: + name: github-pages + url: ${{ steps.deployment.outputs.page_url }} + steps: + - name: Deploy + id: deployment + uses: actions/deploy-pages@v4 diff --git a/CHANGELOG.md b/CHANGELOG.md index e39ce96..a0b3f13 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,6 +18,27 @@ under *Changed* or *Removed*. The `Unreleased` block accumulates entries during development and is rolled into a dated version block (`## [X.Y.Z] — YYYY-MM-DD`) when a release PR closes a milestone. +### Added (M7.1) + +- **Doxygen-generated API reference published as a static site** ([ADR-0027](docs/adr/0027-doxygen-html-site-and-publication-pipeline.md), ROADMAP §7.1). A + checked-in partial Doxyfile ([`docs/doxygen/Doxyfile`](docs/doxygen/Doxyfile)) and a + hand-written landing page ([`docs/doxygen/mainpage.md`](docs/doxygen/mainpage.md)) drive + a dependency-free Doxygen HTML build (built-in theme + treeview, no Graphviz, no Python + doc stack) over the public-header contract surface only. `PROJECT_NUMBER` is injected at + build time from `version.hpp` so the version string stays single-sourced. +- **`docs-site` CI workflow** ([`.github/workflows/docs-site.yml`](.github/workflows/docs-site.yml)) — builds the + reference as a **warn-as-error gate on every PR** (`WARN_AS_ERROR = FAIL_ON_WARNINGS`, + refining the ADR-0013 §5 expectation to gate documentation *correctness* — doc-rot, + stale `@param`, broken refs — not exhaustiveness) and **publishes to GitHub Pages on + push to `master`** via the official `upload-pages-artifact` / `deploy-pages` Actions. +- README gains a `docs-site` build badge and a pointer to the published API reference. + +### Changed (M7.1) + +- Three public-header Doxygen comments use the `%` auto-link escape + (`::%operator new` / `::%operator delete`) to silence spurious unresolved-link warnings + on the global operators under the new warn-as-error gate. No API or behavior change. + ## [0.6.0] — 2026-06-14 **Milestone 6 — Observability & Decorators.** Optional logging / statistics / tracing diff --git a/README.md b/README.md index c7709b0..f71d6b1 100644 --- a/README.md +++ b/README.md @@ -2,6 +2,7 @@ [![ci](https://github.com/danielPoloWork/pbr-cpp-memory-pool/actions/workflows/ci.yml/badge.svg?branch=master)](https://github.com/danielPoloWork/pbr-cpp-memory-pool/actions/workflows/ci.yml) [![docs](https://github.com/danielPoloWork/pbr-cpp-memory-pool/actions/workflows/docs.yml/badge.svg)](https://github.com/danielPoloWork/pbr-cpp-memory-pool/actions/workflows/docs.yml) +[![docs-site](https://github.com/danielPoloWork/pbr-cpp-memory-pool/actions/workflows/docs-site.yml/badge.svg)](https://github.com/danielPoloWork/pbr-cpp-memory-pool/actions/workflows/docs-site.yml) [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE) [![Standard: C++17 / ANSI C](https://img.shields.io/badge/Standard-C%2B%2B17%20%2F%20ANSI%20C-blue.svg)](docs/specs/01_spec_cpp_memory_pool.md) [![Status: v0.6.0 observability](https://img.shields.io/badge/Status-v0.6.0%20observability-green.svg)](https://github.com/danielPoloWork/pbr-cpp-memory-pool/releases/tag/v0.6.0) @@ -37,6 +38,8 @@ void memory_pool_destroy(memory_pool_t* pool); A C++17 RAII wrapper (`it::d4np::memorypool::Pool`) and a typed template (`TypedPool`) layer on top of this surface — see Milestones 2.5 and 3.2 in [`ROADMAP.md`](ROADMAP.md). +The complete, cross-linked **API reference** — every public symbol's parameter / return / throws contract — is generated from the in-header Doxygen comments and published to [GitHub Pages](https://danielpolowork.github.io/pbr-cpp-memory-pool/) on every push to `master` ([ADR-0027](docs/adr/0027-doxygen-html-site-and-publication-pipeline.md)). The same build runs as a warn-as-error gate on every PR. + ## Architecture The pool manages free memory using a **free list embedded inside the free blocks themselves**: when a block is free, its first `sizeof(void*)` bytes hold the address of the next free block. Live blocks carry no metadata at all. @@ -109,7 +112,7 @@ Every PR must clear, at minimum: | Public API docs | Doxygen-compatible, builds without warnings | | Performance claims | Backed by reproducible benchmark under `src/bench/` | -Full quality contract: [`AGENTS.md`](AGENTS.md) §10. The C++ build matrix, sanitizers, `clang-format`, `clang-tidy` diff gate, ANSI C / C99 verification, and zero-external-dependency audit run on every PR via [`ci.yml`](.github/workflows/ci.yml); a docs-only workflow ([`docs.yml`](.github/workflows/docs.yml)) covers markdownlint, internal link checks, and ADR numbering sanity. Both badges above gate `master`. +Full quality contract: [`AGENTS.md`](AGENTS.md) §10. The C++ build matrix, sanitizers, `clang-format`, `clang-tidy` diff gate, ANSI C / C99 verification, and zero-external-dependency audit run on every PR via [`ci.yml`](.github/workflows/ci.yml); a docs-only workflow ([`docs.yml`](.github/workflows/docs.yml)) covers markdownlint, internal link checks, and ADR numbering sanity; a docs-site workflow ([`docs-site.yml`](.github/workflows/docs-site.yml)) builds the Doxygen API reference as a warn-as-error gate on every PR and publishes it to GitHub Pages on push to `master` ([ADR-0027](docs/adr/0027-doxygen-html-site-and-publication-pipeline.md)). The badges above gate `master`. ## Build and test diff --git a/ROADMAP.md b/ROADMAP.md index 7fd3d17..7da86e8 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -108,7 +108,7 @@ Goal: optional logging / statistics / tracing without touching the hot path of r Goal: ship a v1.0.0 reference implementation. -- [ ] 7.1 Doxygen-generated API documentation published as a static site. +- [x] 7.1 Doxygen-generated API documentation published as a static site. Implemented per [ADR-0027](docs/adr/0027-doxygen-html-site-and-publication-pipeline.md), closing the rendering half that [ADR-0013](docs/adr/0013-doxygen-for-api-markdown-for-narrative.md) §4–§5 deferred to this item. A checked-in **partial** Doxyfile ([`docs/doxygen/Doxyfile`](docs/doxygen/Doxyfile)) plus a hand-written landing page ([`docs/doxygen/mainpage.md`](docs/doxygen/mainpage.md)) drive a **dependency-free** Doxygen HTML build — built-in theme with `GENERATE_TREEVIEW`, no Graphviz (`HAVE_DOT = NO`), no vendored CSS, no Python doc stack (the MkDocs/Sphinx-Breathe unified narrative site sketched in ADR-0013 §4 is explicitly **deferred post-v1.0**, consistent with spec §3.3). `INPUT` is the public-header contract surface only (`*.h` + `*.hpp` under `src/main/cpp/it/d4np/memorypool/`, `EXTRACT_PRIVATE = NO`), with `PBR_MEMORY_POOL_DIAGNOSTICS=1` predefined so the ADR-0019 free-list iterator surface renders. **The warn-as-error gate refines ADR-0013 §5**: `WARN_AS_ERROR = FAIL_ON_WARNINGS` + `WARN_IF_DOC_ERROR = YES` fail CI on the *doc-rot* class (malformed commands, unresolved cross-references, stale `@param` names) while `WARN_IF_UNDOCUMENTED` / `WARN_NO_PARAMDOC` stay **off** — gating documentation *correctness*, not ceremonial *exhaustiveness* on every operator and trait typedef (ADR-0027 §3). `PROJECT_NUMBER` is left blank and **injected at build time from `version.hpp`** so the version string stays single-sourced. A new workflow ([`.github/workflows/docs-site.yml`](.github/workflows/docs-site.yml)) builds the site as a **warn-as-error gate on every PR** (no deploy — PRs are never blocked by Pages configuration) and **publishes to GitHub Pages on push to `master`** via the official `upload-pages-artifact` / `deploy-pages` Actions (no generated HTML committed; `build/` is git-ignored). Three public-header comments gain the Doxygen `%` auto-link escape (`::%operator new` / `::%operator delete`) to silence spurious unresolved-link warnings on the global operators. Verified locally with Doxygen 1.10.0: zero warnings, `build/doxygen/html/index.html` generated. **One-time maintainer action:** enable GitHub Pages with *Source: GitHub Actions* in repository settings before the first `master` deploy (the PR gate works regardless). - [ ] 7.2 README: full usage example, performance summary, compatibility matrix. - [ ] 7.3 `CHANGELOG.md` audit for the v1.0.0 entry: consolidate every Unreleased line accumulated since `v0.6.0`, verify category placement, and write the v1.0.0 summary headline (the file itself was introduced in Milestone 1.12). - [ ] 7.4 ADR: install / packaging layout (public-header export, pkg-config, CMake `find_package` config file) — phase 1 distribution per ADR-0004 §5. diff --git a/docs/adr/0027-doxygen-html-site-and-publication-pipeline.md b/docs/adr/0027-doxygen-html-site-and-publication-pipeline.md new file mode 100644 index 0000000..885ab92 --- /dev/null +++ b/docs/adr/0027-doxygen-html-site-and-publication-pipeline.md @@ -0,0 +1,82 @@ +# ADR-0027: Doxygen HTML API site published to GitHub Pages + +- **Status:** Accepted +- **Date:** 2026-06-14 +- **Deciders:** Daniel Polo (maintainer) +- **Related:** [ADR-0013](0013-doxygen-for-api-markdown-for-narrative.md) (Doxygen for the API contract, Markdown for the narrative — this ADR closes the rendering half it deferred), [ROADMAP](../../ROADMAP.md) §7.1 (the item this ADR implements), [ADR-0005](0005-toolchain-matrix-and-supported-platforms.md) §3 (zero-external-dependency philosophy), [ADR-0006](0006-code-style-and-static-analysis-baseline.md) §1 (`.clang-format` leaves Doxygen comments untouched), [`docs/specs/01_spec_cpp_memory_pool.md`](../specs/01_spec_cpp_memory_pool.md) §3.3 (the no-external-dependency contract whose spirit this ADR extends to the docs toolchain). + +## Context + +[ADR-0013](0013-doxygen-for-api-markdown-for-narrative.md) settled the documentation **format** question: Doxygen owns the per-symbol API contract in the public headers, Markdown owns the narrative. It deliberately left the **rendering pipeline** open — §4 names a Doxygen-generated API section optionally wrapped by MkDocs / Sphinx-Breathe for a unified site, but states *"the final pick is M7.1's choice and is not pre-empted here"*; §5 sketches an *expected* warn-as-error Doxyfile *"added in M7.1"*. [ROADMAP](../../ROADMAP.md) §7.1 — the first item of the v1.0 polish milestone — is exactly that work: *"Doxygen-generated API documentation published as a static site."* + +So the forces are fixed and the decision space is bounded: + +- The format is Doxygen (ADR-0013); only the **build, gate, and hosting** are open. +- The project is a single-maintainer reference implementation with a standing **zero-external-dependency** posture (spec §3.3, ADR-0005 §3) — applied to the build graph, and reasonably extended to the docs toolchain: a heavy Python documentation stack would be the largest dependency in the repository. +- AGENTS.md §10 already promises a *"Doxygen-compatible, builds without warnings"* public surface; M7.1 must turn that promise into a CI gate so it cannot silently rot before v1.0. +- The headers are a small set (one C header plus six C++ headers); the API surface is narrow and stable. + +## Decision + +We publish a **Doxygen-generated static HTML site** to **GitHub Pages**, built and deployed by the GitHub-native Pages Actions, with **no external documentation toolchain** (no MkDocs, no Sphinx, no SaaS, no Graphviz). A checked-in **partial Doxyfile** at [`docs/doxygen/Doxyfile`](../doxygen/Doxyfile) drives the build; a dedicated mainpage at [`docs/doxygen/mainpage.md`](../doxygen/mainpage.md) is the landing page and links out to the GitHub-rendered narrative. A new workflow, [`.github/workflows/docs-site.yml`](../../.github/workflows/docs-site.yml), builds the site as a **warn-as-error gate on every pull request** and **deploys it to Pages on push to `master`**. The site scope is the **API reference only**; the unified narrative-plus-API site sketched in ADR-0013 §4 is explicitly **deferred to post-v1.0**. + +Four sub-decisions make the contract precise: + +### 1. Hosting — GitHub Pages via the official Actions + +The site is uploaded with `actions/upload-pages-artifact` and published with `actions/deploy-pages` into the `github-pages` environment. No generated HTML is committed to the repository (the output lives under the git-ignored `build/`), so git history carries no binary doc churn. Publishing is GitHub-native — the same platform that already hosts the code, CI, and releases — so there is no new account, secret, or third-party service in the trust boundary. + +### 2. Scope — API reference now, unified narrative site later + +For v1.0 the site renders the public-header API contract and a single hand-written mainpage. The MkDocs Material / Sphinx-Breathe wrapper that ADR-0013 §4 anticipated — folding the ADRs, spec, and workflow guides into one indexed site — is **not** built here: it would introduce a Python toolchain (the project's heaviest dependency to date) for narrative that GitHub already renders well, and it is a research-and-tune exercise that does not belong on the v1.0 critical path. The mainpage links out to the GitHub-rendered narrative, so nothing is lost; the unified site remains a clean, non-breaking future addition (a post-1.0 candidate alongside the Milestone 8 i18n work). + +### 3. The gate validates documentation *correctness*, not *exhaustiveness* + +This **refines** the expectation sketched in ADR-0013 §5. The Doxyfile sets `WARN_AS_ERROR = FAIL_ON_WARNINGS` (the modern form of "WARN_AS_ERROR = YES": it runs the full pass, prints every warning, then exits non-zero) together with `WARN_IF_DOC_ERROR = YES`. It deliberately leaves `WARN_IF_UNDOCUMENTED`, `WARN_IF_INCOMPLETE_DOC`, and `WARN_NO_PARAMDOC` **off**. The gate therefore fails on the **doc-rot** class — a malformed command, an unresolved cross-reference, a `@param` whose name no longer matches the signature — but not on the absence of a `@param` stanza for every comparison operator or the absence of a doc comment on every iterator trait typedef. Empirically, enabling the exhaustiveness knobs produced ~40 warnings that were almost entirely ceremonial (forced `@param`/`@return` on `operator==`, `operator++`, the five `LegacyForwardIterator` member typedefs, defaulted special members, and the internal config macros) — noise that would push contributors toward filler comments rather than better ones. "Every public symbol carries a comment" stays an AGENTS.md §9 review obligation, enforced socially; the CI gate enforces that the comments that exist are *correct and resolvable*. + +### 4. Version is single-sourced from `version.hpp` + +`PROJECT_NUMBER` is left blank in the checked-in Doxyfile and injected at build time from `PBR_MEMORY_POOL_VERSION_STRING` in [`version.hpp`](../../src/main/cpp/it/d4np/memorypool/version.hpp) (`( cat Doxyfile; echo "PROJECT_NUMBER = $ver" ) | doxygen -`). The version constants stay in exactly one place, so a release bump does not have to remember the Doxyfile — and the Milestone 8.6 consistency lint has one fewer copy to police. + +The HTML is dependency-free: the built-in Doxygen theme with `GENERATE_TREEVIEW = YES`, no Graphviz (`HAVE_DOT = NO`), and no vendored third-party CSS. `PBR_MEMORY_POOL_DIAGNOSTICS=1` is predefined so the free-list diagnostic surface (ADR-0019) appears in the reference. + +## Alternatives Considered + +- **MkDocs Material or Sphinx-Breathe unified site now.** The ADR-0013 §4 end-state — one site indexing API reference *and* narrative. Rejected for v1.0: it adds a Python documentation toolchain (the repository's largest dependency), is a tune-and-iterate research task off the v1.0 critical path, and delivers marginal value over GitHub's already-good Markdown rendering. Deferred post-1.0, where it can be evaluated without release pressure. +- **Read the Docs (or another hosted docs SaaS).** Rejected. It is an external service in the trust boundary, inconsistent with the project's zero-external-dependency posture, when GitHub Pages — already part of the platform hosting everything else — does the job with no new account or secret. +- **Commit generated HTML to a `gh-pages` branch or `docs/` folder.** Rejected. It floods git history with regenerated binary/HTML churn on every doc change and invites the committed output to drift from the headers. The Actions artifact-deploy model keeps the repository to source only. +- **`doxygen-awesome-css` vendored theme.** A popular modern Doxygen skin. Rejected for now: it is a third-party asset to vendor and keep current, and the built-in 1.9/1.10 theme with treeview is clean and adequate for a narrow API surface. Revisitable later as pure polish; not worth a maintained dependency at v1.0. +- **Graphviz/`dot` collaboration & inheritance diagrams.** Tempting given the composition-heavy design (Decorator, Adapter, TypedPool all compose `Pool`). Rejected/deferred: it adds a `graphviz` dependency, makes local validation diverge from CI unless every contributor installs `dot`, and the header set is small enough that Doxygen's textual cross-references convey the relationships. A clean future enhancement. +- **Gate on full documentation exhaustiveness (`WARN_IF_UNDOCUMENTED` + `WARN_NO_PARAMDOC`).** The literal reading of ADR-0013 §5's "fails if any public symbol is missing a comment." Rejected as the *enforced* gate for the reasons in Decision §3 — it rewards ceremonial filler over correctness. Kept as a review obligation, not a build gate. +- **Hardcode the version in the Doxyfile.** Rejected — it creates a fourth copy of the version string to keep in lockstep and would drift on the next release bump; build-time injection from `version.hpp` is the single-source-of-truth path. + +## Consequences + +**Positive** + +- The public API contract is now a browsable, cross-linked, versioned static site — the v1.0 reference-implementation deliverable ROADMAP §7.1 asks for, with no service or toolchain to operate beyond GitHub itself. +- The warn-as-error gate runs on every PR that touches a public header or the Doxygen config, so doc rot (renamed parameters, broken refs, malformed commands) fails CI before merge — the technical backstop ADR-0013 §5 and AGENTS.md §10 promised. +- Zero new runtime or build dependencies; the docs toolchain matches the project's spec §3.3 zero-dependency philosophy. Version stays single-sourced. +- The decision is reversible and extensible: the unified MkDocs/Sphinx site, a vendored theme, and `dot` diagrams are all clean future additions that do not invalidate this pipeline. + +**Negative / costs** + +- **GitHub Pages must be enabled once in repository settings** (Settings → Pages → Source: *GitHub Actions*). Until the maintainer does so, the `deploy` job on `master` fails; the **PR build gate is unaffected** (it never deploys), so contributor workflow is not blocked. This one-time action is called out in the M7.1 PR body. +- CI installs Doxygen from `apt` (Ubuntu 24.04 → Doxygen 1.9.x), which may lag the maintainer's local 1.10.x. The Doxyfile uses only options available since 1.9.5, so the gate behaves identically; a future version-specific divergence would surface as a CI failure, not a silent skip. +- Three public-header comments now write `::%operator new` / `::%operator delete` — the Doxygen `%` escape that suppresses a spurious auto-link to the global operators (which are not documented symbols in this project, so the link cannot resolve). The `%` is invisible in the rendered HTML and is a conventional Doxygen-ism, at the cost of a minor blemish when reading the raw header. +- The narrative (ADRs, spec, guides) is **not yet** unified with the API reference on one site; readers follow the mainpage's outbound links to GitHub. Acceptable for v1.0 and explicitly deferred (Decision §2). + +**Documentation updates landing in the same PR as this ADR** + +- [`docs/adr/README.md`](README.md) — index row for ADR-0027 (Accepted). +- [ROADMAP](../../ROADMAP.md) §7.1 — checkbox flipped with an implementation note. +- [`README.md`](../../README.md) — a pointer to the published API-reference site and a `docs-site` build badge. +- [`CHANGELOG.md`](../../CHANGELOG.md) `Unreleased` — `Added` entry recording the pipeline and ADR. + +## References + +- [ADR-0013](0013-doxygen-for-api-markdown-for-narrative.md) §4–§5 — the rendering pipeline and warn-as-error expectation this ADR decides and refines. +- [ROADMAP](../../ROADMAP.md) §7.1 — the item implemented here. +- [`docs/doxygen/Doxyfile`](../doxygen/Doxyfile), [`docs/doxygen/mainpage.md`](../doxygen/mainpage.md), [`.github/workflows/docs-site.yml`](../../.github/workflows/docs-site.yml) — the artifacts this ADR governs. +- Doxygen manual — [`https://www.doxygen.nl/manual/`](https://www.doxygen.nl/manual/); `WARN_AS_ERROR` / `FAIL_ON_WARNINGS` and the auto-link `%` escape referenced above. +- GitHub Pages with Actions — [`https://github.com/actions/deploy-pages`](https://github.com/actions/deploy-pages). diff --git a/docs/adr/README.md b/docs/adr/README.md index 7096b0e..b9d8a1f 100644 --- a/docs/adr/README.md +++ b/docs/adr/README.md @@ -59,5 +59,6 @@ Do **not** write one for purely local implementation details, formatting, or tri | 0024 | [Dynamic-growth synchronization, creation surface, and the lock-free deferral](0024-dynamic-growth-synchronization-and-creation-surface.md) | Accepted | | 0025 | [Decorator for an instrumented pool variant](0025-decorator-for-instrumented-pool.md) | Accepted | | 0026 | [Observer for pool-lifecycle events](0026-observer-for-pool-lifecycle-events.md) | Accepted | +| 0027 | [Doxygen HTML API site published to GitHub Pages](0027-doxygen-html-site-and-publication-pipeline.md) | Accepted | When adding a new ADR, append a row to this table in the same PR. diff --git a/docs/doxygen/Doxyfile b/docs/doxygen/Doxyfile new file mode 100644 index 0000000..b3ad30d --- /dev/null +++ b/docs/doxygen/Doxyfile @@ -0,0 +1,106 @@ +# Doxygen configuration for pbr-cpp-memory-pool. +# +# Generates the public API reference site from the Doxygen comments in the +# project's public headers. The format split (Doxygen for the API contract, +# Markdown for the narrative) is ADR-0013; the publication pipeline this file +# feeds (Doxygen HTML -> GitHub Pages, warn-as-error gate) is ADR-0027. +# +# This is a PARTIAL configuration: every option not set here keeps its Doxygen +# default. Run it from the REPOSITORY ROOT so the relative INPUT / OUTPUT paths +# resolve, and inject the version at invocation time (the single source of truth +# is version.hpp, so PROJECT_NUMBER is deliberately left blank here): +# +# ver=$(sed -n 's/.*PBR_MEMORY_POOL_VERSION_STRING[^"]*"\([^"]*\)".*/\1/p' \ +# src/main/cpp/it/d4np/memorypool/version.hpp) +# ( cat docs/doxygen/Doxyfile; echo "PROJECT_NUMBER = $ver" ) | doxygen - +# +# Doxygen version this file targets: 1.10.x. + +#--------------------------------------------------------------------------- +# Project identity +#--------------------------------------------------------------------------- +PROJECT_NAME = "pbr-cpp-memory-pool" +PROJECT_BRIEF = "Fixed-block-size O(1) memory pool — C++17 with an ANSI C public surface" +PROJECT_NUMBER = +OUTPUT_DIRECTORY = build/doxygen +OUTPUT_LANGUAGE = English +MARKDOWN_SUPPORT = YES +TAB_SIZE = 4 + +#--------------------------------------------------------------------------- +# Input — the public contract surface only (ADR-0013 §2) +#--------------------------------------------------------------------------- +INPUT = docs/doxygen/mainpage.md \ + src/main/cpp/it/d4np/memorypool +FILE_PATTERNS = *.h *.hpp +RECURSIVE = YES +USE_MDFILE_AS_MAINPAGE = docs/doxygen/mainpage.md +EXCLUDE_SYMBOLS = + +#--------------------------------------------------------------------------- +# Extraction — public symbols only (ADR-0013 §5) +#--------------------------------------------------------------------------- +EXTRACT_ALL = NO +EXTRACT_PRIVATE = NO +EXTRACT_STATIC = NO +EXTRACT_LOCAL_CLASSES = NO +EXTRACT_ANON_NSPACES = NO +HIDE_UNDOC_MEMBERS = NO +HIDE_UNDOC_CLASSES = NO +JAVADOC_AUTOBRIEF = YES +QT_AUTOBRIEF = YES +OPTIMIZE_OUTPUT_FOR_C = NO +BUILTIN_STL_SUPPORT = YES +SHOW_INCLUDE_FILES = YES +SORT_MEMBER_DOCS = NO + +#--------------------------------------------------------------------------- +# Preprocessing — make the diagnostic surface visible to the parser +#--------------------------------------------------------------------------- +# Predefining PBR_MEMORY_POOL_DIAGNOSTICS=1 documents the free-list iterator +# (ADR-0019) and its C accessors, which are otherwise compiled out. The C++ +# version macro keeps the C++17 attribute / noexcept parsing deterministic. +ENABLE_PREPROCESSING = YES +MACRO_EXPANSION = YES +EXPAND_ONLY_PREDEF = YES +SEARCH_INCLUDES = YES +INCLUDE_PATH = src/main/cpp +PREDEFINED = PBR_MEMORY_POOL_DIAGNOSTICS=1 \ + __cplusplus=201703L + +#--------------------------------------------------------------------------- +# Warnings — the CI gate (ADR-0013 §5, ADR-0027 §4) +#--------------------------------------------------------------------------- +# FAIL_ON_WARNINGS runs the full pass, prints every warning, then exits +# non-zero — the modern, CI-friendly form of the ADR-0013 "WARN_AS_ERROR = YES" +# requirement (it surfaces all problems in one run rather than stopping at the +# first). The gate validates documentation *correctness*, not *exhaustiveness* +# (ADR-0027 §4, refining the expectation sketched in ADR-0013 §5): a malformed +# command, an unresolved cross-reference, or a @param whose name no longer +# matches the signature (the doc-rot class) fails the build. We deliberately do +# NOT gate on WARN_IF_UNDOCUMENTED / WARN_NO_PARAMDOC — forcing a @param stanza +# onto every comparison operator and every iterator trait typedef produces +# ceremonial noise that degrades the reference rather than improving it; "every +# public symbol carries a comment" stays an AGENTS.md §9 review obligation. +QUIET = YES +WARNINGS = YES +WARN_IF_UNDOCUMENTED = NO +WARN_IF_DOC_ERROR = YES +WARN_IF_INCOMPLETE_DOC = NO +WARN_NO_PARAMDOC = NO +WARN_AS_ERROR = FAIL_ON_WARNINGS + +#--------------------------------------------------------------------------- +# HTML output — dependency-free, no Graphviz (consistent with spec §3.3) +#--------------------------------------------------------------------------- +GENERATE_HTML = YES +HTML_OUTPUT = html +GENERATE_TREEVIEW = YES +DISABLE_INDEX = NO +FULL_SIDEBAR = NO +HTML_COLORSTYLE = LIGHT +SOURCE_BROWSER = YES +INLINE_SOURCES = NO +GENERATE_LATEX = NO +GENERATE_XML = NO +HAVE_DOT = NO diff --git a/docs/doxygen/mainpage.md b/docs/doxygen/mainpage.md new file mode 100644 index 0000000..f745103 --- /dev/null +++ b/docs/doxygen/mainpage.md @@ -0,0 +1,45 @@ +# pbr-cpp-memory-pool {#mainpage} + +A fixed-block-size, **O(1)** memory pool with a C++17 implementation behind an +ANSI C (C89-compatible) public surface and **zero external dependencies**. + +This site is the **generated API reference** — the per-symbol contract +(parameters, return values, preconditions, thrown exceptions) extracted from the +Doxygen comments in the public headers. It is one of the two documentation +formats the project maintains; the rationale for the split is +[ADR-0013](https://github.com/danielPoloWork/pbr-cpp-memory-pool/blob/master/docs/adr/0013-doxygen-for-api-markdown-for-narrative.md) +(Doxygen for the API contract, Markdown for the narrative), and the pipeline that +publishes this site is +[ADR-0027](https://github.com/danielPoloWork/pbr-cpp-memory-pool/blob/master/docs/adr/0027-doxygen-html-site-and-publication-pipeline.md). + +## Where to start + +- **C public API** — the four-function contract from spec §5 lives in + `memory_pool.h`: `memory_pool_create`, `memory_pool_alloc`, + `memory_pool_free`, `memory_pool_destroy`. +- **C++ wrapper** — `it::d4np::memorypool::Pool` (RAII, move-only) and its + construction surface (`Pool::make`, `PoolBuilder`) are in `memory_pool.hpp`. +- **Typed allocation** — `it::d4np::memorypool::TypedPool` in + `typed_pool.hpp` adds object-lifetime verbs over a typed pool. +- **STL integration** — `it::d4np::memorypool::PoolAllocator` in + `pool_allocator.hpp` is a *Cpp17Allocator* adapter for standard containers. +- **Observability** — `it::d4np::memorypool::InstrumentedPool` in + `instrumented_pool.hpp` is an opt-in Decorator with counters and a + `PoolObserver` lifecycle-event hook. +- **Diagnostics** — `it::d4np::memorypool::FreeListView` in + `free_list_iterator.hpp` is a read-only iterator over the implicit free list, + compiled in only when diagnostics are enabled. + +## Beyond the API reference + +The narrative documentation — the specification, the Architecture Decision +Records, the design-patterns catalogue, the roadmap, and the release notes — is +authored in Markdown and rendered on GitHub: + +- [Project README](https://github.com/danielPoloWork/pbr-cpp-memory-pool/blob/master/README.md) +- [Specification](https://github.com/danielPoloWork/pbr-cpp-memory-pool/blob/master/docs/specs/01_spec_cpp_memory_pool.md) +- [Architecture Decision Records](https://github.com/danielPoloWork/pbr-cpp-memory-pool/tree/master/docs/adr) +- [Design-patterns catalogue](https://github.com/danielPoloWork/pbr-cpp-memory-pool/blob/master/docs/patterns/README.md) +- [Roadmap](https://github.com/danielPoloWork/pbr-cpp-memory-pool/blob/master/ROADMAP.md) + +Licensed under the [MIT License](https://github.com/danielPoloWork/pbr-cpp-memory-pool/blob/master/LICENSE). diff --git a/src/main/cpp/it/d4np/memorypool/memory_pool.h b/src/main/cpp/it/d4np/memorypool/memory_pool.h index e875a0f..e1117f9 100644 --- a/src/main/cpp/it/d4np/memorypool/memory_pool.h +++ b/src/main/cpp/it/d4np/memorypool/memory_pool.h @@ -176,7 +176,7 @@ void memory_pool_free(memory_pool_t* pool, void* block); * back to the operating system, per spec section 3.1 and ADR-0009 §7. * * The backing buffer is released through the matching aligned - * `::operator delete` overload of the C++17 `::operator new(size, + * `::%operator delete` overload of the C++17 `::%operator new(size, * std::align_val_t)` used at creation; the metadata struct is released * via the matching plain `delete`. Passing `NULL` is a no-op. After this * call, @p pool must not be reused. diff --git a/src/main/cpp/it/d4np/memorypool/pool_allocator.hpp b/src/main/cpp/it/d4np/memorypool/pool_allocator.hpp index 6702fbb..95e77d5 100644 --- a/src/main/cpp/it/d4np/memorypool/pool_allocator.hpp +++ b/src/main/cpp/it/d4np/memorypool/pool_allocator.hpp @@ -41,8 +41,8 @@ namespace it::d4np::memorypool { * `T` is not over-aligned. Such requests are served by `Pool::allocate` * (O(1), throwing `std::bad_alloc` on exhaustion per ADR-0016 §2). Every * other request — `n > 1`, an over-aligned `T`, or a rebound node larger - * than the block — is delegated to over-aligned `::operator new` / - * `::operator delete`. + * than the block — is delegated to over-aligned `::%operator new` / + * `::%operator delete`. * * Because the standard guarantees `deallocate(p, n)` is called with the * same `n` (and on the same allocator type, hence the same `sizeof(T)` / @@ -103,7 +103,7 @@ class PoolAllocator { * @return Pointer to uninitialized storage for @p n contiguous `T`. * @throw std::bad_alloc on pool exhaustion (pool-eligible requests), on * `size_t` overflow of `n * sizeof(T)`, or from the fallback - * `::operator new`. + * `::%operator new`. */ [[nodiscard]] T* allocate(std::size_t n) { if (routes_to_pool(n)) { From 5653a01c6829692462ad16642d1194f2f67c3b08 Mon Sep 17 00:00:00 2001 From: Daniel Polo <106583643+danielPoloWork@users.noreply.github.com> Date: Sun, 14 Jun 2026 11:59:03 +0200 Subject: [PATCH 2/2] ci(docs-site): create build/doxygen before running Doxygen A fresh CI checkout has no build/ directory; Doxygen creates the leaf OUTPUT_DIRECTORY but not its missing parent, so the gate failed with "Output directory 'build/doxygen' does not exist and cannot be created". Locally it passed only because prior CMake builds had created build/. mkdir -p build/doxygen up front. Co-Authored-By: Claude Opus 4.8 (1M context) --- .github/workflows/docs-site.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/docs-site.yml b/.github/workflows/docs-site.yml index f9cb5ce..3a409b0 100644 --- a/.github/workflows/docs-site.yml +++ b/.github/workflows/docs-site.yml @@ -47,6 +47,9 @@ jobs: exit 1 fi echo "Building docs for version $ver" + # Doxygen creates OUTPUT_DIRECTORY's leaf but not its missing parent, + # and a fresh CI checkout has no build/ dir — create it up front. + mkdir -p build/doxygen # WARN_AS_ERROR = FAIL_ON_WARNINGS in the Doxyfile makes any doc # warning fail this step — the M7.1 / ADR-0013 §5 gate. ( cat docs/doxygen/Doxyfile; echo "PROJECT_NUMBER = $ver" ) | doxygen -