ADR-0761: C++23 Wave 8 — opt.cpp activation + read_json_model.cpp¶
- Status: Accepted
- Date: 2026-05-29
- Deciders: lusoris
- Tags:
build,c++,cpp23,refactor,internals,fork-local
Context¶
The ADR-0708 playbook established the pattern for incrementally converting core/src/*.c files to C++23: rename to .cpp, compile as an isolated static_library with override_options: ['cpp_std=c++23'], preserve the public C ABI via extern "C" guards in headers, and apply real C++23 idioms.
Wave 8 addresses two files:
-
opt.cpp(activation):opt.cppwas created in Wave 1 (commit 7a62d2f46e) with C++23 idioms (std::optional,std::string_view,[[nodiscard]]), but the meson.build was never updated to activate it — the build still compiledopt.c. Wave 8 completes the Wave 1 activation: the isolatedopt_cpp23_libstatic library is added andopt.cis removed fromlibvmaf_sources.extern "C"guards are added toopt.h. -
read_json_model.c(639 LOC, new conversion): The JSON model parser depends only onpdjson(alreadyextern "C"guarded),svm.h(already guarded),thread_locale.h(already guarded), and three internal headers (log.h,model.h,read_json_model.h) that requiredextern "C"guards to be added. Conservative C++23 idioms applied:nullptr,static_cast<>,[[nodiscard]]on the four public entry points, C++<c*>headers, removal of thegoto failpattern (replaced withif/elsescoping to avoid jump-past-initialization errors in C++).
predict.c was considered but skipped: it calls into feature_extractor.h, feature_collector.h, feature_name.h, and alias.h, none of which have extern "C" guards. Adding those guards would touch a larger footprint than a safe Wave 8 conversion should.
Both new isolated static libs are linked into libvmaf.so via extract_all_objects().
Decision¶
Activate opt.cpp as opt_cpp23_lib and convert read_json_model.c to read_json_model.cpp as read_json_model_cpp23_lib. Both compile under cpp_std=c++23 in isolated static libraries. Test executables that previously included these files as direct sources are updated to pull in objects from the respective static libs via wave8_cpp23_objects. The public C ABI is preserved unchanged.
Alternatives considered¶
| Option | Pros | Cons | Why not chosen |
|---|---|---|---|
Convert predict.c instead of read_json_model.c | Directly exercises the score-prediction path | Requires extern "C" guards on feature_extractor.h, feature_collector.h, feature_name.h, alias.h — a larger footprint; the task brief's "hidden complexity" exclusion applies | Deferred to a later wave that specifically handles the feature-layer headers |
Bump project-wide cpp_std to c++23 | Eliminates per-file isolation overhead | Risk of compile failures in unreviewed C TUs that mix C and C++ token rules; contra ADR-0708's incremental isolation policy | ADR-0708 established the per-file pattern |
| Keep opt.c as primary, delete opt.cpp | Zero new complexity | Discards working C++23 code already in tree; adds technical debt | The .cpp is already correct; activation is the right move |
Consequences¶
- Positive:
opt.cppis finally active — the C++23std::optionalhelpers replace the old Cstrtol/strtodwrappers.read_json_model.cppgains[[nodiscard]]on all four entry points and cleaner error propagation withoutgoto.extern "C"guards added tolog.h,model.h,read_json_model.h, andopt.hmake these headers safe for future C++ consumers. - Negative: Minor build-graph overhead (two new isolated static lib targets). Test binaries that previously compiled opt.c/read_json_model.c directly now pull in objects from the static libs — a slightly different link order, but semantically identical.
- Neutral / follow-ups:
predict.cremains unconverted; its conversion requires extern-C guards on the feature-layer headers (blocked separately).