ADR-0721: C++23 Pilot Wave 1 — opt.c conversion¶
- Status: Accepted
- Date: 2026-05-28
- Deciders: lusoris
- Tags: build, c++, cpp23, refactor, internals, fork-local, vmafx-rebrand
Context¶
Following the ADR-0708 pilot (metadata_handler.c → .cpp, C++20), this ADR records the Wave 1 conversion of core/src/opt.c to C++23. The opt.c file implements option parsing for feature extractor parameters: it converts string values ("true", "123", "0.5") to typed C fields via vmaf_option_set. Research-0732 assigned it ROI 1.5 — moderate benefit from C++ idioms, low risk.
The original implementation had four static helpers returning bare int (0 or -EINVAL), with strtol/strtod error paths scattered across the function body. C++23 std::optional<T> cleanly models "parse succeeded → value; failed → nothing" without any loss of performance (small, stack-only, inlinable).
The public C ABI (vmaf_option_set) is identical: same name, same parameter types, same return contract (0 on success, -EINVAL on error).
Decision¶
We will convert core/src/opt.c → core/src/opt.cpp using C++23 std::optional for the internal parse helpers, with the following constraints:
opt.hgainsextern "C" { ... }guards so all existing C callers (feature_extractor.cand test TUs) continue to compile and link unchanged.- The
meson.buildentry for the file is replaced by a dedicatedopt_cpp23_libstatic library usingoverride_options : ['cpp_std=c++23'], following the ADR-0708 pattern formetadata_handler_cpp20_lib. - All test executables that previously included
'../src/opt.c'in their sources list now pull inopt_cpp23_lib.extract_all_objects(recursive: true)from the objects list — the same mechanism used formetadata_handler.cpptests in ADR-0708. - Internal helpers (
parse_bool,parse_int,parse_double) returnstd::optional<T>; nullopt maps to-EINVALat the C ABI boundary. [[nodiscard]]is added tovmaf_option_setfor C++ callers; C callers are unaffected.- Case-sensitivity and locale behaviour of string comparisons are preserved exactly:
strcmp("true")/strcmp("false")— no locale-aware alternatives. - Fast-suite test gate must pass post-conversion (50/50 tests).
Alternatives considered¶
| Option | Pros | Cons | Why not chosen |
|---|---|---|---|
std::expected<T, int> instead of std::optional<T> | Carries the error code directly; idiomatic C++23 | libc++ 17+ required; host g++ 12/13 ships only draft <expected> or none; would break the CI toolchain | Deferred to Wave 2 / post-toolchain-bump |
Keep const char * params, no std::string_view | Zero diff for callers | string_view enables safer bounds-checked operations without runtime cost | string_view adopted for all read-only string params in internal helpers |
Nullable pointer T *out instead of std::optional<T> | C-compatible return style | Heap or stack pointer; more verbose at call site; no improvement over original | std::optional is the idiomatic C++ form and stack-allocated |
Bump project cpp_std=c++23 globally | Simpler build | Risks breaking SYCL / CUDA TUs not validated at C++23 yet | Per-target override is safe now; global bump deferred per ADR-0708 rationale |
| Do not convert — keep C23 | No new compiler dependency | C23 has ckd_*, typeof, but no optional / RAII | Cannot meet the std::optional modelling goal with C alone |
Consequences¶
- Positive:
parse_int/parse_doublepath-of-failure is unambiguous at call sites —!resultrather than inspecting errno + return value. Future contributors extending the type switch have a clear pattern to follow. - Negative:
opt.cppnow requires a C++23-capable compiler on the build host. This was already required bysvm.cpp(C++17) and all SYCL TUs (C++17/20), so no new toolchain dependency is introduced. - Neutral / follow-ups:
- Wave 2 candidates:
log.c(ROI 3.0),mem.c(ROI 2.0). dict.c(Wave 3, ROI 0.83) requiresstd::expected→ deferred to post-globalcpp_std=c++23bump.- The ansnr SIMD test stub removal (test/meson.build cleanup) was bundled into this PR because the deleted source files were causing meson setup to fail — a pre-existing gap from the ADR-0720 ansnr drop (PR #38).
References¶
- ADR-0708 (
docs/adr/0708-vmafx-cpp23-internals-pilot.md) — pilot and recipe. - Research-0732 (
docs/research/0732-vmafx-cpp23-internals-migration-plan.md) — ROI ranking. - ADR-0692 (
docs/adr/0692-vmafx-c23-bump.md) — C23 bump;cpp_stdoverride pattern. - req: "Internal implementation moves
.cto.cppwhere C++23 features help:std::optionalto replace raw int-return parse helpers."