From patchwork Tue Jan 13 00:07:43 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 25731 Return-Path: X-Original-To: parsemail@patchwork.libcamera.org Delivered-To: parsemail@patchwork.libcamera.org Received: from lancelot.ideasonboard.com (lancelot.ideasonboard.com [92.243.16.209]) by patchwork.libcamera.org (Postfix) with ESMTPS id 9787FC32AF for ; Tue, 13 Jan 2026 00:08:48 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 3765161FDC; Tue, 13 Jan 2026 01:08:48 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="FSV8muXB"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [IPv6:2001:4b98:dc2:55:216:3eff:fef7:d647]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 7FA1861FCC for ; Tue, 13 Jan 2026 01:08:46 +0100 (CET) Received: from pendragon.ideasonboard.com (81-175-209-152.bb.dnainternet.fi [81.175.209.152]) by perceval.ideasonboard.com (Postfix) with UTF8SMTPSA id CA019E01 for ; Tue, 13 Jan 2026 01:08:20 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1768262901; bh=G59KHYcrFik9PcmZ2gs4s2WjPMsap3MCsa/y+r88hHE=; h=From:To:Subject:Date:In-Reply-To:References:From; b=FSV8muXB2OVctKaJnc95NR3WN6Imx9LaN6f9/MecBiUQrOuMS3gAT8d7XkD4ruTLo YTtQH94PW9Gzr+XBFBHnMukuKxu/UUq6wX/F9PlFT89S7zpf+vdbKvKoH7/i022t8M HOkUz0TXC9hmVU4cn6xqj4YsYAMn9qIuSA6gzHyE= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Subject: [PATCH 11/36] libcamera: yaml_parser: Replace getList() with get() specializations Date: Tue, 13 Jan 2026 02:07:43 +0200 Message-ID: <20260113000808.15395-12-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.51.2 In-Reply-To: <20260113000808.15395-1-laurent.pinchart@ideasonboard.com> References: <20260113000808.15395-1-laurent.pinchart@ideasonboard.com> MIME-Version: 1.0 X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: libcamera-devel-bounces@lists.libcamera.org Sender: "libcamera-devel" The YamlObject class has two member function templates to get values: the get() function gets a scalar value, while the getList() function gets a vector of scalar values. As get() is a function template, we can provide specializations for vector types. This makes the code more systematic, and therefore more readable. Replace all getList() occurrences, and drop the getList() function. Signed-off-by: Laurent Pinchart --- include/libcamera/internal/yaml_parser.h | 19 ---- src/ipa/libipa/agc_mean_luminance.cpp | 4 +- src/ipa/libipa/awb_bayes.cpp | 4 +- src/ipa/mali-c55/algorithms/lsc.cpp | 6 +- src/ipa/rkisp1/algorithms/agc.cpp | 2 +- src/ipa/rkisp1/algorithms/dpf.cpp | 6 +- src/ipa/rkisp1/algorithms/gsl.cpp | 8 +- src/ipa/rkisp1/algorithms/lsc.cpp | 4 +- src/ipa/rpi/controller/rpi/agc_channel.cpp | 4 +- src/ipa/rpi/controller/rpi/hdr.cpp | 8 +- src/libcamera/converter/converter_dw100.cpp | 2 +- src/libcamera/global_configuration.cpp | 2 +- .../pipeline/virtual/config_parser.cpp | 2 +- src/libcamera/yaml_parser.cpp | 102 ++++++++---------- test/yaml-parser.cpp | 4 +- 15 files changed, 75 insertions(+), 102 deletions(-) diff --git a/include/libcamera/internal/yaml_parser.h b/include/libcamera/internal/yaml_parser.h index 0ff026706682..7953befe11e2 100644 --- a/include/libcamera/internal/yaml_parser.h +++ b/include/libcamera/internal/yaml_parser.h @@ -182,25 +182,6 @@ public: return get().value_or(std::forward(defaultValue)); } -#ifndef __DOXYGEN__ - template || - std::is_same_v || - std::is_same_v || - std::is_same_v || - std::is_same_v || - std::is_same_v || - std::is_same_v || - std::is_same_v || - std::is_same_v || - std::is_same_v || - std::is_same_v> * = nullptr> -#else - template -#endif - std::optional> getList() const; - DictAdapter asDict() const { return DictAdapter{ list_ }; } ListAdapter asList() const { return ListAdapter{ list_ }; } diff --git a/src/ipa/libipa/agc_mean_luminance.cpp b/src/ipa/libipa/agc_mean_luminance.cpp index 564d4143d363..72988096d384 100644 --- a/src/ipa/libipa/agc_mean_luminance.cpp +++ b/src/ipa/libipa/agc_mean_luminance.cpp @@ -288,9 +288,9 @@ int AgcMeanLuminance::parseExposureModes(const YamlObject &tuningData) } std::vector exposureTimes = - modeValues["exposureTime"].getList().value_or(std::vector{}); + modeValues["exposureTime"].get>().value_or(std::vector{}); std::vector gains = - modeValues["gain"].getList().value_or(std::vector{}); + modeValues["gain"].get>().value_or(std::vector{}); if (exposureTimes.size() != gains.size()) { LOG(AgcMeanLuminance, Error) diff --git a/src/ipa/libipa/awb_bayes.cpp b/src/ipa/libipa/awb_bayes.cpp index d2bcbd83d7f8..595bd0705732 100644 --- a/src/ipa/libipa/awb_bayes.cpp +++ b/src/ipa/libipa/awb_bayes.cpp @@ -211,9 +211,9 @@ int AwbBayes::readPriors(const YamlObject &tuningData) } std::vector temperatures = - p["ct"].getList().value_or(std::vector{}); + p["ct"].get>().value_or(std::vector{}); std::vector probabilities = - p["probability"].getList().value_or(std::vector{}); + p["probability"].get>().value_or(std::vector{}); if (temperatures.size() != probabilities.size()) { LOG(Awb, Error) diff --git a/src/ipa/mali-c55/algorithms/lsc.cpp b/src/ipa/mali-c55/algorithms/lsc.cpp index 5b042c757bc7..f75b9cd7b7b8 100644 --- a/src/ipa/mali-c55/algorithms/lsc.cpp +++ b/src/ipa/mali-c55/algorithms/lsc.cpp @@ -48,11 +48,11 @@ int Lsc::init([[maybe_unused]] IPAContext &context, const YamlObject &tuningData } std::vector rTable = - yamlSet["r"].getList().value_or(std::vector{}); + yamlSet["r"].get>().value_or(std::vector{}); std::vector gTable = - yamlSet["g"].getList().value_or(std::vector{}); + yamlSet["g"].get>().value_or(std::vector{}); std::vector bTable = - yamlSet["b"].getList().value_or(std::vector{}); + yamlSet["b"].get>().value_or(std::vector{}); /* * Some validation to do; only 16x16 and 32x32 tables of diff --git a/src/ipa/rkisp1/algorithms/agc.cpp b/src/ipa/rkisp1/algorithms/agc.cpp index 1ecaff680978..7cc06f91ac2b 100644 --- a/src/ipa/rkisp1/algorithms/agc.cpp +++ b/src/ipa/rkisp1/algorithms/agc.cpp @@ -55,7 +55,7 @@ int Agc::parseMeteringModes(IPAContext &context, const YamlObject &tuningData) } std::vector weights = - value.getList().value_or(std::vector{}); + value.get>().value_or(std::vector{}); if (weights.size() != context.hw.numHistogramWeights) { LOG(RkISP1Agc, Warning) << "Failed to read metering mode'" << key << "'"; diff --git a/src/ipa/rkisp1/algorithms/dpf.cpp b/src/ipa/rkisp1/algorithms/dpf.cpp index 39f3e461f313..ec989bc2421f 100644 --- a/src/ipa/rkisp1/algorithms/dpf.cpp +++ b/src/ipa/rkisp1/algorithms/dpf.cpp @@ -72,7 +72,7 @@ int Dpf::init([[maybe_unused]] IPAContext &context, * +---------|--------> X * -4....-1 0 1 2 3 4 */ - values = dFObject["g"].getList().value_or(std::vector{}); + values = dFObject["g"].get>().value_or(std::vector{}); if (values.size() != RKISP1_CIF_ISP_DPF_MAX_SPATIAL_COEFFS) { LOG(RkISP1Dpf, Error) << "Invalid 'DomainFilter:g': expected " @@ -108,7 +108,7 @@ int Dpf::init([[maybe_unused]] IPAContext &context, * For a 9x9 kernel, columns -6 and 6 are dropped, so coefficient * number 6 is not used. */ - values = dFObject["rb"].getList().value_or(std::vector{}); + values = dFObject["rb"].get>().value_or(std::vector{}); if (values.size() != RKISP1_CIF_ISP_DPF_MAX_SPATIAL_COEFFS && values.size() != RKISP1_CIF_ISP_DPF_MAX_SPATIAL_COEFFS - 1) { LOG(RkISP1Dpf, Error) @@ -137,7 +137,7 @@ int Dpf::init([[maybe_unused]] IPAContext &context, const YamlObject &rFObject = tuningData["NoiseLevelFunction"]; std::vector nllValues; - nllValues = rFObject["coeff"].getList().value_or(std::vector{}); + nllValues = rFObject["coeff"].get>().value_or(std::vector{}); if (nllValues.size() != RKISP1_CIF_ISP_DPF_MAX_NLF_COEFFS) { LOG(RkISP1Dpf, Error) << "Invalid 'RangeFilter:coeff': expected " diff --git a/src/ipa/rkisp1/algorithms/gsl.cpp b/src/ipa/rkisp1/algorithms/gsl.cpp index 9604c0ac001a..7ac5dc215850 100644 --- a/src/ipa/rkisp1/algorithms/gsl.cpp +++ b/src/ipa/rkisp1/algorithms/gsl.cpp @@ -59,7 +59,7 @@ int GammaSensorLinearization::init([[maybe_unused]] IPAContext &context, const YamlObject &tuningData) { std::vector xIntervals = - tuningData["x-intervals"].getList().value_or(std::vector{}); + tuningData["x-intervals"].get>().value_or(std::vector{}); if (xIntervals.size() != kDegammaXIntervals) { LOG(RkISP1Gsl, Error) << "Invalid 'x' coordinates: expected " @@ -83,7 +83,7 @@ int GammaSensorLinearization::init([[maybe_unused]] IPAContext &context, return -EINVAL; } - curveYr_ = yObject["red"].getList().value_or(std::vector{}); + curveYr_ = yObject["red"].get>().value_or(std::vector{}); if (curveYr_.size() != RKISP1_CIF_ISP_DEGAMMA_CURVE_SIZE) { LOG(RkISP1Gsl, Error) << "Invalid 'y:red' coordinates: expected " @@ -92,7 +92,7 @@ int GammaSensorLinearization::init([[maybe_unused]] IPAContext &context, return -EINVAL; } - curveYg_ = yObject["green"].getList().value_or(std::vector{}); + curveYg_ = yObject["green"].get>().value_or(std::vector{}); if (curveYg_.size() != RKISP1_CIF_ISP_DEGAMMA_CURVE_SIZE) { LOG(RkISP1Gsl, Error) << "Invalid 'y:green' coordinates: expected " @@ -101,7 +101,7 @@ int GammaSensorLinearization::init([[maybe_unused]] IPAContext &context, return -EINVAL; } - curveYb_ = yObject["blue"].getList().value_or(std::vector{}); + curveYb_ = yObject["blue"].get>().value_or(std::vector{}); if (curveYb_.size() != RKISP1_CIF_ISP_DEGAMMA_CURVE_SIZE) { LOG(RkISP1Gsl, Error) << "Invalid 'y:blue' coordinates: expected " diff --git a/src/ipa/rkisp1/algorithms/lsc.cpp b/src/ipa/rkisp1/algorithms/lsc.cpp index e7301bfec863..429565a0b51f 100644 --- a/src/ipa/rkisp1/algorithms/lsc.cpp +++ b/src/ipa/rkisp1/algorithms/lsc.cpp @@ -252,7 +252,7 @@ private: RKISP1_CIF_ISP_LSC_SAMPLES_MAX * RKISP1_CIF_ISP_LSC_SAMPLES_MAX; std::vector table = - tuningData[prop].getList().value_or(std::vector{}); + tuningData[prop].get>().value_or(std::vector{}); if (table.size() != kLscNumSamples) { LOG(RkISP1Lsc, Error) << "Invalid '" << prop << "' values: expected " @@ -269,7 +269,7 @@ static std::vector parseSizes(const YamlObject &tuningData, const char *prop) { std::vector sizes = - tuningData[prop].getList().value_or(std::vector{}); + tuningData[prop].get>().value_or(std::vector{}); if (sizes.size() != RKISP1_CIF_ISP_LSC_SECTORS_TBL_SIZE) { LOG(RkISP1Lsc, Error) << "Invalid '" << prop << "' values: expected " diff --git a/src/ipa/rpi/controller/rpi/agc_channel.cpp b/src/ipa/rpi/controller/rpi/agc_channel.cpp index 154551dfacc2..c6cf1f8903f1 100644 --- a/src/ipa/rpi/controller/rpi/agc_channel.cpp +++ b/src/ipa/rpi/controller/rpi/agc_channel.cpp @@ -66,13 +66,13 @@ readMeteringModes(std::map &metering_modes, int AgcExposureMode::read(const libcamera::YamlObject ¶ms) { - auto value = params["shutter"].getList(); + auto value = params["shutter"].get>(); if (!value) return -EINVAL; std::transform(value->begin(), value->end(), std::back_inserter(exposureTime), [](double v) { return v * 1us; }); - value = params["gain"].getList(); + value = params["gain"].get>(); if (!value) return -EINVAL; gain = std::move(*value); diff --git a/src/ipa/rpi/controller/rpi/hdr.cpp b/src/ipa/rpi/controller/rpi/hdr.cpp index f3da8291bf5d..06400ea79a95 100644 --- a/src/ipa/rpi/controller/rpi/hdr.cpp +++ b/src/ipa/rpi/controller/rpi/hdr.cpp @@ -29,7 +29,7 @@ void HdrConfig::read(const libcamera::YamlObject ¶ms, const std::string &mod if (!params.contains("cadence")) LOG(RPiHdr, Fatal) << "No cadence for HDR mode " << name; - cadence = params["cadence"].getList().value(); + cadence = params["cadence"].get>().value(); if (cadence.empty()) LOG(RPiHdr, Fatal) << "Empty cadence in HDR mode " << name; @@ -69,14 +69,14 @@ void HdrConfig::read(const libcamera::YamlObject ¶ms, const std::string &mod tonemap = params["tonemap"].get(ipa::Pwl{}); speed = params["speed"].get(1.0); if (params.contains("hi_quantile_targets")) { - hiQuantileTargets = params["hi_quantile_targets"].getList().value(); + hiQuantileTargets = params["hi_quantile_targets"].get>().value(); if (hiQuantileTargets.empty() || hiQuantileTargets.size() % 2) LOG(RPiHdr, Fatal) << "hi_quantile_targets much be even and non-empty"; } else hiQuantileTargets = { 0.95, 0.65, 0.5, 0.28, 0.3, 0.25 }; hiQuantileMaxGain = params["hi_quantile_max_gain"].get(1.6); if (params.contains("quantile_targets")) { - quantileTargets = params["quantile_targets"].getList().value(); + quantileTargets = params["quantile_targets"].get>().value(); if (quantileTargets.empty() || quantileTargets.size() % 2) LOG(RPiHdr, Fatal) << "quantile_targets much be even and non-empty"; } else @@ -84,7 +84,7 @@ void HdrConfig::read(const libcamera::YamlObject ¶ms, const std::string &mod powerMin = params["power_min"].get(0.65); powerMax = params["power_max"].get(1.0); if (params.contains("contrast_adjustments")) { - contrastAdjustments = params["contrast_adjustments"].getList().value(); + contrastAdjustments = params["contrast_adjustments"].get>().value(); } else contrastAdjustments = { 0.5, 0.75 }; diff --git a/src/libcamera/converter/converter_dw100.cpp b/src/libcamera/converter/converter_dw100.cpp index df5155cfdc93..5782cd0b21b7 100644 --- a/src/libcamera/converter/converter_dw100.cpp +++ b/src/libcamera/converter/converter_dw100.cpp @@ -126,7 +126,7 @@ int ConverterDW100Module::init(const YamlObject ¶ms) return -EINVAL; } - const auto coeffs = coefficients.getList(); + const auto coeffs = coefficients.get>(); if (!coeffs) { LOG(Converter, Error) << "Dewarp parameters 'coefficients' value is not a list"; return -EINVAL; diff --git a/src/libcamera/global_configuration.cpp b/src/libcamera/global_configuration.cpp index e086246d6856..99d16e7c38c6 100644 --- a/src/libcamera/global_configuration.cpp +++ b/src/libcamera/global_configuration.cpp @@ -152,7 +152,7 @@ std::optional> GlobalConfiguration::listOption( if (!*c) return {}; } - return c->getList(); + return c->get>(); } /** diff --git a/src/libcamera/pipeline/virtual/config_parser.cpp b/src/libcamera/pipeline/virtual/config_parser.cpp index 1d3d9ba87ec0..fdc729509371 100644 --- a/src/libcamera/pipeline/virtual/config_parser.cpp +++ b/src/libcamera/pipeline/virtual/config_parser.cpp @@ -115,7 +115,7 @@ int ConfigParser::parseSupportedFormats(const YamlObject &cameraConfigData, std::vector frameRates; if (supportedResolution.contains("frame_rates")) { auto frameRatesList = - supportedResolution["frame_rates"].getList(); + supportedResolution["frame_rates"].get>(); if (!frameRatesList || (frameRatesList->size() != 1 && frameRatesList->size() != 2)) { LOG(Virtual, Error) << "Invalid frame_rates: either one or two values"; diff --git a/src/libcamera/yaml_parser.cpp b/src/libcamera/yaml_parser.cpp index a21e589fdd86..2b3723287051 100644 --- a/src/libcamera/yaml_parser.cpp +++ b/src/libcamera/yaml_parser.cpp @@ -109,12 +109,16 @@ std::size_t YamlObject::size() const /** * \fn template YamlObject::get() const + * \tparam T Type of the value * \brief Parse the YamlObject as a \a T value * * This function parses the value of the YamlObject as a \a T object, and * returns the value. If parsing fails (usually because the YamlObject doesn't * store a \a T value), std::nullopt is returned. * + * If the type \a T is an std::vector, the YamlObject will be parsed as a list + * of values. + * * \return The YamlObject value, or std::nullopt if parsing failed */ @@ -127,6 +131,9 @@ std::size_t YamlObject::size() const * returns the value. If parsing fails (usually because the YamlObject doesn't * store a \a T value), the \a defaultValue is returned. * + * Unlike the get() function, this overload does not support std::vector for the + * type \a T. + * * \return The YamlObject value, or \a defaultValue if parsing failed */ @@ -239,65 +246,50 @@ YamlObject::Accessor::get(const YamlObject &obj) const return Size(*width, *height); } -#endif /* __DOXYGEN__ */ - -/** - * \fn template YamlObject::getList() const - * \brief Parse the YamlObject as a list of \a T - * - * This function parses the value of the YamlObject as a list of \a T objects, - * and returns the value as a \a std::vector. If parsing fails, std::nullopt - * is returned. - * - * \return The YamlObject value as a std::vector, or std::nullopt if parsing - * failed - */ - -#ifndef __DOXYGEN__ - -template || - std::is_same_v || - std::is_same_v || - std::is_same_v || - std::is_same_v || - std::is_same_v || - std::is_same_v || - std::is_same_v || - std::is_same_v || - std::is_same_v || - std::is_same_v> *> -std::optional> YamlObject::getList() const +template +struct YamlObject::Accessor, std::enable_if_t< + std::is_same_v || + std::is_same_v || + std::is_same_v || + std::is_same_v || + std::is_same_v || + std::is_same_v || + std::is_same_v || + std::is_same_v || + std::is_same_v || + std::is_same_v || + std::is_same_v>> { - if (type_ != Type::List) - return std::nullopt; - - std::vector values; - values.reserve(list_.size()); - - for (const YamlObject &entry : asList()) { - const auto value = entry.get(); - if (!value) + std::optional> get(const YamlObject &obj) const + { + if (obj.type_ != Type::List) return std::nullopt; - values.emplace_back(*value); + + std::vector values; + values.reserve(obj.list_.size()); + + for (const YamlObject &entry : obj.asList()) { + const auto value = entry.get(); + if (!value) + return std::nullopt; + values.emplace_back(*value); + } + + return values; } +}; - return values; -} - -template std::optional> YamlObject::getList() const; -template std::optional> YamlObject::getList() const; -template std::optional> YamlObject::getList() const; -template std::optional> YamlObject::getList() const; -template std::optional> YamlObject::getList() const; -template std::optional> YamlObject::getList() const; -template std::optional> YamlObject::getList() const; -template std::optional> YamlObject::getList() const; -template std::optional> YamlObject::getList() const; -template std::optional> YamlObject::getList() const; -template std::optional> YamlObject::getList() const; - +template struct YamlObject::Accessor>; +template struct YamlObject::Accessor>; +template struct YamlObject::Accessor>; +template struct YamlObject::Accessor>; +template struct YamlObject::Accessor>; +template struct YamlObject::Accessor>; +template struct YamlObject::Accessor>; +template struct YamlObject::Accessor>; +template struct YamlObject::Accessor>; +template struct YamlObject::Accessor>; +template struct YamlObject::Accessor>; #endif /* __DOXYGEN__ */ /** diff --git a/test/yaml-parser.cpp b/test/yaml-parser.cpp index 1b22c87b72f1..566401afcab6 100644 --- a/test/yaml-parser.cpp +++ b/test/yaml-parser.cpp @@ -587,9 +587,9 @@ protected: return TestFail; } - const auto &values = firstElement.getList(); + const auto &values = firstElement.get>(); if (!values || values->size() != 2 || (*values)[0] != 1 || (*values)[1] != 2) { - cerr << "getList() failed to return correct vector" << std::endl; + cerr << "get() failed to return correct vector" << std::endl; return TestFail; }