ABI additive-change reviews
tools/check-abi-version.sh fails a build whose installed headers changed while MESHIOPLUSPLUS_ABI_VERSION did not. This file is how that judgement gets recorded when the change really was additive.
One row per release that changed an installed header while holding the ABI version. Adding a row is a claim that every listed header change is Tier C by doc/abi.md's criterion — a new inline function, constexpr variable, type, declaration or header, or an appended enumerator — and therefore cannot affect a consumer that was already compiled. It is not a rubber stamp: the whole point of the ABI number is that a consumer may trust it instead of re-pinning the release version, so a wrong entry here ships silent memory corruption.
The releases and headers changed columns are read by the gate, not just by people. tools/check-abi-version.sh looks for a row matching the ABI version and the release version in CMakeLists.txt, then requires every header that actually changed to be named in it — paths relative to src/cpp/include/meshioplusplus/, as written below. A header you changed but did not list is a red build naming it.
That specificity is the fix for a real defect: through v9.4.0 the gate matched any row whose first column was the current ABI number, so once any ABI-3 row existed, every later header change matched it and passed — reporting "records the additive review" about a review of a different release entirely. A row for one release says nothing about the next one.
If the change edited the body of an existing inline function or template, or moved a data member, it is Tier A/B and belongs in a version bump, not in this table.
| ABI | releases | headers changed | why it is additive |
|---|---|---|---|
| 34 | v17.21.0 | operations/mesh_cad.hpp, version.hpp | version.hpp is the routine release bump (macro values only: minor 20 → 21 and string "17.20.0" → "17.21.0"), as in every prior row. operations/mesh_cad.hpp changes MeshCadLoppedCorner (112 bytes, align 8, as the never-tagged v17.20.0 row states) and the comments on MeshCadSurfaceExtras::mLopCorners and the extras overload, which now accepts mLopCorners instead of throwing. No default argument, inline body, enumerator or other layout changes, so MESHIOPLUSPLUS_ABI_VERSION stays 34. |
| 34 | v17.20.0 | operations/mesh_cad.hpp, version.hpp | version.hpp is the routine release bump (macro values only: minor 19 → 20 and string "17.19.0" → "17.20.0"), as in every prior row. operations/mesh_cad.hpp gains only new declarations: six new structs, MeshCadSurfaceExtras (three bools; 3 bytes, align 1), MeshCadReparamFace (an int64_t, two doubles, a bool, an int32_t and a std::string; 64 bytes, align 8 under libstdc++), MeshCadMergedFace (two int64_t, a double, a std::vector<std::int64_t>, a bool and a std::string; 88 bytes), MeshCadToleranceUse (an int64_t, two doubles and a std::string; 56 bytes), MeshCadLoppedCorner (two int64_t, five doubles, an int64_t, a double, two bools and a std::string; 112 bytes) and MeshCadSurfaceExtrasReport (four std::vectors of them; 96 bytes), all pinned in test_abi_layout.cpp, and a new overload MESHIOPLUSPLUS_API mesh_cad_surface(const BrepInfo&, const MeshCadSurfaceOptions&, const MeshCadSizeSources&, const MeshCadSurfaceExtras&, MeshCadSizeReport* = nullptr, MeshCadSurfaceExtrasReport* = nullptr) beside the unchanged two- and four-argument ones, whose default arguments stay. The comment on MeshCadSurfaceOptions::mReparamConditionNumber changes (its type, default and offset do not): the field, laid out in ABI 34 and refused until now, takes effect in the out-of-line mesh_cad_surface. MeshCadSurfaceOptions (120 bytes), MeshCadSurfaceResult, MeshCadFaceRecord, MeshCadCorner, MeshCadSizeSources and MeshCadSizeReport keep their layouts, which is why the new inputs and reports travel in structs of their own. No existing declaration, default argument, inline body, enumerator or layout changes, so MESHIOPLUSPLUS_ABI_VERSION stays 34. The C header's additions (three fields from mio_mesh_cad_surface_opts_ex's reserved tail, which keeps its 136 bytes, the mio_mesh_cad_tolerance_where enum and the getters) are the C ABI's, checked by its own static_asserts. |
| 34 | v17.19.0 | operations/mesh_cad.hpp, version.hpp | version.hpp is the routine release bump (macro values only: minor 18 → 19 and string "17.18.0" → "17.19.0"), as in every prior row. operations/mesh_cad.hpp gains only new declarations and an include: two new structs, MeshCadSizeSources (two std::vector<std::pair<std::int64_t, double>>, a borrowed const Mesh*, a std::string defaulting to "size" and a bool; 96 bytes, align 8 under libstdc++) and MeshCadSizeReport (two std::vector<std::vector<std::int64_t>>; 48 bytes, align 8), both pinned in test_abi_layout.cpp, and a new overload MESHIOPLUSPLUS_API mesh_cad_surface(const BrepInfo&, const MeshCadSurfaceOptions&, const MeshCadSizeSources&, MeshCadSizeReport* = nullptr) beside the unchanged two-argument one, whose default argument stays; #include <utility> for std::pair. The MeshCadMetric enum's comment changes (its enumerators and values do not): Varying, laid out in ABI 34 and refused until now, takes effect in the out-of-line mesh_cad_surface. MeshCadSurfaceOptions (120 bytes), MeshCadSurfaceResult, MeshCadFaceRecord and MeshCadCorner keep their layouts, which is why the given sizes travel in a struct of their own. No existing declaration, default argument, inline body, enumerator or layout changes, so MESHIOPLUSPLUS_ABI_VERSION stays 34. The C header's additions (mio_mesh_cad_surface_opts_ex, mio_mesh_cad_surface2 and its getters) are the C ABI's, checked by its own static_asserts. |
| 34 | v17.18.0 | operations/mesh_cad.hpp, version.hpp | version.hpp is the routine release bump (macro values only: minor 17 → 18 and string "17.17.0" → "17.18.0"), as in every prior row. operations/mesh_cad.hpp changes in comments only: the file comment describes the size field, pole rings and folds, the Degenerate enumerator's comment also covers a folded triangle, and the trailing comments of MeshCadSurfaceOptions::mGrading, mCurvatureDeviation, mCellsAcrossGaps and mPoleRings become doc comments before them (mMetric's trailing comment is only realigned); with comments and whitespace removed the header is byte-identical to v17.17.0's. Those four fields were laid out in ABI 34 and refused unless 0; they now take effect in the out-of-line mesh_cad_surface. No declaration, enumerator value, default argument, inline body or layout changes (MeshCadSurfaceOptions stays 120 bytes, as test_abi_layout.cpp pins), so MESHIOPLUSPLUS_ABI_VERSION stays 34. The C header's mio_mesh_cad_surface_opts takes pole_rings, grading, curvature_deviation and cells_across_gaps from its reserved tail, keeping its 104 bytes (asserted in c_api.cpp). |
| 34 | v17.17.0 | version.hpp | version.hpp is the routine release bump (macro values only: minor 16 → 17 and string "17.16.0" → "17.17.0"), as in every prior row. This release changes no other installed header: the pipeline's CAD model and the Gmsh 4.1 block split live in operations/pipeline.cpp and formats/gmsh.cpp, and Pipeline, PipelineInput and PipelineStep keep their layouts (the carried model is internal to run_pipeline). No declaration, default argument, inline body, enumerator or layout changes, so MESHIOPLUSPLUS_ABI_VERSION stays 34. |
| 34 | v17.16.0 | operations/mesh_cad.hpp, formats/medit.hpp, version.hpp | version.hpp is the routine release bump (macro values only: minor 15 → 16 and string "17.15.0" → "17.16.0"), as in every prior row. operations/mesh_cad.hpp changes in comments only: the file comment describes the curved elements, the comment on the fields laid out in ABI 34 no longer counts mOrder among those refused, and the trailing comments of MeshCadSurfaceOptions::mOrder and MeshCadSurfaceResult::mNumCurvedStraightened become doc comments before them; both declarations, their types and default member initialisers are unchanged. mOrder was laid out in ABI 34 and refused unless 1; it now accepts 2 and 3 in the out-of-line mesh_cad_surface. No declaration, enumerator value, default argument, inline body or layout changes (MeshCadSurfaceOptions stays 120 bytes, as test_abi_layout.cpp pins), so MESHIOPLUSPLUS_ABI_VERSION stays 34. formats/medit.hpp changes in comments only: the file comment and the write_medit_ascii / read_medit_ascii doc comments name the high-order keywords and their orderings, the region-keeping id lists, and that an unsupported type is skipped with a warning (its stale @throws is dropped); no declaration changes. The C header's mio_mesh_cad_surface_opts and mio_mesh_cad_surface_report take order, reserved_pad and num_curved_straightened from their reserved tails, keeping their sizes (104 and 200 bytes, asserted in c_api.cpp). |
| 33 | v17.14.0 | operations/mesh_cad.hpp, version.hpp | version.hpp is the routine release bump (macro values only: minor 13 → 14 and string "17.13.0" → "17.14.0"), as in every prior row. operations/mesh_cad.hpp changes in comments only: the file comment describes the closed edges, crossing splits and embedded edges mesh_cad_surface now handles, the kMeshCadEdgeName comment names an embedded edge among those cad:edge marks -1, and the MeshCadFaceStatus::SelfIntersecting doc comment is reworded. No declaration, enumerator value, default argument, inline body or layout changes (MeshCadSurfaceOptions stays 48 bytes and MeshCadFaceRecord 112, as test_abi_layout.cpp pins), so MESHIOPLUSPLUS_ABI_VERSION stays 33. The C header changes the MIO_MESH_CAD_SELF_INTERSECTING comment only. |
| 33 | v17.13.0 | operations/mesh_cad.hpp, version.hpp | version.hpp is the routine release bump (macro values only, no declaration), as in every prior row. operations/mesh_cad.hpp is an entirely new header, which nothing existing includes: the kMeshCadFaceName, kMeshCadEdgeName and kMeshCadFaceRegionPrefix constexpr names, the scoped enum MeshCadFaceStatus (std::int32_t), the inline mesh_cad_face_status_name, the new structs MeshCadSurfaceOptions (48 bytes) and MeshCadFaceRecord (112 bytes), both pinned in test_abi_layout.cpp, the result MeshCadSurfaceResult (owning a Mesh, like every operation result) and the exported free functions mesh_cad_surface(const BrepInfo&, const MeshCadSurfaceOptions& = {}) and triangulate_polygon_2d. It changes no existing declaration, default argument, inline body, enumerator or layout (the pinned Brep* structs it reads are untouched), so MESHIOPLUSPLUS_ABI_VERSION stays 33. The C header's additions (mio_mesh_cad_surface_opts, 104 bytes, and mio_mesh_cad_surface_report, 200 bytes, with reserved tails, static-asserted in c_api.cpp) are new entry points only. |
| 29 | v17.1.0 | formats/gltf.hpp, version.hpp | Adds only the struct GltfReadOptions (one bool, pinned in test_abi_layout.cpp), the exported free-function declaration read_gltf(const std::string&, const GltfReadOptions& = {}, const ReadOptions& = {}), a new #include of read_options.hpp, and comment text. Existing structs, enums, signatures, default arguments and inline/template bodies are untouched. version.hpp is the routine release bump (macro values only: minor 0 → 1 and string "17.0.0" → "17.1.0"), as in every prior row. |
| 28 | v16.43.0 | operations/iga.hpp, formats/mfem.hpp, version.hpp | version.hpp is the routine release bump (macro values only, no declaration), as in every prior row. operations/iga.hpp is an entirely new header, which nothing existing includes: the kIgaPatchName and kIgaSpanName constexpr names, the new structs IgaRefineOptions, IgaSampleOptions and IgaEvaluation, and the exported free functions iga_insert_knots, iga_elevate_degree, iga_refine (two overloads), iga_evaluate (two overloads) and iga_sample (two overloads); the two option structs are pinned in test_abi_layout.cpp. formats/mfem.hpp gains only the exported free-function declaration sample_mfem_nurbs(const NurbsInfo&, NurbsInfo* = nullptr); no existing declaration, default argument, layout or inline body changes (NurbsInfo, NurbsPatch, BrepInfo and the other installed structs are untouched, which is what lets the layer sit beside Mesh without a layout change). The C API (mio_iga_opts, 96 bytes with a reserved tail, mio_iga_refine, mio_iga_sample, mio_iga_evaluate, mio_iga_evaluation_*) is new surface; the existing entry points and structs are unchanged. |
| 27 | v16.42.0 | operations/tessellate.hpp, version.hpp | An entirely new header, which nothing existing includes. It declares the kTessellate*Name constexpr names and kTessellateStencilWidth, the new structs TessellateOptions (an int64_t and three bools, 16 bytes, pinned in test_abi_layout.cpp) and TessellateResult (it embeds a Mesh and is not pinned), and the exported tessellate(const Mesh&, const TessellateOptions& = {}). No existing declaration, layout, default argument or inline body changes. version.hpp is the routine release bump (macro values only: minor 41 → 42 and string "16.41.0" → "16.42.0"), as in every prior row. |
| 27 | v16.42.0 | detail/hdf5_util.hpp | Adds only the exported free-function declarations verify_chunks(hid_t, const std::string&) and verify_chunk_rows(hid_t, const std::string&, std::size_t, std::size_t), with their doc comments. No existing declaration, layout, default argument or inline/template body changes. MESHIOPLUSPLUS_ABI_VERSION stays where it is. |
| 26 | v16.41.0 | operations/fit_cad.hpp, version.hpp | An entirely new header, which nothing existing includes and which names no OpenCASCADE type. It declares the kFitCadFaceName, kFitCadTypeName and kFitCadPatchName constexpr names, the FitCadOptions aggregate (32 bytes, align 8, pinned in test_abi_layout.cpp), the FitCadResult aggregate (embeds a Mesh, so not pinned, like FitPrimitivesResult) and the exported free functions fit_cad and fit_cad_has_occt. It includes operations/fit_primitives.hpp for kFitAllTypes, unchanged. Whether the core was built with OpenCASCADE changes only which body fit_cad has, never a declaration or a layout. The C API's mio_fit_cad_opts (80 bytes) and mio_fit_cad_report (192 bytes) are new structs with reserved tails, pinned by static_assert in c_api.cpp and by the Julia size checks. version.hpp is the routine release bump (macro values only: minor 40 → 41 and string "16.40.0" → "16.41.0"), as in every prior row. |
| 25 | v16.39.0 (unreleased skin to CAD) | operations/segment.hpp, operations/fit_primitives.hpp, formats/step.hpp | Three entirely new headers, which nothing existing includes. operations/segment.hpp declares the kSegmentPatchName and kSegmentAdjacencyName constexpr names, the SegmentOptions struct (96 bytes, pinned in test_abi_layout.cpp), the SegmentResult struct (embeds a Mesh, not pinned) and the exported segment(). operations/fit_primitives.hpp declares three constexpr names, the FitPrimitiveType enum, the kFitAllTypes constant, FitPrimitivesOptions (72 bytes, pinned), FitPrimitivesResult (embeds a Mesh) and the exported fit_primitives(). formats/step.hpp declares the exported write_step(). The private kernels (detail/surface_rings, detail/lsq_fit) live under src/cpp/src/detail/ and are not installed. No existing declaration, layout, default argument or inline body changes, so MESHIOPLUSPLUS_ABI_VERSION stays 25. |
| 25 | v16.39.0 (unreleased frd writer) | formats/frd.hpp | Adds only the exported free-function declaration write_frd(const std::string&, const Mesh&, bool LongIds = true), a new class FrdSeriesWriter whose only member is a std::unique_ptr to its implementation (8 bytes, pinned in test_abi_layout.cpp, every member function out-of-line; it includes <cstddef> and <memory>), and doc comments. The existing read_frd/read_frd_metadata declarations, FrdReadOptions and their default arguments are unchanged, and the writer's helpers live in an anonymous namespace in frd.cpp. No layout, enumerator, existing inline body or existing default argument changes, so MESHIOPLUSPLUS_ABI_VERSION stays 25. |
| 25 | v16.39.0 (unreleased frd binary writer) | formats/frd.hpp | Adds only the struct FrdWriteOptions (two bools, 2 bytes, pinned in test_abi_layout.cpp), the overload write_frd(const std::string&, const Mesh&, const FrdWriteOptions&) and the constructor FrdSeriesWriter(const std::string&, const FrdWriteOptions&). The existing bool overloads, their default arguments and the 8-byte pimpl layout of FrdSeriesWriter are unchanged. No ABI bump. |
| 25 | v16.39.0 (unreleased radioss_th writer) | detail/fortran_records.hpp, formats/radioss_th.hpp | Additive: fortran_records.hpp adds five out-of-line functions (fortran_append_record, fortran_put_int32, fortran_put_int64, fortran_put_float32, fortran_put_float64), one overload fortran_records(..., bool Lenient) and an <cstdint> include, leaving the four-argument form and its behaviour unchanged. radioss_th.hpp adds write_radioss_th and the class RadiossThSeriesWriter (a single std::unique_ptr, 8 bytes, pinned in test_abi_layout.cpp, every member out-of-line) and a <memory> include. No existing declaration, default argument, inline body or layout changes, so MESHIOPLUSPLUS_ABI_VERSION stays 25. |
| 25 | v16.39.0 (unreleased svg and tikz readers) | formats/svg.hpp, formats/tikz.hpp, read_options.hpp | Additive: svg.hpp adds Mesh read_svg(const std::string&, const ReadOptions& = {}) and tikz.hpp adds read_tikz likewise, each with an #include of read_options.hpp. read_options.hpp changes only a doc comment (mLenient is also strict=False for the two drawings); ReadOptions keeps its layout. The marker and the welding builder live in the core-private detail/drawing.hpp, which is not installed. No ABI bump. |
| 24 | v16.35.0 | operations/render.hpp, version.hpp | version.hpp is the routine release bump (macro values only, no declaration), as in every prior row. operations/render.hpp gains only declarations: the opaque RenderScene handle (a shared_ptr<const void>) and the free functions prepare_render and render_scene, the TextCell and TextGrid structs with encode_cells and encode_cells_update, and an #include <memory>. RenderOptions, Frame, TextOptions and SnapshotOptions are unchanged (their MIO_ABI_LAYOUT pins still hold), no existing declaration, default argument or inline/template body is touched, and render() keeps its signature (it now draws a prepared scene internally, out of line). The new structs are pinned in tests/cpp/test_abi_layout.cpp. |
| 23 | v16.33.0 | operations/render.hpp, detail/colormap.hpp, version.hpp | version.hpp is the routine release bump (macro values only, no declaration), as in every prior row. operations/render.hpp is an entirely new header: it declares the RenderProjection, RenderShading, RenderEdges, TextEncoding, ColorDepth and TextFormat enums, the RenderColor alias, the RenderOptions, Frame, TextOptions and SnapshotOptions structs, and the exported free functions render, render_text, encode_text, text_frame_size, encode_png, detect_color_depth, encode_cast and write_snapshot. Nothing existing includes it, and no existing declaration, layout, default argument or inline body changes; the four structs are pinned in tests/cpp/test_abi_layout.cpp from this release. detail/colormap.hpp changes its file comment only (it names the added colormaps and their licences): the Rgb struct and the three exported declarations are byte-identical, and the added maps are table data in colormap.cpp, not in the header. |
| 22 | v16.31.0 | version.hpp | Routine release macros only: minor 30 → 31 and string "16.30.0" → "16.31.0". No declaration, layout, default argument or existing inline/template body changes. The performance work of this release (dtype hoisting, per-thread scratch, reserved output, the GIL release and the core library lock) is out-of-line or in core-private detail/ headers, and the roadmap refactor is documentation only. |
| 22 | v16.30.0 | version.hpp | Routine release macros only: minor 29 → 30 and string "16.29.0" → "16.30.0". No declaration, layout, default argument or existing inline/template body changes. Reader robustness fixes are out-of-line; benchmark and fuzz infrastructure introduce no installed C++ header changes. |
| 22 | v16.29.0 | version.hpp | Routine release macros only: minor 28 → 29 and string "16.28.0" → "16.29.0". No declaration, layout, default argument or existing inline/template body changes. The d3plot fixes are out-of-line and use the existing detail/parse_guard.hpp unchanged; the already-reviewed core-parity changes below ship in this release with ABI 22. |
| 22 | v16.28.0 (unreleased pipeline reports) | operations/pipeline.hpp | Adds only the exported free-function declaration pipeline_report_json; existing report and pipeline structs, signatures, default arguments and inline bodies are unchanged. The C report handle and accessors are new symbols; existing C entry points and option layouts remain untouched. |
| 22 | v16.28.0 (unreleased MED parity) | formats/med.hpp | Adds only three exported free-function declarations (med_mesh_names, read_med_named, write_med_multi) and corrects comments. Existing declarations, default arguments, inline bodies and MedInfo layout are unchanged; all implementation changes are out-of-line. New C entry points leave existing option structs and symbols unchanged. |
| 22 | v16.28.0 (unreleased core-parity batch) | formats/vtp.hpp, formats/xdmf.hpp, write_options.hpp, detail/vtu_binary.hpp, detail/classic_stream.hpp, operations/data_manage.hpp | formats/vtp.hpp, formats/xdmf.hpp and write_options.hpp change comments only. detail/vtu_binary.hpp appends LZF without changing earlier enumerator values or the enum representation; WriteOptions is unchanged. detail/classic_stream.hpp adds a zero-argument output-stream factory without editing any existing inline body. operations/data_manage.hpp adds only two exported free-function declarations (sets_to_data / data_to_sets), leaving existing signatures, layouts and default arguments untouched. Reader/writer changes are out-of-line or private; the C glTF struct and entry points are new and existing C option layouts are unchanged. |
| 3 | v9.3.0 | formats/exodus.hpp | Adds one new inline constexpr const char* kExodusAttributePrefix. No existing declaration touched, ExodusInfo unchanged. A consumer compiled against v9.2.0 headers has an identical translation unit either way — it simply does not have the name. |
| 3 | v9.4.0 | abi_version.hpp, detail/abi_version_check.hpp, mesh.hpp | All new: the ABI machinery itself. mesh.hpp gains only an #include; no type's definition changes. See the note in doc/abi.md about the one-way incompatibility this introduction creates (v9.4.0 headers reference a sentinel a ≤v9.3.0 library does not define), which fails closed at link time. |
| 4 | v9.7.0 | formats/gmsh.hpp, version.hpp | version.hpp is the routine release bump (macro values only, no declaration). In formats/gmsh.hpp, all new: a GmshInfo struct (the MedInfo/ExodusInfo side-channel pattern) and two overloads that take it, read_gmsh(path, GmshInfo&, ReadOptions) and write_gmsh41(path, mesh, binary, const GmshInfo&). No existing declaration, default argument or type definition is touched, and neither existing function's mangled name changes — a consumer compiled against v9.6.0 headers links against exactly the same symbols. The one source-level (not ABI) consequence is that &read_gmsh and &write_gmsh41 are now ambiguous as bare function pointers, which is a compile error at the call site, never silent; registry.cpp wraps both in lambdas for that reason. |
| 4 | v9.8.0 | formats/cgns.hpp, version.hpp | version.hpp is the routine release bump (macro values only, no declaration), as in every prior row. formats/cgns.hpp's write_cgns(const std::string&, const Mesh&, int) and read_cgns(const std::string&) declarations are byte-identical to v9.7.0's — the CGNS rewrite (v9.8.0, a genuine CGNS/SIDS-compliant on-disk layout replacing the previous tetra-only encoding) is entirely confined to the .cpp implementation and the header's doc comment describing that on-disk layout. No declaration, default argument or type definition changed, so a consumer compiled against v9.7.0 headers links against exactly the same two symbols with exactly the same signatures; the only observable difference is that files written by the new library have a different (and, unlike before, actually-CGNS-compliant) byte layout, which is a file-format change, not an ABI one. |
| 5 | v9.10.0 | operations/gradient.hpp, detail/cell_adjacency.hpp, version.hpp | version.hpp is the routine release bump (macro values only, no declaration), as in every prior row. The other two are entirely new headers: operations/gradient.hpp declares the GradientOperator/GradientMethod enums, the GradientOptions/GradientResult aggregates, three MESHIOPLUSPLUS_API free functions and three inline constexpr const char* name constants; detail/cell_adjacency.hpp declares a CellIncidence aggregate and three MESHIOPLUSPLUS_API free functions. Nothing pre-existing is touched: no declaration is changed or removed, no default argument moves, no inline body is edited, and no existing type gains, loses or reorders a member. A consumer compiled against v9.9.0 headers therefore links against exactly the same symbols with exactly the same signatures and layouts — it simply does not have the new names. operations/partition.cpp was refactored onto cell_adjacency.hpp in the same release, but that is a .cpp and so out of scope here; operations/partition.hpp is byte-identical. |
| 5 | v9.11.0 | operations/pipeline.hpp, version.hpp | version.hpp is the routine release bump (macro values only, no declaration), as in every prior row. operations/pipeline.hpp is an entirely new header: it declares the PipelineValue alias, the PipelineStep/PipelineInput/PipelineOutput/Pipeline/PipelineStepReport/PipelineReport aggregates and thirteen MESHIOPLUSPLUS_API free functions (the typed engine, the JSON front-end and the option-spelling parsers). It defines no inline function bodies of its own beyond the implicit aggregate members, and nothing pre-existing is touched anywhere else in the installed tree: no declaration is changed or removed, no default argument moves, no inline body is edited, and no existing type gains, loses or reorders a member (ReadOptions/WriteOptions are consumed by value inside the new aggregates, not modified). A consumer compiled against v9.10.0 headers therefore links against exactly the same symbols with exactly the same signatures and layouts — it simply does not have the new names. The vendored nlohmann/json submodule is build-internal (pipeline.cpp only, PRIVATE include) and never reaches an installed header. |
| 5 | v9.13.0 | formats/mdpa.hpp, version.hpp | version.hpp is the routine release bump (macro values only, no declaration), as in every prior row. formats/mdpa.hpp's change is comment-only: the file-block description of Begin Nodes, the "Limitations" list and write_mdpa's doc comment are rewritten to say that arbitrary node ids are now read and that the writer still renumbers to 1..n. Every declaration is byte-identical — the three read_mdpa overloads, both write_mdpa overloads, MdpaInfo, MdpaEntityName and the MdpaProperties/MdpaProperty aliases — no member is added, moved, removed or reordered, no default argument moves, and the header defines no inline body to edit. A consumer compiled against v9.12.0 headers links against exactly the same symbols with exactly the same signatures and layouts; the only observable difference is which files the library will accept, which is a reader-behaviour change, not an ABI one. (The gate keys on paths, not content, which is why a comment-only header change still needs a row here.) |
| 5 | v9.12.0 | operations/sequence.hpp, version.hpp | version.hpp is the routine release bump (macro values only, no declaration), as in every prior row. operations/sequence.hpp is an entirely new header: it declares the SequenceTimeSource/SequenceTimeFrom/SequenceMode enums, the SequenceEntry/SequenceInput/SequenceOutput/SequencePipeline aggregates, one inline constexpr const char* name constant, and eighteen MESHIOPLUSPLUS_API free functions (the pure units, the capability queries, the streaming drivers and the JSON front-end -- the last four are declared here and defined in pipeline.cpp, which keeps the vendored nlohmann/json confined to that one TU and leaves operations/pipeline.hpp byte-identical). Nothing pre-existing is touched anywhere in the installed tree: no declaration is changed or removed, no default argument moves, no inline body is edited, and no existing type gains, loses or reorders a member. In particular Pipeline, PipelineInput, PipelineOutput and PipelineStep are untouched, which is exactly why the sequence types went into a new header rather than growing them: Pipeline embeds PipelineInput by value, so one added member would shift mSteps/mOutput under a consumer compiled against v9.11.0 headers -- a silent Tier A break. Those four types were unpinned in tests/cpp/test_abi_layout.cpp from v9.11.0 until this release, which is what made growing them look free; this release adds their MIO_ABI_LAYOUT lines alongside the four new sequence aggregates, so the same mistake now fails to compile. A consumer built against v9.11.0 headers links against exactly the same symbols with exactly the same signatures and layouts -- it simply does not have the new names. |
| 5 | v9.14.0 | formats/mdpa.hpp, version.hpp | version.hpp is the routine release bump (macro values only, no declaration), as in every prior row. formats/mdpa.hpp gains one new inline constexpr const char* kMdpaIdName = "mdpa:id"; (the kExodusAttributePrefix pattern) plus doc-comment updates to Begin Nodes/Begin Elements/write_mdpa describing the new preserve-on-write behaviour. No existing declaration is touched, removed or reordered: the three read_mdpa overloads, both write_mdpa overloads, MdpaInfo, MdpaEntityName and the MdpaProperties/MdpaProperty aliases are byte-identical to v9.13.0. A consumer compiled against v9.13.0 headers links against exactly the same symbols with exactly the same signatures and layouts — it simply does not have the new name, and the feature itself (the writer consulting point_data/cell_data["mdpa:id"] when present) is entirely a .cpp-side behaviour change reachable through unchanged function signatures. |
| 5 | v9.15.0 | version.hpp | version.hpp is the routine release bump (macro values only, no declaration), as in every prior row -- and it is the only installed header this release touches. The whole change (polyhedral connectivity across the flat C ABI: the mio_poly_conn snapshot, the mio_mesh_add_polygon_block / _polyhedron_block setters and mio_mesh_cell_block_info_ex) lives in bindings/c/, bindings/fortran/, bindings/julia/, bindings/r/ and bindings/wasm/, none of which the gate's src/cpp/include/meshioplusplus scope covers -- and none of which is under MESHIOPLUSPLUS_ABI_VERSION at all, the C API being a separate SOVERSION 0 + append-only-reserved contract (see doc/abi.md). No C++ declaration, type, inline body or default argument changed anywhere, so a consumer compiled against v9.14.0 headers links against exactly the same symbols with exactly the same signatures and layouts. |
| 5 | v9.16.0 | detail/polyhedron.hpp, version.hpp | version.hpp is the routine release bump (macro values only, no declaration), as in every prior row. detail/polyhedron.hpp is an entirely new header: it declares the CellRings and PolyMeasure aggregates, the RingOrientation enum, the FacetKey/FacetKeyHash pair and eight MESHIOPLUSPLUS_API free functions (cell_rings, orient_rings, poly_measure, the polygon_area_vector/polygon_area overload pairs, polygon_centroid, cell_volume_from_corners). Nothing pre-existing is touched anywhere in the installed tree: no declaration is changed or removed, no default argument moves, no inline body is edited, and no existing type gains, loses or reorders a member -- in particular detail/geometry.hpp and detail/cell_faces.hpp are byte-identical, which is exactly why the kernel went into a new header rather than growing either of them. A consumer compiled against v9.15.0 headers therefore links against exactly the same symbols with exactly the same signatures and layouts -- it simply does not have the new names. The release's behaviour change (the corner-average fan replacing the node-first fan in stats/cell_measure/clean, and the polyhedral paths in gradient/quality/surface/smooth) is entirely .cpp-side, reachable through unchanged signatures. |
| 5 | v9.17.0 | operations/convert_cells.hpp, detail/polyhedron.hpp, version.hpp | version.hpp is the routine release bump (macro values only, no declaration), as in every prior row. operations/convert_cells.hpp's change is comment-only: the file-level description of Simplexify and convert_cells' @throws clause are rewritten to say that a polyhedron block now decomposes into tetrahedra rather than throwing. Every declaration is byte-identical -- ConvertCellsMode, ConvertCellsOptions, ConvertCellsResult, convert_cells and convert_cells_mode_from_name -- no member is added, moved, removed or reordered, no default argument moves, and the header defines no inline body to edit. A consumer compiled against v9.16.0 headers links against exactly the same symbols with exactly the same signatures and layouts; the only observable difference is which meshes the operation accepts, which is a behaviour change, not an ABI one. (The gate keys on paths, not content, which is why a comment-only header change still needs a row here -- the v9.13.0 row is the precedent.) detail/polyhedron.hpp is named here only because it was introduced in v9.16.0 and the gate compares against the last tag: its own row above reviews it, and it is byte-identical between v9.16.0 and v9.17.0. |
| 5 | v9.18.0 | formats/cgns.hpp, detail/polyhedron.hpp, operations/convert_cells.hpp, version.hpp | version.hpp is the routine release bump. formats/cgns.hpp gains two new MESHIOPLUSPLUS_API declarations, cgns_has_cgnslib() and read_cgns_mll(), plus doc comments; write_cgns and read_cgns are byte-identical, so a consumer compiled against v9.17.0 headers links against exactly the same symbols with the same signatures -- it simply does not have the two new names. The optional MESHIOPLUSPLUS_HAS_CGNSLIB macro guards only the implementation in src/cpp/src/formats/cgns_mll.cpp; no installed header's content depends on it, so the header is identical whether or not a consumer's build had cgnslib, and cgnslib.h never reaches an installed header. detail/polyhedron.hpp and operations/convert_cells.hpp are named only because the gate compares against the last tag: their own rows above review them, and both are byte-identical since v9.16.0 and v9.17.0 respectively. |
| 5 | v9.19.0 | detail/vtk_cells.hpp, formats/cgns.hpp, detail/polyhedron.hpp, operations/convert_cells.hpp, version.hpp | version.hpp is the routine release bump. detail/vtk_cells.hpp gains one new overload of reconstruct_cells taking the VTU faces/faceoffsets arrays -- a distinct mangled symbol, with the four-argument form left byte-identical and still refusing VTK type 42, so an already-compiled consumer links against exactly what it did before. That the addition is an overload rather than a changed signature is the whole point: changing the existing one would have renamed its symbol, which is Tier A. The other three headers are named only because the gate compares against the last tag; their own rows above review them and all three are byte-identical since the releases that introduced them. Note the MED POE and EnSight nsided/nfaced writers in this release touched no installed header at all -- both are entirely .cpp-side, reachable through unchanged signatures. |
| 6 | v9.21.0 | detail/face_mesh.hpp, formats/cgns.hpp, version.hpp | version.hpp is the routine release bump. detail/face_mesh.hpp gains one new overload of build_global_faces taking a const std::vector<std::size_t>& block filter — a distinct mangled symbol, with the one-argument form's declaration byte-identical, so an already-compiled consumer links against exactly what it did before. That it is an overload rather than a new defaulted parameter is the whole point: a default argument would have changed the existing function's signature and therefore its mangled name, which is Tier A. formats/cgns.hpp's change is comment-only (the file-level description now says NGON_n/NFACE_n are read and written by the hand-rolled path, not only by cgnslib); write_cgns, read_cgns, read_cgns_mll and cgns_has_cgnslib are byte-identical, no member moves and the header defines no inline body to edit. The gate keys on paths rather than content, which is why a comment-only header change still needs naming here — the v9.13.0 row is the precedent. A consumer compiled against v9.20.0 headers links against exactly the same symbols with the same signatures and layouts; it simply does not have the new overload. |
| 6 | v9.23.0 | operations/refine.hpp, version.hpp | version.hpp is the routine release bump (macro values only, no declaration), as in every prior row. operations/refine.hpp gains one new inline constexpr const char* kRefineEntityName = "refine:entity"; (the kExodusAttributePrefix/kMdpaIdName pattern) plus doc-comment updates to kRefineHangingName and the new constant. No existing declaration is touched, removed or reordered: RefineOptions, RefineResult, RefineClosure, RefineCompare and the refine declaration are byte-identical to v9.22.0, no member is added, moved or reordered, no default argument moves, and the header defines no inline body to edit. A consumer compiled against v9.22.0 headers links against exactly the same symbols with exactly the same signatures and layouts — it simply does not have the new name. The release's behaviour changes (a later balanced pass reusing an existing entity node instead of allocating a coincident duplicate, and the hanging rule being evaluated over the emitted cells rather than the input cells' entities) are entirely .cpp-side, reachable through unchanged signatures, and confined to RefineClosure::Balanced — the conforming closures and uniform refinement produce byte-identical output to v9.22.0. |
| 6 | v9.24.0 | operations/refine.hpp, detail/grid_lattice.hpp, detail/point_triangle.hpp, detail/surface_distance.hpp, detail/tri_box.hpp, operations/sdf.hpp, operations/voxelize.hpp, version.hpp | version.hpp is the routine release bump (macro values only, no declaration), as in every prior row. The other six are entirely new headers: detail/grid_lattice.hpp declares the LatticeSpec aggregate and five MESHIOPLUSPLUS_API free functions; detail/point_triangle.hpp and detail/tri_box.hpp are header-only inline (a TriangleFeature enum, a PointTriangleHit aggregate and two inline functions between them, none exported); detail/surface_distance.hpp declares the TriangleSoup/DistanceQuery/DistanceHit aggregates, the SurfaceEdgeKey alias and its hash, and four MESHIOPLUSPLUS_API free functions; operations/sdf.hpp declares five enums, eleven inline constexpr const char* name constants, the SurfaceQuality/SurfaceDistanceOptions/SurfaceDistanceResult/SdfOptions/SdfResult aggregates and eight MESHIOPLUSPLUS_API free functions; operations/voxelize.hpp declares the VoxelFill enum, one name constant, the VoxelOptions/VoxelResult aggregates and three MESHIOPLUSPLUS_API free functions. Nothing pre-existing is touched anywhere in the installed tree: no declaration is changed or removed, no default argument moves, no inline body is edited, and no existing type gains, loses or reorders a member. A consumer compiled against v9.23.0 headers therefore links against exactly the same symbols with exactly the same signatures and layouts -- it simply does not have the new names. Two things were done up front rather than after the fact, both learning from the v9.12.0 row above: SdfOptions and VoxelOptions embed SurfaceDistanceOptions by value, so operations/sdf.hpp ships the octree fields populated-but-reserved (growing the inner struct later would shift both outer structs' tails, a silent Tier A break), and all four option/quality aggregates plus LatticeSpec are pinned in tests/cpp/test_abi_layout.cpp from this release rather than from the one after the mistake. The C ABI's own new structs (mio_sdf_opts, mio_voxel_opts, mio_surface_quality) live in bindings/c/, which this gate's src/cpp/include/meshioplusplus scope does not cover and which is a separate SOVERSION 0 + append-only-reserved contract; their sizes are static_asserted in c_api.cpp and mirrored by the Fortran and Julia layout guards. operations/refine.hpp is listed here only because the gate diffs against the last tag and v9.23.0 was never tagged, so that release's one added inline constexpr const char* kRefineEntityName is still in the window; it is reviewed on its own row above and nothing further changed in it. |
| 6 | v9.25.0 | formats/vti.hpp, operations/crop.hpp, operations/refine.hpp, detail/grid_lattice.hpp, detail/point_triangle.hpp, detail/surface_distance.hpp, detail/tri_box.hpp, operations/sdf.hpp, operations/sequence.hpp, operations/voxelize.hpp, version.hpp | version.hpp is the routine release bump (macro values only, no declaration), as in every prior row. formats/vti.hpp is an entirely new header: four MESHIOPLUSPLUS_API free functions (write_vti, write_vti_codec, read_vti, read_vti_metadata), no types, no inline bodies. detail/grid_lattice.hpp gains one new aggregate (LatticeRequest) and two new MESHIOPLUSPLUS_API free functions (lattice_resolve, lattice_from_mesh); LatticeSpec and the five pre-existing functions are byte-identical, so an already-compiled consumer links against exactly what it did before. operations/crop.hpp gains one new MESHIOPLUSPLUS_API free function, crop_predicate — a new declaration, not a defaulted parameter on an existing one, so crop_bbox/crop_halfspace/CropMode/CropResult keep their exact signatures and layouts; the header also gains an #include of operations/refine.hpp (for RefineCompare), which adds a name to the translation unit and changes no definition. operations/refine.hpp gains one new MESHIOPLUSPLUS_API bool refine_compare_value(double, RefineCompare, double) declaration; its definition moved out of refine.cpp's anonymous namespace, which is a .cpp change and adds a symbol rather than altering one — RefineOptions, RefineResult, RefineClosure, RefineCompare, refine, refine_closure_from_name and refine_compare_from_name are byte-identical. operations/sdf.hpp is the one to read carefully and it is still Tier C: its change is doc-comment only plus one enumerator's comment. SdfStructure::Octree, SdfOptions::mRootResolution/mMaxDepth/mBandCells/mRecordLevels and the compute_sdf declaration all existed verbatim in v9.24.0 — shipped populated-but-reserved precisely so that implementing them would be a pure .cpp change, which is what this release did. No member is added, moved, removed or reordered in any of the five aggregates, no enumerator value changes, no default argument moves, and no inline body is edited. MIO_ABI_LAYOUT in tests/cpp/test_abi_layout.cpp therefore needed no new line for any of them. A consumer compiled against v9.24.0 headers links against exactly the same symbols with exactly the same signatures and layouts; it simply does not have read_vti/write_vti/crop_predicate/lattice_resolve/lattice_from_mesh/refine_compare_value, and compute_sdf — whose symbol it already had — now returns rather than throwing. |
| 6 | v9.27.0 | version.hpp | version.hpp is the routine release bump (macro values only, no declaration), as in every prior row -- and it is the only installed header this window touches (v9.25.0..v9.27.0, since neither v9.26.0 nor v9.27.0 was tagged, so the gate diffs the whole span at once). Both releases in the span (to_pandas/to_polars in v9.26.0; edge_index/feature_matrix/write_dataset/to_torch/to_jax closing the roadmap's ML section in v9.27.0) are pure Python over existing machinery — src/python/meshioplusplus/_ml.py, _gpu.py's new to_torch/to_jax, _interop.py's to_pandas/to_polars/_frame_columns — and touch no C++ source, no binding, no installed header at all. A consumer compiled against v9.25.0 headers links against exactly the same symbols with exactly the same signatures and layouts. |
| 6 | v9.30.0 | version.hpp | version.hpp is the routine release bump (macro values only, no declaration), as in every prior row -- and it is the only installed header this window touches (v9.27.0..v9.30.0, since neither v9.28.0 nor v9.29.0 was tagged, so the gate diffs the whole span at once). All three releases in the span close the roadmap's PhysicsNeMo section: v9.28.0 (the meshioplusplus.physicsnemo adapter and DatasetManifest), v9.29.0 (the browser dataset-manager page) and v9.30.0 (t->t+1 target pairing, the gated physicsnemo.mesh.Mesh bridge, persisted directory handles and per-entry quality summaries in that UI). Every one of them is pure Python (src/python/meshioplusplus/physicsnemo/, _dataset.py, the dataset CLI group, three MCP tools) or TypeScript (src/viewer/src/dataset/, src/viewer/src/worker/*, calling only the already-bound attachQuality/sequenceEntries/timeseriesToSequence/readMeshSelective) over existing machinery, and none of it touches C++ source, a binding, or any other installed header. A consumer compiled against v9.27.0 headers links against exactly the same symbols with exactly the same signatures and layouts. |
| 6 | v10.0.0 | version.hpp | version.hpp is the routine release bump (macro values only, no declaration), as in every prior row -- and it is again the only installed header this window touches (still v9.27.0..HEAD, since v9.28.0/v9.29.0/v9.30.0 were never tagged either, so the gate keeps diffing the same span it did for the row above). This release is a pure version-number bump: MESHIOPLUSPLUS_VERSION_MAJOR 9 -> 10, MINOR/PATCH reset to 0/0, no other line in version.hpp or anywhere else in the installed tree changed. The functional content of the span (v9.28.0-v9.30.0's PhysicsNeMo work) is already reviewed on the v9.30.0 row directly above; this row exists only because the release-version token the gate matches against moved from 9.30.0 to 10.0.0, so that row's exact-token match no longer applies and a fresh one is required. A consumer compiled against v9.30.0 headers links against exactly the same symbols with exactly the same signatures and layouts -- the major version number is not itself part of any symbol's mangling or any type's layout. |
| 7 | v10.9.0 | detail/data_ops.hpp, detail/spatial_hash.hpp, operations/conservative_interpolate.hpp, operations/data_integrate.hpp, operations/hessian.hpp, version.hpp | version.hpp is the routine release bump (macro values only, no declaration), as in every prior row -- and this row covers the whole span since the last tag, v10.6.0..HEAD, since neither v10.7.0 nor v10.8.0 was tagged, so the gate diffs all three releases (conservative interpolation, field integration and the Hessian operation) at once. operations/conservative_interpolate.hpp, operations/data_integrate.hpp and operations/hessian.hpp are entirely new headers: conservative_interpolate.hpp declares the ConservativeInterpolateConflict enum, its _from_name parser, the ConservativeInterpolateOptions aggregate and conservative_interpolate(); data_integrate.hpp declares the FieldIntegralRegion/FieldIntegralArray/DataIntegrateReport/DataIntegrateOptions aggregates and data_integrate(); hessian.hpp declares one inline constexpr const char* kHessianSuffix, the HessianOptions/HessianResult aggregates and hessian() (itself implemented as two internal calls to the pre-existing gradient(), so it adds no new dependency on operations/gradient.hpp's declarations, which are byte-identical). detail/data_ops.hpp gains one new aggregate (WeightedSum, with inline Add/Merge/Mean members -- data_integrate's per-component reducer) and one new MESHIOPLUSPLUS_API free function, accumulate_weighted; every pre-existing declaration in the header (FiniteStats, accumulate_stats, combine_components, cell_measure, ...) is byte-identical. detail/spatial_hash.hpp gains one new template member function, SpatialGrid::ForEachInBox (the read-side twin of the pre-existing InsertBox, added for conservative_interpolate.cpp's bucket-grid overlap queries), plus a doc-comment addition describing it; GridKey, GridKeyHash, grid_quantize, Find, InsertBox, ForEachIn27 and ForEachInShell are byte-identical. Nothing pre-existing is touched anywhere in the installed tree: no declaration is changed or removed, no default argument moves, no existing inline body is edited, and no existing type gains, loses or reorders a member. A consumer compiled against v10.6.0 headers therefore links against exactly the same symbols with exactly the same signatures and layouts -- it simply does not have the new names. All three operations are documented as C++-core-only or Python-fallback-only in doc/conservative_interpolate.md/doc/field_integration.md/doc/hessian.md, and none is under any MESHIOPLUSPLUS_ABI_VERSION-relevant discrete-branch risk in an installed header -- the geometric-clip and winding-repair logic the release notes describe lives entirely in the corresponding .cpp files. |
| 7 | v10.10.0 | operations/remesh.hpp, detail/decimate_common.hpp, version.hpp | version.hpp is the routine release bump (macro values only, no declaration), as in every prior row. operations/remesh.hpp is an entirely new header: it declares the RemeshMetric enum, its _from_name parser, the RemeshOptions/RemeshResult aggregates and two MESHIOPLUSPLUS_API free functions (remesh, remesh_suggest_subdivide). detail/decimate_common.hpp gains one new MESHIOPLUSPLUS_API free function, decim_quadric_optimal_point(const double q[10], const double pFallback[3], double pOut[3]) -- the cofactor-solve-with-fallback logic hoisted out of decim_place's Optimal branch so remesh's quadric-metric cluster placement can share it. decim_place's own declaration is byte-identical (same three parameters, same DecimPlaced return type); only its definition in decimate_common.cpp changed to call the new function instead of inlining the solve, which is a .cpp-only change and does not touch this header at all. Nothing else pre-existing in either header is touched: no declaration is changed or removed, no default argument moves, no existing inline body is edited, and no existing type (DecimFaces, DecimCsr, DecimPlaced, DecimPlaceCtx) gains, loses or reorders a member. A consumer compiled against v10.9.0 headers therefore links against exactly the same symbols with exactly the same signatures and layouts -- it simply does not have remesh/remesh_suggest_subdivide/decim_quadric_optimal_point. The hoist's behaviour-preservation for decimate/decimate_volume (both consumers of decim_place) is verified by their full existing gtest suites, run unmodified both before and after -- the decimate_volume/v10.6.0 hoist precedent for this same file. |
| 10 | v10.15.0 | detail/provenance.hpp, version.hpp | version.hpp is the routine release bump (macro values only, no declaration), as in every prior row. detail/provenance.hpp is an entirely new header: it declares one inline constexpr const char* kProvenanceTag, built at compile time from version.hpp's MESHIOPLUSPLUS_VERSION_STRING (the canonical one-line credit every format writer now emits, replacing the ad hoc per-writer strings that had drifted between the C++ core and its Python twins). No existing declaration, aggregate, enumerator or inline body anywhere in the installed tree is touched. A consumer compiled against v10.14.0 headers therefore links against exactly the same symbols with exactly the same signatures and layouts -- it simply does not have the new name. |
| 10 | v10.16.0 | detail/provenance.hpp, version.hpp | version.hpp is the routine release bump (macro values only, no declaration), as in every prior row. detail/provenance.hpp grows from v10.15.0's single kProvenanceTag constant into the full opt-in record: two new enums (ProvenanceMode, SlotTier), two new aggregates (ProvenanceNote, ProvenanceRecord), one new RAII class (ProvenanceScope), and ten new MESHIOPLUSPLUS_API free functions (current_provenance_mode, current_provenance, provenance_note, provenance_set_source, provenance_set_target, provenance_add_operation, provenance_lines, provenance_render_lines, provenance_render_xml_comment, provenance_timestamp). kProvenanceTag itself is byte-identical to v10.15.0 -- same declaration, same value, same position in the file. No existing declaration, aggregate, enumerator or inline body anywhere in the installed tree is touched, and no existing type gains, loses or reorders a member. A consumer compiled against v10.15.0 headers therefore links against exactly the same symbols with exactly the same signatures and layouts -- it simply does not have the new names. The runtime mechanism this header declares (a thread-local scope stack) lives entirely in the new src/cpp/src/detail/provenance.cpp, a .cpp file and therefore outside this gate's src/cpp/include/meshioplusplus scope regardless. |
Five further headers are named above only because the gate diffs against the last tag (v9.22.0) and neither v9.23.0 nor v9.24.0 was tagged, so their changes are still in the window. detail/point_triangle.hpp, detail/surface_distance.hpp, detail/tri_box.hpp and operations/voxelize.hpp are v9.24.0's entirely-new headers and are reviewed on that release's row above; nothing in them changed here beyond one comment in operations/voxelize.hpp (a "41 format tables" count becoming 42). operations/sequence.hpp's change in this release is likewise comment-only — the same format count in its file-level doc block — with every declaration, aggregate and enumerator byte-identical; the gate keys on paths rather than content, which is why it still needs naming (the v9.13.0 row is the precedent). The C ABI's own new struct (mio_compute_sdf_opts) and two new entry points live in bindings/c/, outside this gate's src/cpp/include/meshioplusplus scope and under the separate SOVERSION 0 + append-only-reserved contract; sizeof(mio_compute_sdf_opts) is static_asserted in c_api.cpp at 232 and mirrored by the Fortran and Julia layout guards. |
| 11 | v10.18.0 | formats/gid.hpp, version.hpp | version.hpp is the routine release bump (macro values only, no declaration), as in every prior row. formats/gid.hpp is an entirely new header: it declares the GidMode enum, three MESHIOPLUSPLUS_API free functions (gid_mode_from_name, gid_available, gid_build_option) and one MESHIOPLUSPLUS_API writer (write_gid), backing the new write-only gid format (GiD postprocess, on a vendored gidpost 2.14). No existing declaration, aggregate, enumerator or inline body anywhere in the installed tree is touched, and no existing type gains, loses or reorders a member. A consumer compiled against v10.17.0 headers therefore links against exactly the same symbols with exactly the same signatures and layouts -- it simply does not have the new names. The vendored gidpost C sources (src/cpp/third_party/gidpost/) are build-internal (formats/gid.cpp only, PRIVATE include dir, mirroring the pugixml/nlohmann-json precedent) and never reach an installed header. |
| 11 | v10.19.0 | formats/gid.hpp, version.hpp | version.hpp is the routine release bump (macro values only, no declaration), as in every prior row. formats/gid.hpp gains three new MESHIOPLUSPLUS_API declarations for the GiD reader -- read_gid, read_gid_metadata and gid_readable -- plus a new #include of read_options.hpp (for the ReadOptions/MeshMetadata those signatures name). Every pre-existing declaration is untouched: the GidMode enum has the same four enumerators with the same values, and gid_mode_from_name/gid_available/gid_build_option/write_gid keep their exact signatures and default arguments -- in particular gid_available deliberately keeps its v10.18.0 meaning (write capability) rather than being redefined, with gid_readable added as the read-side twin, precisely so an already-compiled consumer's behaviour cannot change. No aggregate gains, loses or reorders a member. A consumer compiled against v10.18.0 headers therefore links against exactly the same symbols with exactly the same signatures and layouts -- it simply does not have the three new names. The reader's own translation units (src/cpp/src/formats/gid_read.cpp and the format-private src/cpp/src/formats/gid_common.hpp) live outside src/cpp/include/meshioplusplus/ and so are outside this gate's scope entirely. Same release, additionally: gid.hpp gains a new enum class GidResultType (nine enumerators, std::int64_t underlying type -- deliberately meshio++'s own rather than a reuse of gidpost's GiD_ResultType, since this header must stay free of gidpost, which the reader is built without), one inline constexpr const char* (kGidResultTypePrefix), and three further MESHIOPLUSPLUS_API declarations (gid_result_type_name, gid_result_type_from_name, gid_result_dim_is_legal). All additive: no existing declaration, enumerator or aggregate is touched, and the new enum's values are static_asserted against gidpost's GiD_ResultType in gid.cpp (a compile-time check, not a runtime one, so drift is caught in this repo's own build rather than becoming an ABI concern). A consumer compiled against an earlier v10.19.0 snapshot of this header still links against exactly the same symbols with exactly the same signatures -- it simply does not have the four new names. Same release, additionally: gid.hpp gains two further inline constexpr const char* constants (kGidGaussPointsPrefix, kGidGaussCoordsPrefix) backing arbitrary Gauss-point-per-element support. Both are additive compile-time constants with no linkage of their own; no existing declaration, enumerator or aggregate is touched, and the Gauss-point machinery itself lives entirely in the non-installed src/cpp/src/formats/gid_common.hpp and the two format .cpp files, outside this gate's scope. A consumer compiled against an earlier v10.19.0 snapshot links against exactly the same symbols with the same signatures and layouts. Same release, additionally: GidMode gains an appended enumerator AsciiZipped = 4. The enum already declares an explicit : int underlying type, so its size and the values of every pre-existing enumerator are unchanged; appending is Tier C additive under doc/abi.md's own rule. No aggregate, signature or inline body is touched, and a consumer compiled against an earlier snapshot behaves identically — it simply never names the new mode. Same release, additionally: gid.hpp gains one further MESHIOPLUSPLUS_API free function (write_gid_series, the multi-step writer) plus an #include <functional> for the provider type it names. Purely additive -- deliberately a free function rather than a stateful class, so no new aggregate exists to have a layout at all, and no existing declaration, enumerator or inline body is touched. A consumer compiled against an earlier snapshot links against the same symbols with the same signatures. |
| 11 | v10.20.0 | formats/gid.hpp, version.hpp | version.hpp is the routine release bump (macro values only, no declaration), as in every prior row. formats/gid.hpp itself is untouched by this release -- it changed earlier in the same v10.17.0..HEAD span (the v10.18.0 and v10.19.0 rows above already review every one of those changes in full: the new header, the reader declarations, GidResultType, the Gauss-point constants, AsciiZipped, write_gid_series), and is named here only because this gate's base is still the last real tag (v10.17.0 -- neither v10.18.0, v10.19.0 nor this release has been tagged), so the diff span keeps accumulating and this release's row must account for the whole span, not just what it itself changed. This release's own work -- a new MESHIOPLUSPLUS_ZLIB_STATIC CMake option that vendors a pinned, FetchContent-fetched static zlib instead of find_package(ZLIB), and the cli.yml/wheels.yml flag flips that consume it so the release CLI binaries and every published wheel gain gid write support -- lives entirely in CMakeLists.txt and the two GitHub Actions workflow files: build/CI configuration, not C++ source, touching no header, binding or declaration anywhere. No existing type, enumerator, default argument or inline body changed in this release. A consumer compiled against v10.19.0 headers links against exactly the same symbols with exactly the same signatures and layouts. |
| 11 | v10.20.1 | version.hpp | version.hpp is the routine release bump (macro values only, no declaration), as in every prior row -- and it is the only installed header this release touches (v10.20.0 was tagged, so the gate's base moved and formats/gid.hpp drops out of the diff). The two fixes it ships -- the Windows CLI's zlibstatic target not inheriting MESHIOPLUSPLUS_STATIC_RUNTIME's /MT CRT setting, and a WASM provenance leak (writeMesh/convert/convertSurface/convertSurfaceOps not resetting the scope-less provenance record before writing) -- live entirely in CMakeLists.txt and bindings/wasm/js_bindings.cpp, neither of which is under src/cpp/include/meshioplusplus. A consumer compiled against v10.20.0 headers links against exactly the same symbols with exactly the same signatures and layouts. |
| 11 | v10.20.2 | version.hpp | version.hpp is the routine release bump (macro values only, no declaration), as in every prior row -- and, again, the only installed header this release touches. This release carries no code change at all: v10.20.1's tag push was lost to a GitHub Actions outage (the wasm/wheels/ci workflows never started a run for it, and packages's jobs all came back cancelled), so v10.20.2 simply re-cuts the identical tree under a new tag so the release workflows get a clean run. A consumer compiled against v10.20.1 headers links against exactly the same symbols with exactly the same signatures and layouts. | | 11 | v10.21.0 | version.hpp | version.hpp is the routine release bump (macro values only, no declaration), as in every prior row -- and, again, the only installed header this release touches. This release adds a Blender add-on: a new pure-Python module src/python/meshioplusplus/_blender.py, a new public meshioplusplus.formats() in _helpers.py, a backward-compatible qualifier= keyword on the private _gpu._require_framework, and a Blender 4.2+ extension under src/blender/ with its build script and CI jobs. Every one of those is Python, packaging or CI: nothing under src/cpp/include/meshioplusplus other than the version macros changed, no binding was touched, and no C++ declaration, type, enumerator, default argument or inline body changed anywhere. A consumer compiled against v10.20.2 headers links against exactly the same symbols with exactly the same signatures and layouts. | | 11 | v10.21.1 | version.hpp | version.hpp is the routine release bump (macro values only, no declaration), as in every prior row -- and, again, the only installed header this release touches. This release is documentation and tooling only: a generated SVG/PNG diagram pipeline under doc/diagrams/, a rewritten doc/roadmap.md, a new doc/architecture.md overview page, sidebar regrouping and several stale-count/broken-link fixes. Nothing under src/cpp/include/meshioplusplus other than the version macros changed, no binding was touched, and no C++ declaration, type, enumerator, default argument or inline body changed anywhere. A consumer compiled against v10.21.0 headers links against exactly the same symbols with exactly the same signatures and layouts. | | 11 | v10.36.0 | formats/flac3d.hpp, version.hpp | version.hpp is the routine release bump (macro values only, no declaration), as in every prior row. formats/flac3d.hpp is comment-only: read_flac3d(const std::string&) and write_flac3d(const std::string&, const Mesh&, const std::string&, bool) are byte-identical to v10.35.0's, with the same default arguments and the same mangled names, and the file declares no type, enum or constant at all. Only the Doxygen block changed -- the reader no longer throws on a ZGROUP/FGROUP section and the writer now emits one, so the @throws and @note paragraphs describing the old deferral (and their factually wrong claim that cell_sets is not carried by the Mesh conversion layer, contradicted by bindings/python/np_conversions.hpp since v8.1.0) had to go. All of this release's actual work -- group parsing and emission, the separate zone/face id namespaces, the region naming rule -- lives in src/cpp/src/formats/flac3d.cpp, outside this gate's src/cpp/include/meshioplusplus scope. A consumer compiled against v10.35.0 headers links against exactly the same symbols with exactly the same signatures and layouts; only the bytes those functions read and write changed, which is a file-format change and not an ABI one (the v9.8.0 CGNS row is the precedent). |
| 12 | v10.37.0 | operations/curvature.hpp, detail/surface_distance.hpp, version.hpp | version.hpp is the routine release bump (macro values only, no declaration), as in every prior row. operations/curvature.hpp is an entirely new header: it declares the CurvatureDualArea enum, two MESHIOPLUSPLUS_API name-parser free functions (curvature_dual_area_from_name, curvature_dual_area_name), four inline constexpr const char* point-data array-name constants, the CurvatureOptions/CurvatureResult aggregates, and compute_curvature(). No pre-existing declaration, aggregate, enumerator or inline body anywhere in the installed tree is touched. detail/surface_distance.hpp was already reviewed on this same span by the ABI-12 bump's own history (it added SurfaceEdgeRecord/SurfaceEdgeMap/build_surface_edges and moved soup_quality's declaration a few lines down the file with a byte-identical signature and hence a byte-identical mangled name -- declaration order within a header is not ABI) and is named here only because it is still within the diffed window; nothing in it changed again in this release. CurvatureOptions is newly pinned in tests/cpp/test_abi_layout.cpp from this release (MIO_ABI_LAYOUT(meshioplusplus::CurvatureOptions, 40, 8)), the RefineOptions/RemeshOptions/OptimizeVolumeOptions "pin in advance" lesson. A consumer compiled against v10.36.0 headers links against exactly the same symbols with exactly the same signatures and layouts -- it simply does not have the new names. | | 12 | v10.38.0 | operations/repair.hpp, operations/shrinkwrap.hpp, operations/sobolev_deform.hpp, detail/surface_distance.hpp, version.hpp | version.hpp is the routine release bump (macro values only, no declaration), as in every prior row. The three operations/*.hpp are entirely new headers: each declares its own options/result aggregates, its array-name constants and one MESHIOPLUSPLUS_API free function (repair, shrinkwrap, sobolev_deform). No pre-existing declaration, aggregate, enumerator or inline body anywhere in the installed tree is touched by them. detail/surface_distance.hpp is purely additive: one new aggregate (SurfaceProjection) and one new exported function (query_surface_projections), plus a #include of the already-installed detail/point_triangle.hpp (needed for TriangleFeature) and a comment reworded on TriangleSoup::mVertices. ClosestPointHit, DistanceHit, DistanceQuery, TriangleSoup, SurfaceEdgeRecord and every existing function signature are byte-identical, so their mangled names and layouts are unchanged; the sd_feature_normal hoist that query_surface_projections shares with query_distances is entirely inside surface_distance.cpp's anonymous namespace and is not installed at all. RepairOptions, ShrinkwrapOptions and SobolevOptions are pinned in tests/cpp/test_abi_layout.cpp from this release (24/8, 96/8, 112/8), the RefineOptions/RemeshOptions/CurvatureOptions "pin in advance" lesson; every *Result stays unpinned, embedding a Mesh. A consumer compiled against v10.37.0 headers links against exactly the same symbols with exactly the same signatures and layouts -- it simply does not have the new names. | | 12 | v11.0.0 | detail/cell_faces.hpp, version.hpp | Both changes are comment-only, made while retargeting doc cross-references from the retired CLAUDE.md to AGENTS.md. detail/cell_faces.hpp's wedge15 doc comment now points at formats/ensight.cpp instead of CLAUDE.md for the penta15 involution warning; version.hpp's "Version bumps" note now points at AGENTS.md. Neither header's declarations are touched: CellFaceDef, MESHIOPLUSPLUS_API const std::vector<CellFaceDef>& cell_faces(CellType) and the inline skin_supported(CellType) are byte-identical to v10.38.0, and version.hpp's macros are unchanged beyond the routine 11.0.0 release bump already covered by the "routine release bump" note in every prior row. A consumer compiled against v10.38.0 headers links against exactly the same symbols with exactly the same signatures and layouts; the only observable difference is where a doc comment tells a reader to look, which is a repo-hygiene change, not an ABI one. (The gate keys on paths, not content, which is why a comment-only header change still needs a row here -- the v9.13.0 row is the precedent.) | | 12 | v11.1.0 | detail/cell_faces.hpp, formats/gid.hpp, operations/agglomerate.hpp, version.hpp | version.hpp is the routine release bump (macro values only, no declaration), as in every prior row. detail/cell_faces.hpp carries no new change here: its one-line comment fix (the wedge15 doc comment pointing at formats/ensight.cpp instead of the retired CLAUDE.md) was already reviewed by the v11.0.0 row above, but landed on master in a commit made after the v11.0.0 git tag was cut, so the gate sees it as changed since that tag and it has to be named again here -- same one-line comment, same conclusion: CellFaceDef, cell_faces(CellType) and skin_supported(CellType) are untouched. formats/gid.hpp's doc comment now lists hexahedron27/wedge15/pyramid13 alongside their base types instead of separately flagging them "not yet verified" (true again since v10.19.0's Kratos-derived orderings); no declaration in the file changed. operations/agglomerate.hpp's doc comment now points its "see the roadmap" cross-reference at the specific doc/roadmap.md section instead of the page as a whole; AgglomerateOptions, AgglomerateResult and agglomerate(...) are untouched. Everything else in the release is Python/C++ tests and doc/ (issue #76's mesh.cell_sets-vs-mesh.regions clarification, plus the roadmap restructuring that prompted the two comment fixes above), neither of which is installed. A consumer compiled against v11.0.0 headers links against exactly the same symbols with exactly the same signatures and layouts. | | 12 | v11.2.0 | detail/cell_faces.hpp, formats/gid.hpp, operations/agglomerate.hpp, version.hpp | Same three comment-only headers as the v11.1.0 row above, named again only because the gate's base is still the v11.0.0 tag (neither v11.1.0 nor this release has been tagged) and none of them changed again since that row reviewed them: detail/cell_faces.hpp's wedge15 doc-comment fix, formats/gid.hpp's "not yet verified" wording removal and operations/agglomerate.hpp's roadmap cross-reference are byte-identical to v11.1.0, and CellFaceDef/cell_faces(CellType)/skin_supported(CellType), GidMode/write_gid/read_gid/etc. and AgglomerateOptions/AgglomerateResult/agglomerate(...) remain untouched. version.hpp is the routine release bump (macro values only, no declaration), as in every prior row. This release's actual work -- Tier A of roadmap §1 "WASM parity" (a WASM loader-error type, integer-dtype carry across the embind boundary, index maps, per-format side channels, write options, written-paths reporting, a stateful sequence reader, and a frozen pin mask added to bindings/c/, bindings/fortran/, the Julia and R bindings) -- touches bindings/wasm/, bindings/c/, bindings/fortran/, bindings/julia/, bindings/r/, tests and doc/, none of which is under src/cpp/include/meshioplusplus. A consumer compiled against v11.1.0 headers links against exactly the same symbols with exactly the same signatures and layouts. | | 12 | v11.3.0 | detail/cell_faces.hpp, formats/cgns.hpp, formats/ensight.hpp, formats/gid.hpp, formats/med.hpp, formats/tecplot.hpp, operations/agglomerate.hpp, operations/sequence.hpp, version.hpp | detail/cell_faces.hpp, formats/gid.hpp and operations/agglomerate.hpp carry no new change: the same three comment-only fixes the v11.1.0/v11.2.0 rows already reviewed, named again only because the gate's base is still the v11.0.0 tag. version.hpp is the routine release bump. The remaining four headers are this release's actual work -- roadmap §1 tier B1 (in-file timelines) -- and every change to them is purely additive: formats/med.hpp gains one new MESHIOPLUSPLUS_API free function, read_med_metadata(const std::string&, const ReadOptions&); formats/cgns.hpp gains four (read_cgns/read_cgns_mll ReadOptions overloads, read_cgns_metadata, read_cgns_mll_metadata) plus a new #include "read_options.hpp"; formats/tecplot.hpp gains two (a read_tecplot ReadOptions overload, read_tecplot_metadata) plus the same new include; formats/ensight.hpp gains two (a read_ensight ReadOptions overload, read_ensight_metadata) plus the same new include; operations/sequence.hpp gains one, seq_format_may_have_steps(const std::string&), promoted out of sequence.cpp's anonymous namespace (previously internal-linkage-only, so no already-compiled consumer could have named it) -- mirroring the existing sequence_write_supports_time's own exported shape. No existing declaration, aggregate, enumerator, default argument or inline body in any of the nine headers is touched, moved or reordered; ReadOptions/MeshMetadata (the types every new overload takes/returns) are themselves unchanged. A consumer compiled against v11.2.0 headers links against exactly the same symbols with exactly the same signatures and layouts -- it simply does not have the new names. | | 13 | v11.5.0 | detail/cell_faces.hpp, formats/cgns.hpp, formats/ensight.hpp, formats/gid.hpp, formats/med.hpp, formats/openfoam.hpp, formats/tecplot.hpp, operations/agglomerate.hpp, operations/sequence.hpp, version.hpp | The gate's base is still the v11.0.0 tag (nothing in v11.1.0..v11.4.0 was tagged either), so every header any of those releases touched keeps appearing here until one is. detail/cell_faces.hpp, formats/gid.hpp and operations/agglomerate.hpp carry the same three comment-only fixes the v11.1.0/v11.2.0/v11.3.0 rows already reviewed; formats/cgns.hpp, formats/ensight.hpp, formats/med.hpp, formats/tecplot.hpp and operations/sequence.hpp carry the purely-additive v11.3.0 changes the row above already reviewed in full; formats/openfoam.hpp carries v11.4.0's mRegion layout change, already covered by that release's own MESHIOPLUSPLUS_ABI_VERSION 12 -> 13 bump (no review row was needed there, since a bump -- not a held number -- is what that gate branch requires). None of the nine changed again in this release. version.hpp is the routine release bump (macro values only, no declaration). This release's actual work -- roadmap §1 tier B3 (Gmsh physical-tag allocation for untagged regions, and 4.1 $Entities synthesis from Cell regions) -- lives entirely in src/cpp/src/formats/gmsh.cpp: every new struct (GmshRegionTag, GmshSynthesizedTags) and function (gmsh_infer_region_dim, gmsh_resolve_region_tags, gmsh_flat_tags_from_regions, gmsh_synthesize_tags_41) is static/anonymous-namespace, and write_gmsh22/write_gmsh41 keep their exact existing signatures in formats/gmsh.hpp -- unchanged, not even touched by this release's diff. A consumer compiled against v11.4.0 headers links against exactly the same symbols with exactly the same signatures and layouts. | | 13 | v11.6.0 | detail/cell_faces.hpp, formats/cgns.hpp, formats/ensight.hpp, formats/gid.hpp, formats/med.hpp, formats/openfoam.hpp, formats/tecplot.hpp, formats/vtm.hpp, formats/vtr.hpp, formats/vts.hpp, operations/agglomerate.hpp, operations/sequence.hpp, version.hpp | The gate's base is still the v11.0.0 tag, so every header any untagged release touched keeps appearing here until one is. detail/cell_faces.hpp, formats/gid.hpp and operations/agglomerate.hpp carry the same three comment-only fixes reviewed since v11.1.0; formats/cgns.hpp, formats/ensight.hpp, formats/med.hpp, formats/tecplot.hpp and operations/sequence.hpp carry the purely-additive v11.3.0 changes; formats/openfoam.hpp carries v11.4.0's mRegion layout change, already covered by that release's own ABI 12 -> 13 bump. None of those seven changed again in this release. version.hpp is the routine release bump. formats/vts.hpp, formats/vtr.hpp and formats/vtm.hpp are this release's actual work -- roadmap §1 tier B4 -- and each is an entirely new header: formats/vts.hpp declares write_vts/write_vts_codec/read_vts/read_vts_metadata; formats/vtr.hpp declares the same four names for .vtr; formats/vtm.hpp declares write_vtm/write_vtm_codec/read_vtm/read_vtm_metadata. None of the three declares a type, aggregate or enumerator at all -- only free functions over the pre-existing Mesh/ReadOptions/MeshMetadata/detail::VtkCodec types, none of which is touched. No pre-existing declaration anywhere in the installed tree is changed, moved or reordered by any of the three. A consumer compiled against v11.5.0 headers links against exactly the same symbols with exactly the same signatures and layouts -- it simply does not have the new names. | | 13 | v12.0.0 | detail/cell_faces.hpp, formats/cgns.hpp, formats/ensight.hpp, formats/gid.hpp, formats/med.hpp, formats/openfoam.hpp, formats/tecplot.hpp, formats/vtm.hpp, formats/vtr.hpp, formats/vts.hpp, operations/agglomerate.hpp, operations/sequence.hpp, detail/fast_number.hpp, version.hpp | The gate's base is still the v11.0.0 tag. detail/cell_faces.hpp, formats/gid.hpp, formats/cgns.hpp, formats/ensight.hpp, formats/med.hpp, formats/tecplot.hpp, operations/sequence.hpp, formats/openfoam.hpp, formats/vts.hpp, formats/vtr.hpp and formats/vtm.hpp carry no new change -- the same fixes the v11.1.0 through v11.6.0 rows above already reviewed. version.hpp is the routine release bump (macro values only, no declaration). operations/agglomerate.hpp carries one new comment-only edit this release: its "see the roadmap" cross-reference's section number moves §6 -> §5, following roadmap.md's own renumbering when §1 "WASM parity" (now fully shipped across v11.2.0-v11.6.0) was removed and every later section shifted down by one. AgglomerateOptions, AgglomerateResult and agglomerate(...) are untouched -- only the doc comment's target number changed. Same release, additionally: detail/fast_number.hpp is an entirely new header (roadmap §1 "correctness debts", the locale-sensitive number I/O item) -- it declares is_c_decimal_point, two parse_double overloads (const char*-cursor and std::string), the throwing stod_c, and one variadic, printf-attributed snprintf_c, all inline and none exported via MESHIOPLUSPLUS_API, plus one internal c_numeric_locale() helper backed by a function-local static locale_t. No pre-existing declaration, aggregate, enumerator or inline body anywhere in the installed tree is touched by it, and it declares no type or aggregate of its own for a consumer to have a stale layout of. Being header-only inline, every caller of these functions gets them from its own translation unit's compile, not from the previously-built meshioplusplus library, so there is no split-inline-definition hazard either. A consumer compiled against v11.6.0 headers links against exactly the same symbols with exactly the same signatures and layouts -- it simply does not have the new names. | | 13 | v12.1.0 | detail/fast_number.hpp, version.hpp | The gate's base is now the v12.0.0 tag. detail/fast_number.hpp carries no new change since the v12.0.0 row above reviewed it -- the same entirely-new header-only-inline header (is_c_decimal_point, two parse_double overloads, the throwing stod_c, one variadic snprintf_c, plus the internal c_numeric_locale() helper), byte-identical to that review; it only counts again because it landed in commits made after the v12.0.0 tag was cut. version.hpp is the routine release bump (macro values only, no declaration), as in every prior row. No pre-existing declaration, aggregate, enumerator, default argument or inline body anywhere in the installed tree is touched. A consumer compiled against v12.0.0 headers links against exactly the same symbols with exactly the same signatures and layouts -- it simply does not have the new names. | | 13 | v13.0.0 | detail/classic_stream.hpp, formats/ensight.hpp, version.hpp | The gate's base is now the v12.1.0 tag. version.hpp is the routine release bump (macro values only, no declaration), as in every prior row. formats/ensight.hpp carries one comment-only edit: its doc comment's roadmap cross-reference moves §7 -> §1, following doc/roadmap.md's renumbering when the Correctness debts section closed and Format reach became the first section (the reference was already stale by one since v12.0.0); no declaration, aggregate, enumerator, default argument or inline body is touched. Same release, additionally: detail/classic_stream.hpp is an entirely new header (roadmap "correctness debts", the locale-sensitive stream number I/O item) -- it declares imbue_classic and five factories, make_classic_istringstream, make_classic_ostringstream, make_classic_stringstream, make_classic_ifstream and make_classic_ofstream, all inline and none exported via MESHIOPLUSPLUS_API, and it declares no type or aggregate of its own for a consumer to have a stale layout of. No pre-existing declaration, aggregate, enumerator, default argument or inline body anywhere in the installed tree is touched by it. Being header-only inline, every caller of these functions gets them from its own translation unit's compile, not from the previously-built meshioplusplus library, so there is no split-inline-definition hazard either. detail/format_compat.hpp is deliberately not changed to use it: its std::format fallback is a function template in an installed header, so imbuing inside it would be a Tier B ODR change forcing an MESHIOPLUSPLUS_ABI_VERSION bump, and it only renders log lines and exception text -- never a byte of a file and never anything that is re-parsed -- so the residual (a message reading 1,5 under a global comma locale on a toolchain without <format>) is the cheaper side of that trade. A consumer compiled against v12.1.0 headers links against exactly the same symbols with exactly the same signatures and layouts -- it simply does not have the new names. | | 15 | v15.1.0 | formats/pcd.hpp, formats/xyz.hpp, version.hpp | formats/pcd.hpp and formats/xyz.hpp are entirely new headers: the PcdData enumeration, the PcdReadOptions and XyzReadOptions structs and four free functions (read_pcd, write_pcd, read_xyz, write_xyz), each declared with a defaulted trailing argument that no earlier release had. Nothing an already-compiled consumer contains refers to any of them, and no existing type, enumerator, default argument or inline body changes. version.hpp is the routine release bump (macro values only, no declaration), as in every prior row. | | 15 | v15.2.0 | detail/keyword_card.hpp, formats/lsdyna.hpp, version.hpp | detail/keyword_card.hpp and formats/lsdyna.hpp are entirely new headers: the CardMode enumeration, the CardField struct and five free functions (card_field_width, split_card, card_to_int, card_to_real, format_real16) in the first, and read_lsdyna and write_lsdyna in the second, with no default argument and no options struct. Nothing an already-compiled consumer contains refers to any of them, and no existing type, enumerator, default argument or inline body changes. version.hpp is the routine release bump (macro values only, no declaration), as in every prior row. | | 15 | v15.3.0 | formats/frd.hpp, version.hpp | formats/frd.hpp is an entirely new header: the FrdReadOptions struct (one bool, its layout pinned in tests/cpp/test_abi_layout.cpp) and three free functions (read_frd with a defaulted ReadOptions and an overload taking FrdReadOptions, and read_frd_metadata). Nothing an already-compiled consumer contains refers to any of them, and no existing type, enumerator, default argument or inline body changed: the format's derived switch is deliberately its own struct rather than a new member of ReadOptions, whose layout would have been a Tier A break. version.hpp is the routine release bump (macro values only, no declaration), as in every prior row. | | 15 | v15.4.0 | detail/surface_normals.hpp, operations/normals.hpp, formats/gltf.hpp, detail/colormap.hpp, version.hpp | detail/surface_normals.hpp, operations/normals.hpp and formats/gltf.hpp are entirely new headers: the VertexNormalGroups struct and four free functions (corner_angle, soup_face_normals, accumulate_vertex_normals, vertex_normal_groups) in the first; the NormalsOptions/NormalsResult aggregates, two inline constexpr const char* array-name constants and compute_normals() in the second; and the GltfContainer/GltfUpAxis enumerations, the GltfWriteOptions struct, two name parsers and write_gltf() in the third. NormalsOptions (64 bytes) and GltfWriteOptions (168 bytes) are pinned in tests/cpp/test_abi_layout.cpp from the release that introduces them; NormalsResult embeds a Mesh and is deliberately not pinned, like every other *Result. detail/colormap.hpp gains one declaration, srgb_to_linear_bits(), a pure addition: no existing declaration, enumerator, default argument or inline body in it changes. detail/surface_distance.hpp is untouched (the pseudonormal table's body moved into the new kernel, an out-of-line .cpp change). version.hpp is the routine release bump (macro values only, no declaration), as in every prior row. | | 15 | v15.5.0 | detail/mesh_carve.hpp, detail/sym3_eigen.hpp, operations/tensor_invariants.hpp, formats/frd.hpp, formats/openfoam.hpp, version.hpp | detail/mesh_carve.hpp, detail/sym3_eigen.hpp and operations/tensor_invariants.hpp are entirely new headers: the MeshPart struct and carve_by_region() (VTKHDF's own private composite-carving logic, generalized so EnSight's future multi-part writer can share it) in the first; sym3_mises()/sym3_principal() (the cyclic-Jacobi eigensolver, moved out of formats/frd.cpp so .frd's derived= and the new data operation share one implementation) in the second; and the TensorInvariant enum, the TensorInvariantsOptions struct, tensor_invariants() and tensor_invariant_from_name() in the third. OpenFoamWriteOptions (12 bytes, 4-aligned — three POD fields, no pointer/std::string member) is pinned in tests/cpp/test_abi_layout.cpp from the release that introduces it, the PvdSeriesWriter/GltfWriteOptions precedent above. formats/frd.hpp's only change is comment-only: the file-level doc comment now describes the binary layout read_frd accepts (previously refused) and read_frd's @throws clause drops "is binary" as a rejection reason; FrdReadOptions and every declaration are byte-identical to v15.3.0. formats/openfoam.hpp gains one new struct (OpenFoamWriteOptions, kept separate from the ABI-pinned OpenFoamInfo/WriteOptions specifically so neither's layout moves) and one new four-argument write_openfoam overload; the existing three-argument overload, OpenFoamInfo and every other declaration are byte-identical to v15.4.0. No pre-existing declaration, aggregate, enumerator, default argument or inline body anywhere in the installed tree is changed, moved or reordered by any of the five. A consumer compiled against v15.4.0 headers links against exactly the same symbols with exactly the same signatures and layouts — it simply does not have the new names. version.hpp is the routine release bump (macro values only, no declaration), as in every prior row. | | 15 | v15.6.0 | formats/unv.hpp, version.hpp | formats/unv.hpp gains three new MESHIOPLUSPLUS_API declarations — read_unv(const std::string&, const ReadOptions&), read_unv(const std::string&, UnvInfo&, const ReadOptions&) and read_unv_metadata(const std::string&, const ReadOptions& = {}), distinct mangled symbols with no default argument that could make an existing call ambiguous ({} cannot bind the UnvInfo& of the two-argument overload) — plus the #include "meshioplusplus/read_options.hpp" they need (the v9.4.0 mesh.hpp precedent: an include, no type changed) and rewritten doc comments. UnvInfo keeps its two members in the same order (its comment is the only change), and the two write_unv and two existing read_unv declarations, with their default arguments, are byte-identical to v15.5.0. No inline body, aggregate or enumerator exists in the header to change. What did change is behaviour behind the unchanged symbols (groups arrive as regions, results as steps, the corrected node orders — see the CHANGELOG's Breaking: items), which is a release-note matter, not a layout one. version.hpp is the routine release bump (macro values only, no declaration), as in every prior row. | | 15 | v15.7.0 | formats/nastran_h5.hpp, detail/hdf5_util.hpp, version.hpp | formats/nastran_h5.hpp is an entirely new header, #ifdef MESHIOPLUSPLUS_HAS_HDF5-guarded like med.hpp: two free functions (read_nastran_h5 with a defaulted ReadOptions, and read_nastran_h5_metadata) and no type. detail/hdf5_util.hpp gains one new aggregate, h5::CompoundMember (a std::string, a bool, a DType and a std::vector<std::size_t>: returned by value from the new function below, never taken by an existing one, so not pinned in test_abi_layout.cpp), and two new MESHIOPLUSPLUS_API functions, compound_members() and read_compound_member() (its last parameter a defaulted const DType*, on a new symbol, so no existing call can change meaning). Every existing declaration of the header, with its default arguments, is byte-identical to v15.6.0. The format needs no ReadOptions member: mTimeStep and the narrowing options already carry everything it honours. No pre-existing declaration, aggregate, enumerator, default argument or inline body anywhere in the installed tree is changed, moved or reordered. version.hpp is the routine release bump (macro values only, no declaration), as in every prior row. | | 16 | v16.1.0 | formats/mphtxt.hpp, formats/nastran.hpp, detail/keyword_card.hpp, version.hpp | formats/mphtxt.hpp gains two new MESHIOPLUSPLUS_API declarations, read_mphbin(const std::string&) and write_mphbin(const std::string&, const Mesh&); read_mphtxt/write_mphtxt keep their signatures (their doc comments and out-of-line bodies changed, which a compiled consumer does not see). formats/nastran.hpp changes only doc comments: read_nastran/write_nastran keep their declarations, and the reader's new behaviour lives in the library. detail/keyword_card.hpp gains two new overloads, card_to_int(const std::string&, const std::string&, const std::string&) and card_to_real(...) with the same extra parameter — distinct mangled symbols with no default arguments, so no existing call changes meaning; the existing two-argument functions are unchanged. No type, layout, inline body or default argument changed. version.hpp: the release macros, as every release. | | 16 | v16.2.0 | formats/elmer.hpp, formats/febio.hpp, formats/xplt.hpp, detail/facet_index.hpp, detail/zlib_inflate.hpp, operations/sniff.hpp, version.hpp | formats/elmer.hpp, formats/febio.hpp and formats/xplt.hpp are entirely new headers of free functions (read_elmer/write_elmer, read_febio/write_febio, read_xplt/read_xplt_metadata, each reader with a defaulted const ReadOptions& on a new symbol) and no type. detail/facet_index.hpp is new: the FacetIndexOptions, FacetOwner and FacetHit aggregates and the FacetIndex class (an std::unordered_map member; constructed and queried only through its own exported members, never passed into an existing function, so not pinned in test_abi_layout.cpp), plus facet_nodes(). detail/zlib_inflate.hpp is new: zlib_available() and zlib_inflate(), declared whether or not the build has zlib (without it, the function throws). operations/sniff.hpp changes only its doc comment: sniff_format keeps its declaration and now also answers for a directory. The C header meshioplusplus.h changes only mio_sniff_format's doc comment and the release macros. No pre-existing declaration, aggregate, enumerator, default argument or inline body anywhere in the installed tree is changed, moved or reordered. version.hpp: the release macros, as every release. | | 16 | v16.3.0 | detail/keyword_card.hpp, formats/ansysinp.hpp, formats/ansys_rst.hpp, detail/ansys_model.hpp, version.hpp | detail/keyword_card.hpp gains two new MESHIOPLUSPLUS_API functions, parse_fortran_format(std::string_view) and split_fixed(std::string_view, const std::vector<CardField>&), with no default argument; CardField and the existing functions are unchanged, and a duplicated #pragma once was removed (no declaration moves). formats/ansysinp.hpp gains one new overload, read_ansysinp(const std::string&, const ReadOptions&, AnsysInfo&), a distinct mangled symbol whose arity differs from the existing two-argument read_ansysinp(const std::string&, AnsysInfo&), so no call becomes ambiguous; it adds the #include "meshioplusplus/read_options.hpp" it needs (the v9.4.0 mesh.hpp precedent) and rewrites doc comments. AnsysInfo keeps its two members in the same order, and write_ansysinp keeps its declaration (its new behaviour lives in the library). formats/ansys_rst.hpp is an entirely new header of two free functions (read_ansys_rst with a defaulted ReadOptions, read_ansys_rst_metadata) and no type. detail/ansys_model.hpp is new: the AnsysCategory enumeration, the AnsysElement, AnsysComponent and AnsysModel aggregates (taken by const reference only by the new ansys_build_mesh, never by an existing function, so not pinned in test_abi_layout.cpp, as with v15.7.0's h5::CompoundMember) and three new functions (ansys_category, ansys_mesh200_category, ansys_build_mesh). Nothing an already-compiled consumer contains refers to any of them, and no existing type, enumerator, default argument or inline body changes. version.hpp is the routine release bump (macro values only, no declaration). v16.2.0 was never tagged on its own (it ships to master together with this release), so the check compares against v16.1.0 and also sees v16.2.0's headers: formats/elmer.hpp, formats/febio.hpp, formats/xplt.hpp, detail/facet_index.hpp, detail/zlib_inflate.hpp and operations/sniff.hpp. They are reviewed in the v16.2.0 row above (new headers of free functions and new aggregates, and a doc-comment change to operations/sniff.hpp), and this release does not touch them again. | | 16 | v16.5.0 | formats/patran.hpp, formats/femap.hpp, formats/mfem.hpp, registry.hpp, version.hpp | formats/patran.hpp, formats/femap.hpp and formats/mfem.hpp are entirely new headers: free functions (read_patran/write_patran; read_femap with a defaulted ReadOptions, read_femap_metadata, femap_time_values, write_femap; two read_mfem and two write_mfem overloads) and one new aggregate, MfemGridFunction (two std::strings), passed by const reference only. registry.hpp changes a doc comment only (resolve_format's .mesh rule lives in registry.cpp). version.hpp changes its version macros. No existing layout, inline body or default argument changes, so MESHIOPLUSPLUS_ABI_VERSION stays 16. | | 16 | v16.6.0 | version.hpp, formats/patran.hpp, formats/femap.hpp, formats/mfem.hpp, registry.hpp | The routine release bump (macro values only, no declaration); the C header meshioplusplus.h changes only MIO_VERSION_MINOR. Everything else in the release lives in the library: the readers changed are out-of-line, and the new helpers (formats/face_cells_common.hpp, the VTU appended-data decoder in vtu_read.cpp) are format-private and never installed. detail/node_order.hpp keeps its declarations; the new flux tables are data in node_order.cpp. No declaration, aggregate, enumerator, default argument or inline body in the installed tree changes. v16.5.0 reaches master untagged, so check-abi-version compares against v16.3.0 and also sees the headers v16.5.0 added or touched (formats/patran.hpp, formats/femap.hpp, formats/mfem.hpp, registry.hpp); they are reviewed in the v16.5.0 row and unchanged since. | | 16 | v16.7.0 | detail/abaqus_types.hpp, detail/binary_stream.hpp, detail/degenerate_solid.hpp, detail/fortran_records.hpp, formats/abaqus_fil.hpp, formats/libmesh.hpp, formats/radioss.hpp, formats/z88.hpp, version.hpp | All eight are entirely new headers. The four format headers declare free functions only (read_abaqus_fil with a defaulted ReadOptions, read_abaqus_fil_metadata, abaqus_fil_time_values; read_libmesh; read_radioss; is_z88_filename, read_z88 and write_z88 with defaulted bools). detail/abaqus_types.hpp and detail/degenerate_solid.hpp declare free functions and one new aggregate, CollapsedBrick (a const char* and a std::vector), returned by value; detail/fortran_records.hpp two new aggregates of plain integers and two free functions. detail/binary_stream.hpp defines one new class, ByteCursor, entirely inline; no existing header includes it, so no already-compiled consumer can have an older copy of its body. The Abaqus type table moved out of abaqus.cpp into the library, and the LS-DYNA collapse now calls the shared helper: both out-of-line. version.hpp changes its version macros; meshioplusplus.h only MIO_VERSION_MINOR. No existing declaration, layout, enumerator, default argument or inline body changes, so MESHIOPLUSPLUS_ABI_VERSION stays 16. | | 16 | v16.8.0 | detail/ansys_model.hpp, formats/ansys_rst.hpp, formats/marc.hpp, version.hpp | formats/marc.hpp is an entirely new header of free functions (is_marc_deck, read_marc, read_marc_t19 with a defaulted ReadOptions, read_marc_t19_metadata). formats/ansys_rst.hpp adds two free functions, read_ansys_rst_cyclic and read_ansys_rst_cyclic_metadata (defaulted ReadOptions, like their siblings); its other changes are comments. detail/ansys_model.hpp adds one new aggregate, AnsysCellLocation (two std::int64_t and a std::vector<int>), and a new out-of-line overload of ansys_build_mesh taking a std::vector<AnsysCellLocation>&; the existing overload keeps its declaration, and its out-of-line body now forwards to the new one with the same result. version.hpp changes its version macros; meshioplusplus.h only MIO_VERSION_MINOR. No existing declaration, layout, enumerator, default argument or inline body changes, so MESHIOPLUSPLUS_ABI_VERSION stays 16. | | 16 | v16.9.0 | detail/nastran_model.hpp, formats/lsdyna_d3plot.hpp, formats/nastran_op2.hpp, version.hpp | All three are entirely new headers. formats/lsdyna_d3plot.hpp and formats/nastran_op2.hpp declare free functions only (read_lsdyna_d3plot, lsdyna_d3plot_time_values, read_lsdyna_d3plot_metadata, is_d3plot_filename, is_d3plot_head; read_nastran_op2, nastran_op2_time_values, read_nastran_op2_metadata), with defaulted ReadOptions like their siblings. detail/nastran_model.hpp adds three aggregates (NastranCardSpec, NastranCardRows, NastranCells) and out-of-line free functions (nastran_card_spec, nastran_add_cells, nastran_add_frame, nastran_read_deck); the nastran_h5 reader moved onto them from its own anonymous-namespace code, with the same output. version.hpp changes its version macros; meshioplusplus.h only MIO_VERSION_MINOR. No existing declaration, layout, enumerator, default argument or inline body changes, so MESHIOPLUSPLUS_ABI_VERSION stays 16. | | 16 | v16.10.0 | detail/nastran_model.hpp, formats/ansys.hpp, formats/nastran_h5.hpp, formats/nastran_op2.hpp, formats/tecplot.hpp, formats/xplt.hpp, version.hpp | detail/nastran_model.hpp adds one new aggregate, NastranCoordCard (integers, a bool and two fixed arrays), one new class, NastranCoordSystems (a std::map; its constructor and methods out-of-line except the inline Has and Add, both new), and two out-of-line free functions, nastran_apply_frames and nastran_rotate_to_basic; it drops the declaration of nastran_add_frame, which was never exported (no MESHIOPLUSPLUS_API; the library hides every other symbol), so no compiled consumer can have referenced it. The five format headers change comments only: the Tecplot reader's .plt and ordered zones, the Nastran readers' coordinate systems and multi-valued arrays, the Fluent writer's face-based layout, the .xplt surface blocks and remeshed runs. version.hpp changes its version macros; meshioplusplus.h only MIO_VERSION_MINOR. No existing layout, inline body, enumerator or default argument changes, so MESHIOPLUSPLUS_ABI_VERSION stays 16. | | 16 | v16.11.0 | formats/elmer.hpp, formats/libmesh.hpp, formats/mfem.hpp, formats/radioss_anim.hpp, formats/z88.hpp, version.hpp | All additions. formats/elmer.hpp gains one new overload, write_elmer(const std::string&, const Mesh&, bool Halo); the existing two-argument write_elmer is unchanged (no default argument was added to it). formats/libmesh.hpp gains the new free function write_libmesh. formats/mfem.hpp gains one new overload, read_mfem(path, grid_functions, const ReadOptions&), and an #include of read_options.hpp; the existing overloads are unchanged. formats/radioss_anim.hpp is an entirely new header (is_radioss_anim_filename, read_radioss_anim, read_radioss_anim_metadata, all out-of-line). formats/z88.hpp changes comments only. version.hpp changes its version macros; meshioplusplus.h only MIO_VERSION_MINOR. No existing layout, inline body, enumerator or default argument changes, so MESHIOPLUSPLUS_ABI_VERSION stays 16. | | 16 | v16.12.0 | formats/lsdyna_binout.hpp, formats/lsdyna_d3plot.hpp, formats/patran.hpp, formats/radioss_th.hpp, version.hpp | All additions. formats/lsdyna_binout.hpp and formats/radioss_th.hpp are entirely new headers (read_lsdyna_binout, lsdyna_binout_time_values, read_lsdyna_binout_metadata, is_binout_filename, is_binout_head; is_radioss_th_filename, is_radioss_th_head, read_radioss_th, radioss_th_time_values, read_radioss_th_metadata), every function out-of-line. formats/patran.hpp adds one new aggregate, PatranResultFile (two std::strings, pinned in tests/cpp/test_abi_layout.cpp from this release), one new overload read_patran(const std::string&, const std::vector<PatranResultFile>&) and an #include <vector>; the existing one-argument read_patran and write_patran are unchanged, only their comments grew. formats/lsdyna_d3plot.hpp changes comments only. version.hpp changes its version macros; meshioplusplus.h only MIO_VERSION_MINOR. No existing layout, inline body, enumerator or default argument changes, so MESHIOPLUSPLUS_ABI_VERSION stays 16. | | 16 | v16.13.0 | formats/szplt.hpp, formats/vtx.hpp, version.hpp | All additions. formats/vtx.hpp (read_vtx, vtx_time_values, read_vtx_metadata) and formats/szplt.hpp (read_szplt, szplt_time_values, read_szplt_metadata) are entirely new headers, each compiled only with its optional dependency (MESHIOPLUSPLUS_HAS_ADIOS2, MESHIOPLUSPLUS_HAS_TECIO), every function out-of-line, no type declared. version.hpp changes its version macros; meshioplusplus.h only MIO_VERSION_MINOR. No existing layout, inline body, enumerator or default argument changes, so MESHIOPLUSPLUS_ABI_VERSION stays 16. | | 17 | v16.15.0 | detail/hdf5_util.hpp, detail/space_filling.hpp, detail/vtu_binary.hpp, operations/optimize_volume.hpp, operations/partition.hpp, version.hpp | version.hpp is the routine release bump (macro values only, no declaration). detail/space_filling.hpp gains one new inline function, sfc_stable_argsort, and the four standard includes it needs (<algorithm>, <cstddef>, <numeric>, <vector>); sfc_bits, sfc_part1by2, sfc_morton_key and sfc_hilbert_key are byte-identical, so a consumer compiled against v16.14.0 has the same definitions and simply lacks the new name. The other four are comment-only: the doc comments of h5::read_dataset and h5::write_dataset (detail/hdf5_util.hpp) and of b64decode (detail/vtu_binary.hpp) describe the new chunked and parallel implementations, whose bodies are out-of-line in src/cpp/src/detail/ with unchanged signatures; operations/optimize_volume.hpp's determinism note and operations/partition.hpp's describe the sort now used. No declaration, default argument, inline body or layout changes in any of them. | | 18 | v16.17.0 | detail/degenerate_solid.hpp, detail/keyword_card.hpp, formats/ensight.hpp, formats/femap.hpp, formats/marc.hpp, formats/radioss.hpp, registry.hpp, version.hpp | All additions. detail/degenerate_solid.hpp declares one new out-of-line function, expand_brick (and includes <string_view>); detail/keyword_card.hpp two, format_real_fit and format_real_short; formats/ensight.hpp one new overload, write_ensight(path, mesh, bool binary, bool fortran), a distinct mangled symbol beside the unchanged three-argument form (the other lines changed are comments); formats/marc.hpp write_marc, formats/radioss.hpp write_radioss(path, mesh, bool Stubs = false), and registry.hpp resolve_write_format, each new. formats/femap.hpp declares a new class, FemapSeriesWriter, whose only member is a std::unique_ptr to its implementation (8 bytes, pinned in test_abi_layout.cpp), every member function out-of-line, and includes <cstddef> and <memory>. version.hpp changes its version macros; meshioplusplus.h only MIO_VERSION_MINOR. No existing layout, inline body, enumerator or default argument changes, so MESHIOPLUSPLUS_ABI_VERSION stays 18. | | 18 | v16.18.0 | operations/neighbors.hpp, detail/surface_distance.hpp, version.hpp | version.hpp is the routine release bump (macro values only, no declaration). operations/neighbors.hpp is an entirely new header: the NeighborMethod enum, the NeighborOptions and NeighborPairs aggregates and one MESHIOPLUSPLUS_API function, neighbor_pairs. detail/surface_distance.hpp gains one new MESHIOPLUSPLUS_API overload, soup_quality(const TriangleSoup&, const SurfaceEdgeMap&), a distinct mangled symbol beside the unchanged one-argument declaration, plus its doc comment. No existing declaration, default argument, inline body or layout changes. | | 18 | v16.19.0 | detail/spatial_hash.hpp, version.hpp | version.hpp is the routine release bump (macro values only, no declaration). detail/spatial_hash.hpp gains one new inline member function, SpatialGrid::AssignBuckets (the bulk form of Insert/InsertBox), an #include <utility> and comment changes; a member function adds no data member, so SpatialGrid's and DistanceQuery's layouts are unchanged (still pinned in tests/cpp/test_abi_layout.cpp), and every existing member's body is byte-identical. No existing declaration, default argument, inline body or layout changes. | | 18 | v16.20.0 | version.hpp | The routine release bump (macro values only, no declaration). The release's I/O changes are all in out-of-line bodies and in core-private headers beside the sources (detail/open_source.hpp, detail/row_writer.hpp, detail/vtu_decode.hpp, formats/vtk_preflight.hpp), which no installed header names. No declaration, default argument, inline body, enumerator or layout changes, so MESHIOPLUSPLUS_ABI_VERSION stays 18. | | 18 | v16.21.0 | formats/vtu.hpp, write_options.hpp, meshioplusplus.h (C), version.hpp | version.hpp is the routine release bump (macro values only, no declaration). formats/vtu.hpp gains one new exported function, write_vtu_appended, and comment changes (the file and read_vtu comments had gone stale); write_vtu/write_vtu_codec keep their declarations and out-of-line bodies. write_options.hpp's WriteEncoding gains RawAppended after every existing enumerator, and the C mio_write_encoding gains MIO_ENCODING_RAW_APPENDED = 3 after MIO_ENCODING_BINARY = 2: appended enumerators, no existing value moves, and WriteOptions/mio_write_opts keep their layouts (the test_abi_layout.cpp pins are unchanged). The tokenizer is in the core-private detail/text_cursor.hpp, which no installed header names. MESHIOPLUSPLUS_ABI_VERSION stays 18. v16.18.0 to v16.21.0 reach master in one merge, on top of the untagged v16.17.0, so the gate compares against v16.16.0 and this row also names the headers the earlier rows reviewed: v16.17.0's detail/degenerate_solid.hpp, detail/keyword_card.hpp, formats/ensight.hpp, formats/femap.hpp, formats/marc.hpp, formats/radioss.hpp and registry.hpp, v16.18.0's operations/neighbors.hpp and detail/surface_distance.hpp, and v16.19.0's detail/spatial_hash.hpp. Since those reviews they changed only in comments (the release numbers they cite), so the earlier verdicts stand. | | 18 | v16.21.1 | version.hpp | The routine release bump (macro values only, no declaration): MESHIOPLUSPLUS_VERSION_PATCH and MESHIOPLUSPLUS_VERSION_STRING move from 0/"16.21.0" to 1/"16.21.1". This release is documentation-only (roadmap §0): no other installed header changed, no reader/writer/operation output changed, and MESHIOPLUSPLUS_ABI_VERSION stays 18. | | 18 | v16.22.0 | detail/space_filling.hpp, operations/neighbors.hpp, parallel.hpp, version.hpp | version.hpp is the routine release bump (macro values only, no declaration): MESHIOPLUSPLUS_VERSION_MINOR 21 -> 22, MESHIOPLUSPLUS_VERSION_PATCH 1 -> 0 and MESHIOPLUSPLUS_VERSION_STRING "16.21.1" -> "16.22.0"; the C header changes only MIO_VERSION_MINOR/MIO_VERSION_PATCH beside it. The other three are comment-only: their doc comments' roadmap section numbers moved down by one when doc/roadmap.md §2 (Spack package upkeep) was removed and every later section renumbered, so parallel.hpp's note on the sort-based facet and edge tables, operations/neighbors.hpp's on neighbor_pairs and detail/space_filling.hpp's on the space-filling order now cite Performance as §3 rather than §4. Not one declaration, default argument, inline or template body, enumerator or layout changes in any of them, so MESHIOPLUSPLUS_ABI_VERSION stays 18. No reader, writer or operation output changes either: the release is a documentation one, and the only bytes a release does move are the four writer provenance comments, whose refreshed BASELINE_HASHES were verified against the previous hashes with the old version string substituted back in. v16.21.1 reaches master untagged, so the gate compares against v16.21.0, whose own row above reviewed version.hpp. | | 18 | v16.23.0 (untagged; ships in v16.24.0) | operations/feature_edges.hpp, operations/hausdorff.hpp, operations/periodic.hpp, operations/region_ops.hpp, region.hpp, backends/meshio_mesh.hpp, backends/native_mesh.hpp, backends/kratos_mesh.hpp, mesh_api.hpp, detail/decimate_common.hpp, meshioplusplus.h (C), version.hpp | version.hpp is the routine release bump (macro values only, no declaration): MESHIOPLUSPLUS_VERSION_MINOR 22 -> 23 and MESHIOPLUSPLUS_VERSION_STRING "16.22.0" -> "16.23.0"; the C header's MIO_VERSION_MINOR beside it. The four operations/*.hpp are entirely new headers: they declare new exported functions (feature_edges, hausdorff_distance, region_op_name, region_op_from_name, find_region, edit_regions, match_periodic_nodes), new types and new inline constexpr constants; nothing pre-existing is touched, and the new option structs are pinned in tests/cpp/test_abi_layout.cpp from this release. region.hpp gains one new inline member function, detail::RegionList::Remove, and the three backends one new inline member each, RemoveRegion (the Kratos one forwarding to its staging mesh); a member function adds no data member, so RegionList, MeshioMesh, NativeMesh, KratosMesh and Mesh keep their layouts (still pinned), and every existing member's body is byte-identical. mesh_api.hpp and detail/decimate_common.hpp are comment-only (RemoveRegion documented; decim_mark_features marked deprecated — its declaration and out-of-line body unchanged, merely no longer called). The C header gains new functions, structs (mio_feature_edges_opts/_report, mio_hausdorff_opts/_report, mio_region_selector, mio_periodic_opts, each with a reserved tail and a static_asserted size), the new enum mio_region_op, the macro MIO_REGION_ANY and the opaque mio_periodic_pairs; no existing declaration changes. No existing declaration, default argument, inline body, enumerator or layout changes, so MESHIOPLUSPLUS_ABI_VERSION stays 18. | | 18 | v16.24.0 | operations/quality_gate.hpp, meshioplusplus.h (C), version.hpp | version.hpp is the routine release bump (macro values only, no declaration): MESHIOPLUSPLUS_VERSION_MINOR 23 -> 24 and MESHIOPLUSPLUS_VERSION_STRING "16.23.0" -> "16.24.0"; the C header's MIO_VERSION_MINOR beside it. operations/quality_gate.hpp is an entirely new header: it declares new exported functions (parse_quality_thresholds, check_quality, quality_gate_summary) and new types (QualityThreshold, QualityGateOptions, QualityCheck, QualityGateResult); nothing pre-existing is touched. The C header gains the new struct mio_quality_gate_report (reserved tail, size static_asserted at 88 bytes) and the new function mio_check_quality, and loses a duplicated block — mio_extract_surface, mio_extract_skin, mio_attach_quality, mio_quality_counts and mio_sniff_format were each declared twice, identically; one declaration of each remains, so no symbol, signature or layout changes. No existing declaration, default argument, inline body, enumerator or layout changes, so MESHIOPLUSPLUS_ABI_VERSION stays 18. | | 19 | v16.26.0 | version.hpp | The routine release bump (macro values only, no declaration): MESHIOPLUSPLUS_VERSION_MINOR 25 -> 26 and MESHIOPLUSPLUS_VERSION_STRING "16.25.0" -> "16.26.0"; the C header's MIO_VERSION_MINOR beside it. This release's actual work — the EnSight FileSource, d3plot airbag-count, Gmsh $NodeData/$ElementData and UGRID node-index reader-crash fixes found by the scheduled fuzz workflow — lives entirely in .cpp implementation files (src/cpp/src/file_source.cpp, src/cpp/src/formats/{gmsh,lsdyna_d3plot,ugrid}.cpp), none of which is installed. No existing declaration, default argument, inline body, enumerator or layout in any installed header changes, so MESHIOPLUSPLUS_ABI_VERSION stays 19. | | 20 | v16.28.0 | operations/interfaces.hpp, version.hpp | version.hpp is the routine release bump (macro values only, no declaration): MESHIOPLUSPLUS_VERSION_MINOR 27 -> 28 and MESHIOPLUSPLUS_VERSION_STRING "16.27.0" -> "16.28.0". operations/interfaces.hpp is an entirely new header declaring the interface/contact enums, option and result aggregates, and four exported operations (region_adjacency, find_interface, contact_pairs, split_interface). The new standalone option/report/array-result layouts are pinned in tests/cpp/test_abi_layout.cpp; result types embedding Mesh are deliberately not pinned because each mesh backend has a different layout. No existing declaration, default argument, inline body, enumerator value or type layout changes. The C header's new functions and reserved-tail option structs are outside the C++ ABI gate and follow the separate append-only C ABI contract. MESHIOPLUSPLUS_ABI_VERSION stays 20. The Gmsh, Tecplot and VTU reader-crash fixes found by the scheduled fuzz workflow remain .cpp-only. | | 22 | v16.28.0 (unreleased VTK parity) | formats/vti.hpp, formats/vts.hpp, formats/vtr.hpp, formats/vtp.hpp, formats/vtk.hpp | Comment-only corrections describe appended/multi-piece XML reads and native legacy structured reads. No declaration, default argument, inline/template body, enumerator or layout changes. The shared decoder/assembly declarations are core-private under src/cpp/src/detail/; implementations, including rank-aware tensor row copies, are out-of-line. Release version 16.28.0 and ABI 22 remain unchanged; the earlier MDPA/Gmsh layout changes separately required ABI 21/22. | | 22 | v16.28.0 (unreleased XDMF series regions) | formats/xdmf_time_series.hpp, meshioplusplus.h (C) | Comment-only updates record that WritePointsCells consumes fixed named regions with geometry and topology. All declarations, default arguments, inline/template bodies and layouts are unchanged. The shared set encoder declaration is core-private in src/cpp/src/formats/xdmf_sets.hpp; implementation changes are out-of-line. ABI 22 remains unchanged. | | 22 | v16.28.0 (unreleased core parity completion) | formats/exodus.hpp, operations/pipeline.hpp, formats/netgen.hpp, meshioplusplus.h (C) | Additive: exodus.hpp adds the move-only pimpl ExodusTimeSeriesWriter and its out-of-line methods, without altering existing declarations/defaults/layouts; its one-pointer layout is pinned in test_abi_layout.cpp. pipeline.hpp adds pipeline_v2_op_table(); Version 2 uses the existing typed structs and variants unchanged. netgen.hpp is comment-only capability correction. C adds opaque mio_exodus_series lifecycle functions, leaving all existing option structs and entry points unchanged. All new behavior is implemented out-of-line; no pre-existing inline/template body changes, so ABI 22 remains unchanged. | | 22 | v16.28.0 (unreleased Nastran HDF5 writer) | formats/nastran_h5.hpp | Pure additions: the free function write_nastran_h5 and the class NastranH5SeriesWriter (a pimpl, std::unique_ptr to an incomplete type, constructor, Write, NumSteps and Finalize out-of-line), both MESHIOPLUSPLUS_HAS_HDF5-guarded like the reader. No existing declaration, layout, enumerator, default argument or inline body changes, so MESHIOPLUSPLUS_ABI_VERSION stays 22. | | 22 | v16.28.0 (unreleased Radioss animation writer) | formats/radioss_anim.hpp | Pure additions: the free function write_radioss_anim and the class RadiossAnimSeriesWriter (a pimpl, std::unique_ptr to an incomplete type, constructor, destructor, move operations, Write, NumSteps and Finalize out-of-line). The existing is_radioss_anim_filename, read_radioss_anim and read_radioss_anim_metadata declarations are unchanged, and the header gains only the <cstddef> and <memory> includes. No existing declaration, layout, enumerator, default argument or inline body changes, so MESHIOPLUSPLUS_ABI_VERSION stays 22. | | 22 | v16.28.0 (unreleased FEBio plot writer) | formats/xplt.hpp | Pure additions: the free function write_xplt and the class XpltSeriesWriter (a pimpl, std::unique_ptr to an incomplete type, constructor, destructor, move operations, Write, NumSteps and Finalize out-of-line). The existing read_xplt and read_xplt_metadata declarations are unchanged, and the header gains only the <cstddef> and <memory> includes. No existing declaration, layout, enumerator, default argument or inline body changes, so MESHIOPLUSPLUS_ABI_VERSION stays 22. | | 22 | v16.28.0 (unreleased DOLFINx VTX writer) | formats/vtx.hpp | Pure additions inside the MESHIOPLUSPLUS_HAS_ADIOS2 guard: the free function write_vtx and the class VtxSeriesWriter (a pimpl, std::unique_ptr to an incomplete type, constructor, destructor, move operations, Write, NumSteps and Finalize out-of-line). The existing read_vtx, vtx_time_values and read_vtx_metadata declarations are unchanged, and the header gains only the <cstddef> and <memory> includes. No existing declaration, layout, enumerator, default argument or inline body changes, so MESHIOPLUSPLUS_ABI_VERSION stays 22. | | 22 | v16.28.0 (unreleased Tecplot SZL writer) | formats/szplt.hpp | Pure additions inside the MESHIOPLUSPLUS_HAS_TECIO guard: the free function write_szplt and the class SzpltSeriesWriter (a pimpl, std::unique_ptr to an incomplete type, constructor, destructor, move operations, Write, NumSteps and Finalize out-of-line). The existing read_szplt, szplt_time_values and read_szplt_metadata declarations are unchanged, and the header gains only the <cstddef> and <memory> includes. No existing declaration, layout, enumerator, default argument or inline body changes, so MESHIOPLUSPLUS_ABI_VERSION stays 22. | | 22 | v16.28.0 (unreleased Marc post-file writer) | formats/marc.hpp | Pure additions: the free function write_marc_t19 and the class MarcT19SeriesWriter (a pimpl, std::unique_ptr to an incomplete type, constructor, destructor, move operations, Write, NumSteps and Finalize out-of-line). Every existing declaration is unchanged, and the header gains only the <memory> include (<cstddef> was there). No existing declaration, layout, enumerator, default argument or inline body changes, so MESHIOPLUSPLUS_ABI_VERSION stays 22. | | 22 | v16.28.0 (unreleased Ansys results writer) | formats/ansys_rst.hpp, detail/ansys_model.hpp | Pure additions: the free function write_ansys_rst and the class AnsysRstSeriesWriter (a pimpl, std::unique_ptr to an incomplete type, constructor, destructor, move operations, Write, NumSteps and Finalize out-of-line); detail/ansys_model.hpp gains the free functions ansys_cell_layout, ansys_default_routine, ansys_num_corners and ansys_element_types with the struct AnsysElementTypes. The existing declarations are unchanged. | | 22 | v16.28.0 (unreleased LS-DYNA d3plot writer) | formats/lsdyna_d3plot.hpp | Pure additions: the free function write_lsdyna_d3plot (with defaulted MaxFileBytes and DoublePrecision) and the class LsdynaD3plotSeriesWriter (a pimpl, std::unique_ptr to an incomplete type, constructor, destructor, move operations, Write, NumSteps and Finalize out-of-line), plus the <memory> include. The existing declarations are unchanged. | | 22 | v16.28.0 (unreleased Medit binary) | formats/medit.hpp | Pure additions: the free functions read_medit_binary, write_medit_binary, read_medit and write_medit. The existing declarations are unchanged. | | 22 | v16.28.0 (unreleased OpenFOAM series, regions, decomposed) | formats/openfoam.hpp | Pure additions: the free functions write_openfoam_region and write_openfoam_decomposed and the class OpenFoamSeriesWriter (a pimpl, std::unique_ptr to an incomplete type, constructor, destructor, move operations, Write, NumSteps and Finalize out-of-line). OpenFoamInfo (the 128-byte pinned struct) and OpenFoamWriteOptions are unchanged. | | 30 | v17.3.0 (§3 writers and readers) | detail/ansys_model.hpp, detail/nastran_model.hpp, detail/vtu_binary.hpp, formats/abaqus_fil.hpp, formats/ansys_rst.hpp, formats/lsdyna_binout.hpp, formats/lsdyna_d3plot.hpp, formats/marc.hpp, formats/medit.hpp, formats/nastran_h5.hpp, formats/neuroglancer.hpp, formats/openfoam.hpp, formats/radioss_anim.hpp, formats/szplt.hpp, formats/vtx.hpp, formats/xdmf.hpp, formats/xplt.hpp, version.hpp | Pure additions: the new header formats/neuroglancer.hpp (read_neuroglancer, write_neuroglancer); the free functions write_ansys_rst, write_lsdyna_d3plot, write_marc_t19, read_medit_binary, write_medit_binary, read_medit, write_medit, write_nastran_h5, write_openfoam_region, write_openfoam_decomposed, write_radioss_anim, write_szplt, write_vtx and write_xplt; the series-writer classes AnsysRstSeriesWriter, LsdynaD3plotSeriesWriter, MarcT19SeriesWriter, NastranH5SeriesWriter, OpenFoamSeriesWriter, RadiossAnimSeriesWriter, SzpltSeriesWriter, VtxSeriesWriter and XpltSeriesWriter (pimpls, with out-of-line members); and in detail/ansys_model.hpp the struct AnsysElementTypes and the functions ansys_cell_layout, ansys_default_routine, ansys_num_corners and ansys_element_types. The #include lines added across the list are additive. The only removed text is comments: the LZMA enumerator in detail/vtu_binary.hpp keeps its name, position and value and changes only its trailing comment, and the other removals are doc-comment lines in formats/medit.hpp, formats/nastran_h5.hpp and formats/xdmf.hpp. No layout, enumerator, default argument or inline body of an existing entity changes, so MESHIOPLUSPLUS_ABI_VERSION stays 30. version.hpp changes only the release version macros (MESHIOPLUSPLUS_VERSION_MINOR and MESHIOPLUSPLUS_VERSION_STRING, bumped to 17.3.0): macro values with no type, function or layout behind them, which a compiled consumer never reads back. Three headers changed after the v17.3.0 tag, while the version is still 17.3.0, so this row names them too: detail/nastran_model.hpp, formats/abaqus_fil.hpp and formats/lsdyna_binout.hpp. Their changes are pure additions, reviewed in the rows labelled v17.4.0 below (30), so MESHIOPLUSPLUS_ABI_VERSION stays 30. | | 30 | v17.4.0 (binout split) | formats/lsdyna_binout.hpp | Pure additions: the struct LsdynaBinoutWriteOptions (a std::size_t, an int and a bool), the overloads write_lsdyna_binout(const std::string&, const Mesh&, std::size_t) and write_lsdyna_binout(const std::string&, const Mesh&, const LsdynaBinoutWriteOptions&), and the constructors LsdynaBinoutSeriesWriter(const std::string&, std::size_t) and LsdynaBinoutSeriesWriter(const std::string&, const LsdynaBinoutWriteOptions&). The existing write_lsdyna_binout(const std::string&, const Mesh&) and LsdynaBinoutSeriesWriter(const std::string&) declarations are unchanged (the one-argument forms call the new ones with 0 inside the library), and LsdynaBinoutSeriesWriter keeps its single std::unique_ptr member (8 bytes, pinned in test_abi_layout.cpp). No layout, enumerator, default argument or inline body of an existing entity changes, so MESHIOPLUSPLUS_ABI_VERSION stays 30. | | 30 | v17.4.0 (nastran springs and dampers) | detail/nastran_model.hpp | Pure additions: the struct NastranCellIds (the per-block nastran:card, nastran:c1 and nastran:c2 arrays; when some block holds a CBAR, its nastran:x, nastran:g0, nastran:pin and nastran:w; when some block holds a CELAS2, its nastran:k, nastran:ge and nastran:s; when some block holds a CDAMP2, its nastran:b) and the overload of nastran_add_cells that takes the spring and damper components, the card fields and an output NastranCellIds*. NastranCellIds is first shipped in this release, so no released consumer has compiled its members, and they are recorded here rather than as a layout bump. The six-argument nastran_add_cells and every existing signature are unchanged. The new inline accessor NastranCoordSystems::Get, which returns a resolved system by id, adds no data member and changes no existing body. No ABI bump. | | 30 | v17.4.0 (abaqus_fil binary layouts) | formats/abaqus_fil.hpp | Pure additions: the struct AbaqusFilWriteOptions (two bools and an int, 8 bytes, pinned in test_abi_layout.cpp), the overload write_abaqus_fil(const std::string&, const Mesh&, const AbaqusFilWriteOptions&) and the constructor AbaqusFilSeriesWriter(const std::string&, const AbaqusFilWriteOptions&). The existing write_abaqus_fil(const std::string&, const Mesh&, bool = false) and AbaqusFilSeriesWriter(const std::string&, bool = false) declarations, their default arguments and AbaqusFilSeriesWriter's single std::unique_ptr member are unchanged, so MESHIOPLUSPLUS_ABI_VERSION stays 30. | | 30 | v17.4.0 (xplt compression) | formats/xplt.hpp | Pure additions: the struct XpltWriteOptions (one bool, 1 byte, pinned in test_abi_layout.cpp), the overload write_xplt(const std::string&, const Mesh&, const XpltWriteOptions&) and the constructor XpltSeriesWriter(const std::string&, const XpltWriteOptions&). The existing write_xplt(const std::string&, const Mesh&) and XpltSeriesWriter(const std::string&) declarations and XpltSeriesWriter's single std::unique_ptr member are unchanged, and the rest of the header's change is comments, so MESHIOPLUSPLUS_ABI_VERSION stays 30. | | 30 | v17.4.0 (openfoam regionProperties and zones) | formats/openfoam.hpp | Pure additions: the struct OpenFoamRegionGroup (a family name and its region names, a std::string and a std::vector<std::string>; 56 bytes, align 8, pinned in test_abi_layout.cpp) and the free functions write_openfoam_region_properties(const std::string&, const std::vector<OpenFoamRegionGroup>&) and read_openfoam_region_properties(const std::string&). The declarations of write_openfoam_region, write_openfoam_decomposed and read_openfoam are unchanged; their doc comments changed (decomposed zones, the regionProperties note and the boundary-patch values). OpenFoamInfo (the 128-byte pinned struct) and OpenFoamWriteOptions are unchanged, so MESHIOPLUSPLUS_ABI_VERSION stays 30. | | 30 | v17.4.0 | detail/nastran_model.hpp, formats/abaqus_fil.hpp, formats/lsdyna_binout.hpp, formats/openfoam.hpp, formats/xplt.hpp, version.hpp | The five content headers are pure additions, reviewed in the rows labelled v17.4.0 (binout split), v17.4.0 (nastran springs and dampers), v17.4.0 (abaqus_fil binary layouts), v17.4.0 (xplt compression) and v17.4.0 (openfoam regionProperties and zones) above: new option structs (pinned in test_abi_layout.cpp), new overloads beside unchanged existing declarations, and one new inline accessor that adds no data member. version.hpp changes only the release version macros (MESHIOPLUSPLUS_VERSION_MINOR and MESHIOPLUSPLUS_VERSION_STRING, bumped to 17.4.0): macro values with no type, function or layout behind them, which a compiled consumer never reads back. No existing declaration, default argument, inline body, enumerator or layout changes, so MESHIOPLUSPLUS_ABI_VERSION stays 30. | | 30 | v17.5.0 | formats/openfoam.hpp, formats/xplt.hpp, version.hpp | The two content headers are pure additions, reviewed in the rows labelled v17.4.0 (xplt compression) and v17.4.0 (openfoam regionProperties and zones) above; the changes were made after the v17.4.0 tag while the version was still 17.4.0 and ship unrevised in this release: in formats/openfoam.hpp the struct OpenFoamRegionGroup and the free functions write_openfoam_region_properties / read_openfoam_region_properties, in formats/xplt.hpp the struct XpltWriteOptions, the overload write_xplt(const std::string&, const Mesh&, const XpltWriteOptions&) and the constructor XpltSeriesWriter(const std::string&, const XpltWriteOptions&) (pinned in test_abi_layout.cpp), the rest of both diffs doc-comment text. version.hpp changes only the release version macros (MESHIOPLUSPLUS_VERSION_MINOR and MESHIOPLUSPLUS_VERSION_STRING, bumped to 17.5.0): macro values with no type, function or layout behind them, which a compiled consumer never reads back. No existing declaration, default argument, inline body, enumerator or layout changes, so MESHIOPLUSPLUS_ABI_VERSION stays 30. | | 30 | v17.5.0 (unreleased vtx mesh policy) | formats/vtx.hpp | Pure additions, inside the MESHIOPLUSPLUS_HAS_ADIOS2 guard that already hides the whole header: the scoped enum VtxMeshPolicy (std::uint8_t, 1 byte, pinned in test_abi_layout.cpp), the constructor VtxSeriesWriter(const std::string&, VtxMeshPolicy) beside the unchanged explicit VtxSeriesWriter(const std::string&), and an <cstdint> include; the rest of the diff is doc-comment text (the multi-block writer and the meshio.shared_points attribute). VtxSeriesWriter keeps its single std::unique_ptr member, every member function stays out of line, and no existing declaration, default argument, inline body or enumerator changes, so MESHIOPLUSPLUS_ABI_VERSION stays 30. | | 30 | v17.6.0 | formats/vtx.hpp, version.hpp | formats/vtx.hpp is pure additions, reviewed in full in the row labelled v17.5.0 (unreleased vtx mesh policy) above: the change was made after the v17.5.0 tag while the version was still 17.5.0, so it ships unrevised here. It adds the scoped enum VtxMeshPolicy (std::uint8_t, 1 byte, pinned in test_abi_layout.cpp), the constructor VtxSeriesWriter(const std::string&, VtxMeshPolicy) beside the unchanged explicit VtxSeriesWriter(const std::string&) and an <cstdint> include; the rest of its diff is doc-comment text (the multi-block writer and the meshio.shared_points attribute). VtxSeriesWriter keeps its single std::unique_ptr member and every member function stays out of line. version.hpp is the routine release bump (macro values only: minor 5 → 6 and string "17.5.0" → "17.6.0"), as in every prior row. This row is recorded after the v17.6.0 tag was cut: the release commit carried no row for its own release, which is what tools/check-abi-version.sh reported on it. No existing declaration, default argument, inline body, enumerator or layout changes, so MESHIOPLUSPLUS_ABI_VERSION stays 30. | | 30 | v17.7.0 | version.hpp | version.hpp is the routine release bump (macro values only: minor 6 → 7 and string "17.6.0" → "17.7.0"), as in every prior row. This release carries no other installed-header change: it records the ABI 30 / v17.6.0 review the v17.6.0 release commit was missing. No existing declaration, default argument, inline body, enumerator or layout changes, so MESHIOPLUSPLUS_ABI_VERSION stays 30. | | 30 | v17.8.0 | detail/planar_skin.hpp, operations/octree.hpp, operations/voxelize.hpp, version.hpp | version.hpp is the routine release bump (macro values only, no declaration), as in every prior row. detail/planar_skin.hpp and operations/octree.hpp are entirely new headers: planar_skin.hpp declares the PlanarPlane enum, the PlanarFrame aggregate (two inline permutation members), the PlanarSkin aggregate and eight MESHIOPLUSPLUS_API free functions (planar_plane_from_name, planar_frame, collect_planar_skin, mesh_is_polyline_only, require_closed_polyline, segment_box_overlap_2d, polyline_closest_point_2d, polyline_signed_distance_2d); octree.hpp declares the OctreeBalance and OctreeTransition enums, their _from_name parsers, four name constants, the OctreeOptions/OctreeResult aggregates and octree(). OctreeOptions (304 bytes, 8-aligned) is pinned in tests/cpp/test_abi_layout.cpp from the release that introduces it, as VoxelOptions was. operations/voxelize.hpp is comment-only: the mResolution doc comment now says a zero third entry selects the 2-D pixel variant; VoxelOptions, VoxelResult, VoxelFill, grid and voxelize keep their exact declarations, layouts (216 bytes, still pinned) and default arguments, and no inline body is edited. The 2-D selection is implemented entirely in voxelize.cpp behind the unchanged signature. A consumer compiled against v17.7.0 headers links against exactly the same symbols with the same signatures and layouts -- it simply does not have the new names. The C ABI's new mio_octree_opts (176 bytes), mio_octree_report (96) and enums live in bindings/c/, outside this gate's scope and under the separate SOVERSION 0 + append-only-reserved contract; their sizes are static_asserted in c_api.cpp and mirrored by the Fortran and Julia layout guards. | | 31 | v17.10.0 | operations/primitives.hpp, version.hpp | version.hpp is the routine release bump (macro values only, no declaration), as in every prior row. operations/primitives.hpp is an entirely new header: seven free functions (rectangle, box, disk, uv_sphere, icosa_sphere, cylinder, reference_cells) taking only std::array, std::vector, std::string, int and std::int64_t arguments, with default arguments of their own. It declares no struct, enum or class, so there is no layout to pin in test_abi_layout.cpp, and it changes no existing declaration, default argument or inline body. Its functions return the existing Mesh. Strictly additive. | | 32 | v17.11.0 | operations/fit_cad.hpp | The diff is doc-comment text only: a paragraph on the freeform stage halving a patch no single B-spline follows (freeform_split). No declaration, struct member, default argument, inline body or enumerator changes, so there is no layout to pin and MESHIOPLUSPLUS_ABI_VERSION stays 32. |