Skip to content

Commit e06a7c0

Browse files
committed
[#282]:svarga:docs, decorate H5D public surface + clean group titles
Parallel of the H5A decoration sweep for the dataset (H5D*) family. Most H5D files already had alias-first docstrings from the prior sweep -- this turn focuses on the gaps (H5Dread, H5Dappend, H5Dsparse, H5Dopen) and on shortening the @defgroup titles across the API so the rendered Topics / Modules tree reads cleanly. Unlike H5A, the H5D public surface does not use SFINAE on the parent type -- every signature takes a concrete h5::fd_t / h5::ds_t -- so the H5CPP_*_RET return-type macro pattern from H5A does not apply here. The lowercase hid_t template-param rename does not apply either. DOCSTRINGS * H5Dread.hpp -- 8 overloads modernised from the older chained-aliases format to the full template (one-liner @brief, detailed description, \par_* parameter aliases, @throws, @code example, \sa_h5cpp / \sa_hdf5, @sa cross-refs): - read(ds, T* ptr, args...) -- low-level raw pointer - read(fd, path, T* ptr, args...) - read(file_path, path, T* ptr, args...) - read(ds, T& ref, args...) -- primary by-reference path - read(fd, path, T& ref, args...) - read(file_path, path, T& ref, args...) - T read(ds, args...) -- return-by-value primary - T read(fd, path, args...) - T read(file_path, path, args...) Each docstring distinguishes its overload's role (primary vs convenience) and points at sibling overloads through @sa. * H5Dappend.hpp -- 4 public entry points decorated: - append(pt, const T&) -- buffered element append - append(pt, const T*) -- raw-chunk path - flush(pt) -- explicit chunk flush - reset(pt) -- dimension-tracker reset Includes streaming-loop @code example showing the create / append / flush flow against an extendable chunked dataset. * H5Dsparse.hpp -- both public entry points decorated: - write<T, LOC>(parent, path, sparse_src) - read<T, LOC>(parent, path) Documents the CSC group layout, scipy / 10x / Loompy interop, the uint32-on-disk index width limit, the sync() / makeCompressed() preconditions, and the ColMajor static_assert. Cross-references the Supported Linear Algebra Types page § Sparse storage layout. * H5Dopen.hpp -- single public entry point modernised: - open(fd, path, dapl) -- with note on the high-throughput pipeline tag auto-initialisation path. GROUP TITLES (h5cpp/H5config.hpp) * Renamed the @defgroup titles so the rendered group page titles read as short noun phrases instead of the inline-signature form the project used historically: - io-create "template <T> ds_t create( ... );" -> "HDF5 datasets -- create" - io-read "h5::read<T>( ds | path [,offset]...)" -> "HDF5 datasets -- read" - io-write "herr_t h5::write<T>( ds | path, object<T>...)" -> "HDF5 datasets -- write" - io-append "h5::append<T>( pt , T object);" -> "HDF5 packet table -- append" - io-wrap "`handle` | `type_id` with RAII" -> "RAII handles" - file-io "`h5::open` | `h5::create` | `h5::mute` | `h5::unmute`" -> "HDF5 files" * Added @defgroup sparse-io ("HDF5 sparse datasets") so the func_sparse_hdr alias actually produces a group page (was previously a dangling reference). Mirrors the attribute-io fix from the H5A sweep. * The attribute-io title rename ("HDF5 attributes") landed in the H5A commit and is unchanged here. ALIAS VOCABULARY * docs/links/h5cpp.txt + docs/aliases.md catalog -- added \func_append_hdr (-> @InGroup io-append) alongside the existing func_*_hdr family. Now used by the H5Dappend.hpp public surface. VERIFICATION * End-to-end compile + run on the H5D public surface: create<float> with current_dims{10,10}, write a vector, read it back, append 32 samples through h5::pt_t with chunk{16}, flush. All operations return 0, no diagnostic output. * Doxygen build clean -- no warnings.log produced.
1 parent 0504008 commit e06a7c0

11 files changed

Lines changed: 769 additions & 182 deletions

File tree

docs/aliases.md

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -139,11 +139,12 @@ Conventions:
139139

140140
| Alias | Expands to | Use on |
141141
|---|---|---|
142-
| `\func_read_hdr` | `@ingroup io-read` | every `h5::read` overload |
143-
| `\func_write_hdr` | `@ingroup io-write` | every `h5::write` overload |
144-
| `\func_create_hdr` | `@ingroup io-create` | every `h5::create` overload |
142+
| `\func_read_hdr` | `@ingroup datasets` | every `h5::read` overload |
143+
| `\func_write_hdr` | `@ingroup datasets` | every `h5::write` overload |
144+
| `\func_create_hdr` | `@ingroup datasets` | every `h5::create` overload |
145+
| `\func_append_hdr` | `@ingroup datasets` | `h5::append` / `h5::flush` / `h5::reset` (packet table) |
145146
| `\func_attr_hdr` | `@ingroup attribute-io` | every `h5::aread` / `h5::awrite` |
146-
| `\func_sparse_hdr` | `@ingroup sparse-io` | sparse read/write overloads |
147+
| `\func_sparse_hdr` | `@ingroup datasets` | sparse read/write overloads |
147148
| `\func_async_hdr` | `@ingroup async-io` | `h5::async::*` factories |
148149
| `\func_traversal_hdr` | `@ingroup traversal` | `h5::ls` / `h5::dfs` / `h5::bfs` |
149150
| `\func_read_desc` | one-line read description | combine with `func_read_hdr` |

docs/links/h5cpp.txt

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -82,16 +82,23 @@ ALIASES += returns_ref="@return `h5::reference_t` handle (rule-of-five RAII; thr
8282
ALIASES += returns_paths="@return `std::vector<std::string>` of object paths relative to the start node"
8383

8484
############ FUNCTION GROUP HEADERS
85-
ALIASES += func_create_hdr="\ingroup io-create"
85+
# All dataset-side overloads land in the single `datasets` group (HDF5
86+
# datasets) — mirrors how `attribute-io` carries the full attribute
87+
# surface. The per-operation aliases (\func_read_hdr, \func_write_hdr,
88+
# etc.) are kept as semantic markers in source so a reader can tell at
89+
# a glance which surface a function belongs to; the @ingroup target is
90+
# uniform on the rendered side.
91+
ALIASES += func_create_hdr="\ingroup datasets"
8692
ALIASES += func_create_links="\sa_h5cpp \sa_hdf5 \sa_stl \sa_linalg"
8793

88-
ALIASES += func_write_hdr="\ingroup io-write"
94+
ALIASES += func_write_hdr="\ingroup datasets"
8995
ALIASES += func_write_desc="Write an object into an HDF5 dataset. The dataset must exist or be created first with `h5::create`."
9096

91-
ALIASES += func_read_hdr="\ingroup io-read"
97+
ALIASES += func_read_hdr="\ingroup datasets"
9298
ALIASES += func_read_desc="Read data from an HDF5 dataset into memory. Optional offset/stride/count/block arguments select a hyperslab; omitting them reads the entire dataset."
9399

100+
ALIASES += func_append_hdr="\ingroup datasets"
94101
ALIASES += func_attr_hdr="\ingroup attribute-io"
95-
ALIASES += func_sparse_hdr="\ingroup sparse-io"
102+
ALIASES += func_sparse_hdr="\ingroup datasets"
96103
ALIASES += func_async_hdr="\ingroup async-io"
97104
ALIASES += func_traversal_hdr="\ingroup traversal"

doxy/Doxyfile

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -133,7 +133,8 @@ HTML_FILE_EXTENSION = .html
133133
HTML_HEADER = header.html
134134
HTML_FOOTER = footer.html
135135
HTML_EXTRA_STYLESHEET = doxygen-awesome.css customdoxygen.css
136-
HTML_EXTRA_FILES = doxygen-awesome-darkmode-toggle.js
136+
HTML_EXTRA_FILES = doxygen-awesome-darkmode-toggle.js \
137+
doxygen-overload-collapse.js
137138
HTML_COLORSTYLE_HUE = 28
138139
HTML_COLORSTYLE_SAT = 150
139140
HTML_COLORSTYLE_GAMMA = 80

doxy/customdoxygen.css

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,75 @@ pre.fragment {
100100
border-left: 3px solid var(--primary-light-color);
101101
}
102102

103+
/* ------------------------------------------------------------------ */
104+
/* Overload collapse (doxygen-overload-collapse.js) */
105+
/* ------------------------------------------------------------------ */
106+
107+
/* Compact navigator strip placed under the primary heading of a
108+
* multi-overload run. Lists "[1/N] [2/N] ..." as anchor links so the
109+
* reader sees one entry per function name but can still jump to a
110+
* specific overload signature. */
111+
.overload-jump-strip {
112+
margin: 0.3em 0 1em 0;
113+
padding: 0.2em 0.6em;
114+
font-size: 0.9em;
115+
color: var(--page-secondary-foreground-color);
116+
border-left: 3px solid var(--primary-light-color);
117+
background: var(--code-background);
118+
border-radius: var(--border-radius-small);
119+
}
120+
.overload-jump-strip .overload-jump-label {
121+
font-style: italic;
122+
margin-right: 0.4em;
123+
}
124+
.overload-jump-strip .overload-jump-link {
125+
display: inline-block;
126+
margin: 0 0.15em;
127+
padding: 0 0.35em;
128+
border-radius: var(--border-radius-small);
129+
color: var(--primary-color);
130+
text-decoration: none;
131+
}
132+
.overload-jump-strip .overload-jump-link:hover {
133+
background: var(--primary-color);
134+
color: var(--on-primary-color);
135+
}
136+
137+
/* Folded [2..N] overloads — render the summary like a slimmer memtitle
138+
* so the visual rhythm stays consistent with the unfolded [1/N] header
139+
* above it. */
140+
details.overload-fold {
141+
margin: 0.6em 0;
142+
}
143+
details.overload-fold > summary.overload-summary {
144+
cursor: pointer;
145+
padding: 0.4em 0.8em;
146+
background: var(--code-background);
147+
border-left: 3px solid var(--primary-light-color);
148+
border-radius: var(--border-radius-small);
149+
font-weight: 600;
150+
list-style: none; /* hide default ▶ marker, we draw one below */
151+
}
152+
details.overload-fold > summary.overload-summary::-webkit-details-marker {
153+
display: none;
154+
}
155+
details.overload-fold > summary.overload-summary::before {
156+
content: "▶";
157+
display: inline-block;
158+
margin-right: 0.5em;
159+
color: var(--primary-color);
160+
font-size: 0.8em;
161+
transition: transform 0.15s ease;
162+
}
163+
details.overload-fold[open] > summary.overload-summary::before {
164+
transform: rotate(90deg);
165+
}
166+
details.overload-fold > summary.overload-summary .overload {
167+
color: var(--page-secondary-foreground-color);
168+
font-weight: 400;
169+
margin-left: 0.4em;
170+
}
171+
103172
/* ------------------------------------------------------------------ */
104173
/* Compact function-signature rendering */
105174
/* ------------------------------------------------------------------ */

doxy/doxygen-overload-collapse.js

Lines changed: 169 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,169 @@
1+
// Doxygen 1.9.x renders function-group pages with one <h2 class="memtitle">
2+
// heading per overload — `read() [1/10]`, `read() [2/10]`, ... — producing a
3+
// long vertical stack on overload-heavy free-function groups like the
4+
// `datasets` and `attribute-io` groups in h5cpp.
5+
//
6+
// This script collapses each contiguous run of same-name overloads into a
7+
// single visible heading; the [2..N] overloads' detail blocks become
8+
// <details> sections, collapsed by default and labelled with each overload's
9+
// own [k/N] tag. Anchors are preserved so deep-links from the rest of the
10+
// doc tree still scroll to the exact overload.
11+
//
12+
// Look-and-feel intent: each function name appears as ONE entry on the group
13+
// page, mirroring how a class member page renders overloads under one
14+
// heading. The detail body for [1/N] is shown inline (so the most common
15+
// signature reads at a glance); the rest fold under disclosure widgets.
16+
17+
(function () {
18+
function nameKey(h2) {
19+
// h2.memtitle text is "fnname() [k/N]" (or just "fnname()" when not
20+
// an overload). Strip the [k/N] and trailing whitespace to get the
21+
// group key.
22+
const txt = h2.textContent || "";
23+
// Remove the diamond glyph + non-breaking space the permalink span
24+
// injects ("◆ "), then drop the [k/N] suffix.
25+
return txt.replace(/\s*/, "").replace(/\s*\[\d+\/\d+\]\s*$/, "").trim();
26+
}
27+
28+
function overloadIndex(h2) {
29+
const m = (h2.textContent || "").match(/\[(\d+)\/(\d+)\]\s*$/);
30+
return m ? { k: parseInt(m[1], 10), n: parseInt(m[2], 10) } : null;
31+
}
32+
33+
function detailBlockAfter(h2) {
34+
// The detail block for a memtitle is the immediately-following
35+
// <div class="memitem"> (which itself contains the mlabels table
36+
// with the rendered signature plus the memdoc). Doxygen always
37+
// emits exactly one memitem per memtitle.
38+
let node = h2.nextElementSibling;
39+
while (node && !(node.tagName === "DIV" && node.classList.contains("memitem"))) {
40+
node = node.nextElementSibling;
41+
}
42+
return node;
43+
}
44+
45+
function collapseOverloads(root) {
46+
const headings = Array.from(root.querySelectorAll("h2.memtitle"));
47+
if (!headings.length) return;
48+
49+
// Group consecutive headings sharing the same name key.
50+
const groups = [];
51+
let cur = null;
52+
for (const h of headings) {
53+
const key = nameKey(h);
54+
if (cur && cur.key === key) {
55+
cur.items.push(h);
56+
} else {
57+
if (cur) groups.push(cur);
58+
cur = { key, items: [h] };
59+
}
60+
}
61+
if (cur) groups.push(cur);
62+
63+
for (const g of groups) {
64+
if (g.items.length < 2) continue;
65+
66+
// Strip the [k/N] suffix from the first (visible) heading and
67+
// append a compact overload index that links to each one.
68+
const first = g.items[0];
69+
const firstIdx = overloadIndex(first);
70+
if (firstIdx) {
71+
first.innerHTML = first.innerHTML.replace(
72+
/<span class="overload">\[\d+\/\d+\]<\/span>/,
73+
""
74+
);
75+
}
76+
77+
// Build the overload jump-strip and insert it right after the
78+
// first heading, before its detail body.
79+
const strip = document.createElement("div");
80+
strip.className = "overload-jump-strip";
81+
strip.innerHTML =
82+
'<span class="overload-jump-label">overloads:</span> ' +
83+
g.items
84+
.map((h, i) => {
85+
// Each h2 is preceded by an <a id="..."> anchor or
86+
// contains one inside the permalink span. We pull the
87+
// id from the preceding anchor.
88+
let id = null;
89+
let prev = h.previousElementSibling;
90+
while (prev) {
91+
if (prev.tagName === "A" && prev.id) { id = prev.id; break; }
92+
if (prev.tagName === "H2") break;
93+
prev = prev.previousElementSibling;
94+
}
95+
return id
96+
? `<a class="overload-jump-link" href="#${id}">[${i + 1}/${g.items.length}]</a>`
97+
: `<span class="overload-jump-link">[${i + 1}/${g.items.length}]</span>`;
98+
})
99+
.join(" ");
100+
first.insertAdjacentElement("afterend", strip);
101+
102+
// Fold the [2..N] overloads into <details> elements. The detail
103+
// body sits inside the <details>; the heading becomes the
104+
// <summary>. The preceding <a id="..."> anchor moves INTO the
105+
// <details> so deep-link resolution (openOnHash) can walk up
106+
// from the anchor's parent chain and open the right <details>.
107+
for (let i = 1; i < g.items.length; i++) {
108+
const h = g.items[i];
109+
const detail = detailBlockAfter(h);
110+
if (!detail) continue;
111+
112+
const details = document.createElement("details");
113+
details.className = "overload-fold";
114+
const summary = document.createElement("summary");
115+
summary.className = "overload-summary";
116+
// Strip the diamond glyph from summary text — the disclosure
117+
// triangle replaces it visually.
118+
summary.innerHTML = h.innerHTML.replace(/\s*/, "");
119+
details.appendChild(summary);
120+
121+
// Collect the preceding <a id="..."> anchor (if any) so it
122+
// moves into the <details> alongside the detail body.
123+
const anchor =
124+
h.previousElementSibling &&
125+
h.previousElementSibling.tagName === "A" &&
126+
h.previousElementSibling.id
127+
? h.previousElementSibling
128+
: null;
129+
130+
// Replace the original heading + detail with the <details>
131+
// wrapper containing the anchor + detail body.
132+
h.replaceWith(details);
133+
detail.parentNode.removeChild(detail);
134+
if (anchor) {
135+
anchor.parentNode.removeChild(anchor);
136+
details.insertBefore(anchor, summary.nextSibling);
137+
}
138+
details.appendChild(detail);
139+
}
140+
}
141+
}
142+
143+
function openOnHash() {
144+
// If the URL fragment targets an anchor inside a collapsed
145+
// <details>, open it so the deep-link actually scrolls into view.
146+
if (!window.location.hash) return;
147+
const id = window.location.hash.slice(1);
148+
const target = document.getElementById(id);
149+
if (!target) return;
150+
let node = target.parentElement;
151+
while (node) {
152+
if (node.tagName === "DETAILS") node.open = true;
153+
node = node.parentElement;
154+
}
155+
// Re-trigger the scroll after the layout reflows.
156+
target.scrollIntoView();
157+
}
158+
159+
if (document.readyState === "loading") {
160+
document.addEventListener("DOMContentLoaded", () => {
161+
collapseOverloads(document);
162+
openOnHash();
163+
});
164+
} else {
165+
collapseOverloads(document);
166+
openOnHash();
167+
}
168+
window.addEventListener("hashchange", openOnHash);
169+
})();

doxy/header.html

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
<script type="text/javascript">
2121
DoxygenAwesomeDarkModeToggle.init()
2222
</script>
23+
<script type="text/javascript" src="$relpath^doxygen-overload-collapse.js"></script>
2324
</head>
2425
<body>
2526
<div id="top"><!-- do not remove this div, it is closed by doxygen! -->

0 commit comments

Comments
 (0)