Message ID | 20220727023816.30008-2-laurent.pinchart@ideasonboard.com |
---|---|
State | Accepted |
Headers | show |
Series |
|
Related | show |
Hi Laurent, Thank you for your patch. On Wed, 27 Jul 2022 at 03:38, Laurent Pinchart < laurent.pinchart@ideasonboard.com> wrote: > The YamlObject::get() function takes a default value and an optional > bool ok flag to handle parsing errors. This ad-hoc mechanism complicates > error handling in callers. > > A better API is possible by dropping the default value and ok flag and > returning an std::optional. Not only does it simplify the calls, it also > lets callers handle errors through the standard std::optional class > instead of the current ad-hoc mechanism. > > Provide a convenience get() wrapper around std::optional::value_or() to > further simplify callers that don't need any specific error handling. > s/convenience/convenient/ ? > Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com> > This is much cleaner for error handling! Reviewed-by: Naushir Patuck <naush@raspberrypi.com> > --- > include/libcamera/internal/yaml_parser.h | 9 +- > src/libcamera/yaml_parser.cpp | 138 +++++++++-------------- > test/yaml-parser.cpp | 71 ++++++------ > 3 files changed, 96 insertions(+), 122 deletions(-) > > diff --git a/include/libcamera/internal/yaml_parser.h > b/include/libcamera/internal/yaml_parser.h > index 064cf44381d7..61f2223223a7 100644 > --- a/include/libcamera/internal/yaml_parser.h > +++ b/include/libcamera/internal/yaml_parser.h > @@ -9,6 +9,7 @@ > > #include <iterator> > #include <map> > +#include <optional> > #include <string> > #include <vector> > > @@ -165,7 +166,13 @@ public: > #else > template<typename T> > #endif > - T get(const T &defaultValue, bool *ok = nullptr) const; > + std::optional<T> get() const; > + > + template<typename T> > + T get(const T &defaultValue) const > + { > + return get<T>().value_or(defaultValue); > + } > > DictAdapter asDict() const { return DictAdapter{ dictionary_ }; } > ListAdapter asList() const { return ListAdapter{ list_ }; } > diff --git a/src/libcamera/yaml_parser.cpp b/src/libcamera/yaml_parser.cpp > index 5c45e44e49c3..4299f5abd38a 100644 > --- a/src/libcamera/yaml_parser.cpp > +++ b/src/libcamera/yaml_parser.cpp > @@ -31,12 +31,6 @@ namespace { > /* Empty static YamlObject as a safe result for invalid operations */ > static const YamlObject empty; > > -void setOk(bool *ok, bool result) > -{ > - if (ok) > - *ok = result; > -} > - > } /* namespace */ > > /** > @@ -100,54 +94,52 @@ std::size_t YamlObject::size() const > } > > /** > - * \fn template<typename T> YamlObject::get<T>( > - * const T &defaultValue, bool *ok) const > + * \fn template<typename T> YamlObject::get<T>() const > + * \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. > + * > + * \return The YamlObject value, or std::nullopt if parsing failed > + */ > + > +/** > + * \fn template<typename T> YamlObject::get<T>(const T &defaultValue) > const > * \brief Parse the YamlObject as a \a T value > * \param[in] defaultValue The default value when failing to parse > - * \param[out] ok The result of whether the parse succeeded > * > * 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), the \a defaultValue is returned, and \a ok is set > to > - * false. Otherwise, the YamlObject value is returned, and \a ok is set > to true. > + * store a \a T value), the \a defaultValue is returned. > * > - * The \a ok pointer is optional and can be a nullptr if the caller > doesn't > - * need to know if parsing succeeded. > - * > - * \return Value as a bool type > + * \return The YamlObject value, or \a defaultValue if parsing failed > */ > > #ifndef __DOXYGEN__ > > template<> > -bool YamlObject::get(const bool &defaultValue, bool *ok) const > +std::optional<bool> YamlObject::get() const > { > - setOk(ok, false); > - > if (type_ != Type::Value) > - return defaultValue; > + return {}; > > - if (value_ == "true") { > - setOk(ok, true); > + if (value_ == "true") > return true; > - } else if (value_ == "false") { > - setOk(ok, true); > + else if (value_ == "false") > return false; > - } > > - return defaultValue; > + return {}; > } > > template<> > -int16_t YamlObject::get(const int16_t &defaultValue, bool *ok) const > +std::optional<int16_t> YamlObject::get() const > { > - setOk(ok, false); > - > if (type_ != Type::Value) > - return defaultValue; > + return {}; > > if (value_ == "") > - return defaultValue; > + return {}; > > char *end; > > @@ -157,22 +149,19 @@ int16_t YamlObject::get(const int16_t &defaultValue, > bool *ok) const > if ('\0' != *end || errno == ERANGE || > value < std::numeric_limits<int16_t>::min() || > value > std::numeric_limits<int16_t>::max()) > - return defaultValue; > + return {}; > > - setOk(ok, true); > return value; > } > > template<> > -uint16_t YamlObject::get(const uint16_t &defaultValue, bool *ok) const > +std::optional<uint16_t> YamlObject::get() const > { > - setOk(ok, false); > - > if (type_ != Type::Value) > - return defaultValue; > + return {}; > > if (value_ == "") > - return defaultValue; > + return {}; > > /* > * libyaml parses all scalar values as strings. When a string has > @@ -183,7 +172,7 @@ uint16_t YamlObject::get(const uint16_t &defaultValue, > bool *ok) const > */ > std::size_t found = value_.find_first_not_of(" \t"); > if (found != std::string::npos && value_[found] == '-') > - return defaultValue; > + return {}; > > char *end; > > @@ -193,22 +182,19 @@ uint16_t YamlObject::get(const uint16_t > &defaultValue, bool *ok) const > if ('\0' != *end || errno == ERANGE || > value < std::numeric_limits<uint16_t>::min() || > value > std::numeric_limits<uint16_t>::max()) > - return defaultValue; > + return {}; > > - setOk(ok, true); > return value; > } > > template<> > -int32_t YamlObject::get(const int32_t &defaultValue, bool *ok) const > +std::optional<int32_t> YamlObject::get() const > { > - setOk(ok, false); > - > if (type_ != Type::Value) > - return defaultValue; > + return {}; > > if (value_ == "") > - return defaultValue; > + return {}; > > char *end; > > @@ -218,22 +204,19 @@ int32_t YamlObject::get(const int32_t &defaultValue, > bool *ok) const > if ('\0' != *end || errno == ERANGE || > value < std::numeric_limits<int32_t>::min() || > value > std::numeric_limits<int32_t>::max()) > - return defaultValue; > + return {}; > > - setOk(ok, true); > return value; > } > > template<> > -uint32_t YamlObject::get(const uint32_t &defaultValue, bool *ok) const > +std::optional<uint32_t> YamlObject::get() const > { > - setOk(ok, false); > - > if (type_ != Type::Value) > - return defaultValue; > + return {}; > > if (value_ == "") > - return defaultValue; > + return {}; > > /* > * libyaml parses all scalar values as strings. When a string has > @@ -244,7 +227,7 @@ uint32_t YamlObject::get(const uint32_t &defaultValue, > bool *ok) const > */ > std::size_t found = value_.find_first_not_of(" \t"); > if (found != std::string::npos && value_[found] == '-') > - return defaultValue; > + return {}; > > char *end; > > @@ -254,22 +237,19 @@ uint32_t YamlObject::get(const uint32_t > &defaultValue, bool *ok) const > if ('\0' != *end || errno == ERANGE || > value < std::numeric_limits<uint32_t>::min() || > value > std::numeric_limits<uint32_t>::max()) > - return defaultValue; > + return {}; > > - setOk(ok, true); > return value; > } > > template<> > -double YamlObject::get(const double &defaultValue, bool *ok) const > +std::optional<double> YamlObject::get() const > { > - setOk(ok, false); > - > if (type_ != Type::Value) > - return defaultValue; > + return {}; > > if (value_ == "") > - return defaultValue; > + return {}; > > char *end; > > @@ -277,50 +257,38 @@ double YamlObject::get(const double &defaultValue, > bool *ok) const > double value = std::strtod(value_.c_str(), &end); > > if ('\0' != *end || errno == ERANGE) > - return defaultValue; > + return {}; > > - setOk(ok, true); > return value; > } > > template<> > -std::string YamlObject::get(const std::string &defaultValue, bool *ok) > const > +std::optional<std::string> YamlObject::get() const > { > - setOk(ok, false); > - > if (type_ != Type::Value) > - return defaultValue; > + return {}; > > - setOk(ok, true); > return value_; > } > > template<> > -Size YamlObject::get(const Size &defaultValue, bool *ok) const > +std::optional<Size> YamlObject::get() const > { > - setOk(ok, false); > - > if (type_ != Type::List) > - return defaultValue; > + return {}; > > if (list_.size() != 2) > - return defaultValue; > + return {}; > > - /* > - * Add a local variable to validate each dimension in case > - * that ok == nullptr. > - */ > - bool valid; > - uint32_t width = list_[0]->get<uint32_t>(0, &valid); > - if (!valid) > - return defaultValue; > + auto width = list_[0]->get<uint32_t>(); > + if (!width) > + return {}; > > - uint32_t height = list_[1]->get<uint32_t>(0, &valid); > - if (!valid) > - return defaultValue; > + auto height = list_[1]->get<uint32_t>(); > + if (!height) > + return {}; > > - setOk(ok, true); > - return Size(width, height); > + return Size(*width, *height); > } > > #endif /* __DOXYGEN__ */ > diff --git a/test/yaml-parser.cpp b/test/yaml-parser.cpp > index 38f848232fa6..ebb654f2ef9c 100644 > --- a/test/yaml-parser.cpp > +++ b/test/yaml-parser.cpp > @@ -148,7 +148,6 @@ protected: > } > > /* Test string object */ > - bool ok; > auto &strObj = (*root)["string"]; > > if (strObj.isDictionary()) { > @@ -161,27 +160,27 @@ protected: > return TestFail; > } > > - if (strObj.get<string>("", &ok) != "libcamera" || !ok) { > + if (strObj.get<string>().value_or("") != "libcamera") { > cerr << "String object parse as wrong content" << > std::endl; > return TestFail; > } > > - if (strObj.get<int32_t>(-1, &ok) != -1 || ok) { > + if (strObj.get<int32_t>()) { > cerr << "String object parse as integer" << > std::endl; > return TestFail; > } > > - if (strObj.get<uint32_t>(1, &ok) != 1 || ok) { > + if (strObj.get<uint32_t>()) { > cerr << "String object parse as unsigned integer" > << std::endl; > return TestFail; > } > > - if (strObj.get<double>(1.0, &ok) != 1.0 || ok) { > + if (strObj.get<double>()) { > cerr << "String object parse as double" << > std::endl; > return TestFail; > } > > - if (strObj.get<Size>(Size(0, 0), &ok) != Size(0, 0) || ok) > { > + if (strObj.get<Size>()) { > cerr << "String object parse as Size" << std::endl; > return TestFail; > } > @@ -199,27 +198,27 @@ protected: > return TestFail; > } > > - if (int32Obj.get<int32_t>(-100, &ok) != -100 || !ok) { > + if (int32Obj.get<int32_t>().value_or(0) != -100) { > cerr << "Integer object parse as wrong value" << > std::endl; > return TestFail; > } > > - if (int32Obj.get<string>("", &ok) != "-100" || !ok) { > + if (int32Obj.get<string>().value_or("") != "-100") { > cerr << "Integer object fail to parse as string" > << std::endl; > return TestFail; > } > > - if (int32Obj.get<double>(1.0, &ok) != -100.0 || !ok) { > + if (int32Obj.get<double>().value_or(0.0) != -100.0) { > cerr << "Integer object fail to parse as double" > << std::endl; > return TestFail; > } > > - if (int32Obj.get<uint32_t>(1, &ok) != 1 || ok) { > + if (int32Obj.get<uint32_t>()) { > cerr << "Negative integer object parse as unsigned > integer" << std::endl; > return TestFail; > } > > - if (int32Obj.get<Size>(Size(0, 0), &ok) != Size(0, 0) || > ok) { > + if (int32Obj.get<Size>()) { > cerr << "Integer object parse as Size" << > std::endl; > return TestFail; > } > @@ -237,27 +236,27 @@ protected: > return TestFail; > } > > - if (uint32Obj.get<int32_t>(-1, &ok) != 100 || !ok) { > + if (uint32Obj.get<int32_t>().value_or(0) != 100) { > cerr << "Unsigned integer object fail to parse as > integer" << std::endl; > return TestFail; > } > > - if (uint32Obj.get<string>("", &ok) != "100" || !ok) { > + if (uint32Obj.get<string>().value_or("") != "100") { > cerr << "Unsigned integer object fail to parse as > string" << std::endl; > return TestFail; > } > > - if (uint32Obj.get<double>(1.0, &ok) != 100.0 || !ok) { > + if (uint32Obj.get<double>().value_or(0.0) != 100.0) { > cerr << "Unsigned integer object fail to parse as > double" << std::endl; > return TestFail; > } > > - if (uint32Obj.get<uint32_t>(100, &ok) != 100 || !ok) { > + if (uint32Obj.get<uint32_t>().value_or(0) != 100) { > cerr << "Unsigned integer object parsed as wrong > value" << std::endl; > return TestFail; > } > > - if (uint32Obj.get<Size>(Size(0, 0), &ok) != Size(0, 0) || > ok) { > + if (uint32Obj.get<Size>()) { > cerr << "Unsigned integer object parsed as Size" > << std::endl; > return TestFail; > } > @@ -275,27 +274,27 @@ protected: > return TestFail; > } > > - if (doubleObj.get<string>("", &ok) != "3.14159" || !ok) { > + if (doubleObj.get<string>().value_or("") != "3.14159") { > cerr << "Double object fail to parse as string" << > std::endl; > return TestFail; > } > > - if (doubleObj.get<double>(1.0, &ok) != 3.14159 || !ok) { > + if (doubleObj.get<double>().value_or(0.0) != 3.14159) { > cerr << "Double object parse as wrong value" << > std::endl; > return TestFail; > } > > - if (doubleObj.get<int32_t>(-1, &ok) != -1 || ok) { > + if (doubleObj.get<int32_t>()) { > cerr << "Double object parse as integer" << > std::endl; > return TestFail; > } > > - if (doubleObj.get<uint32_t>(1, &ok) != 1 || ok) { > + if (doubleObj.get<uint32_t>()) { > cerr << "Double object parse as unsigned integer" > << std::endl; > return TestFail; > } > > - if (doubleObj.get<Size>(Size(0, 0), &ok) != Size(0, 0) || > ok) { > + if (doubleObj.get<Size>()) { > cerr << "Double object parse as Size" << std::endl; > return TestFail; > } > @@ -313,27 +312,27 @@ protected: > return TestFail; > } > > - if (sizeObj.get<string>("", &ok) != "" || ok) { > + if (sizeObj.get<string>()) { > cerr << "Size object parse as string" << std::endl; > return TestFail; > } > > - if (sizeObj.get<double>(1.0, &ok) != 1.0 || ok) { > + if (sizeObj.get<double>()) { > cerr << "Size object parse as double" << std::endl; > return TestFail; > } > > - if (sizeObj.get<int32_t>(-1, &ok) != -1 || ok) { > + if (sizeObj.get<int32_t>()) { > cerr << "Size object parse as integer" << > std::endl; > return TestFail; > } > > - if (sizeObj.get<uint32_t>(1, &ok) != 1 || ok) { > + if (sizeObj.get<uint32_t>()) { > cerr << "Size object parse as unsigned integer" << > std::endl; > return TestFail; > } > > - if (sizeObj.get<Size>(Size(0, 0), &ok) != Size(1920, 1080) > || !ok) { > + if (sizeObj.get<Size>().value_or(Size(0, 0)) != Size(1920, > 1080)) { > cerr << "Size object parse as wrong value" << > std::endl; > return TestFail; > } > @@ -351,27 +350,27 @@ protected: > return TestFail; > } > > - if (listObj.get<string>("", &ok) != "" || ok) { > + if (listObj.get<string>()) { > cerr << "List object parse as string" << std::endl; > return TestFail; > } > > - if (listObj.get<double>(1.0, &ok) != 1.0 || ok) { > + if (listObj.get<double>()) { > cerr << "List object parse as double" << std::endl; > return TestFail; > } > > - if (listObj.get<int32_t>(-1, &ok) != -1 || ok) { > + if (listObj.get<int32_t>()) { > cerr << "List object parse as integer" << > std::endl; > return TestFail; > } > > - if (listObj.get<uint32_t>(1, &ok) != 1 || ok) { > + if (listObj.get<uint32_t>()) { > cerr << "List object parse as unsigne integer" << > std::endl; > return TestFail; > } > > - if (listObj.get<Size>(Size(0, 0), &ok) != Size(0, 0) || > ok) { > + if (listObj.get<Size>()) { > cerr << "String list object parse as Size" << > std::endl; > return TestFail; > } > @@ -424,27 +423,27 @@ protected: > return TestFail; > } > > - if (dictObj.get<string>("", &ok) != "" || ok) { > + if (dictObj.get<string>()) { > cerr << "Dictionary object parse as string" << > std::endl; > return TestFail; > } > > - if (dictObj.get<double>(1.0, &ok) != 1.0 || ok) { > + if (dictObj.get<double>()) { > cerr << "Dictionary object parse as double" << > std::endl; > return TestFail; > } > > - if (dictObj.get<int32_t>(-1, &ok) != -1 || ok) { > + if (dictObj.get<int32_t>()) { > cerr << "Dictionary object parse as integer" << > std::endl; > return TestFail; > } > > - if (dictObj.get<uint32_t>(1, &ok) != 1 || ok) { > + if (dictObj.get<uint32_t>()) { > cerr << "Dictionary object parse as unsigned > integer" << std::endl; > return TestFail; > } > > - if (dictObj.get<Size>(Size(0, 0), &ok) != Size(0, 0) || > ok) { > + if (dictObj.get<Size>()) { > cerr << "Dictionary object parse as Size" << > std::endl; > return TestFail; > } > -- > Regards, > > Laurent Pinchart > >
diff --git a/include/libcamera/internal/yaml_parser.h b/include/libcamera/internal/yaml_parser.h index 064cf44381d7..61f2223223a7 100644 --- a/include/libcamera/internal/yaml_parser.h +++ b/include/libcamera/internal/yaml_parser.h @@ -9,6 +9,7 @@ #include <iterator> #include <map> +#include <optional> #include <string> #include <vector> @@ -165,7 +166,13 @@ public: #else template<typename T> #endif - T get(const T &defaultValue, bool *ok = nullptr) const; + std::optional<T> get() const; + + template<typename T> + T get(const T &defaultValue) const + { + return get<T>().value_or(defaultValue); + } DictAdapter asDict() const { return DictAdapter{ dictionary_ }; } ListAdapter asList() const { return ListAdapter{ list_ }; } diff --git a/src/libcamera/yaml_parser.cpp b/src/libcamera/yaml_parser.cpp index 5c45e44e49c3..4299f5abd38a 100644 --- a/src/libcamera/yaml_parser.cpp +++ b/src/libcamera/yaml_parser.cpp @@ -31,12 +31,6 @@ namespace { /* Empty static YamlObject as a safe result for invalid operations */ static const YamlObject empty; -void setOk(bool *ok, bool result) -{ - if (ok) - *ok = result; -} - } /* namespace */ /** @@ -100,54 +94,52 @@ std::size_t YamlObject::size() const } /** - * \fn template<typename T> YamlObject::get<T>( - * const T &defaultValue, bool *ok) const + * \fn template<typename T> YamlObject::get<T>() const + * \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. + * + * \return The YamlObject value, or std::nullopt if parsing failed + */ + +/** + * \fn template<typename T> YamlObject::get<T>(const T &defaultValue) const * \brief Parse the YamlObject as a \a T value * \param[in] defaultValue The default value when failing to parse - * \param[out] ok The result of whether the parse succeeded * * 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), the \a defaultValue is returned, and \a ok is set to - * false. Otherwise, the YamlObject value is returned, and \a ok is set to true. + * store a \a T value), the \a defaultValue is returned. * - * The \a ok pointer is optional and can be a nullptr if the caller doesn't - * need to know if parsing succeeded. - * - * \return Value as a bool type + * \return The YamlObject value, or \a defaultValue if parsing failed */ #ifndef __DOXYGEN__ template<> -bool YamlObject::get(const bool &defaultValue, bool *ok) const +std::optional<bool> YamlObject::get() const { - setOk(ok, false); - if (type_ != Type::Value) - return defaultValue; + return {}; - if (value_ == "true") { - setOk(ok, true); + if (value_ == "true") return true; - } else if (value_ == "false") { - setOk(ok, true); + else if (value_ == "false") return false; - } - return defaultValue; + return {}; } template<> -int16_t YamlObject::get(const int16_t &defaultValue, bool *ok) const +std::optional<int16_t> YamlObject::get() const { - setOk(ok, false); - if (type_ != Type::Value) - return defaultValue; + return {}; if (value_ == "") - return defaultValue; + return {}; char *end; @@ -157,22 +149,19 @@ int16_t YamlObject::get(const int16_t &defaultValue, bool *ok) const if ('\0' != *end || errno == ERANGE || value < std::numeric_limits<int16_t>::min() || value > std::numeric_limits<int16_t>::max()) - return defaultValue; + return {}; - setOk(ok, true); return value; } template<> -uint16_t YamlObject::get(const uint16_t &defaultValue, bool *ok) const +std::optional<uint16_t> YamlObject::get() const { - setOk(ok, false); - if (type_ != Type::Value) - return defaultValue; + return {}; if (value_ == "") - return defaultValue; + return {}; /* * libyaml parses all scalar values as strings. When a string has @@ -183,7 +172,7 @@ uint16_t YamlObject::get(const uint16_t &defaultValue, bool *ok) const */ std::size_t found = value_.find_first_not_of(" \t"); if (found != std::string::npos && value_[found] == '-') - return defaultValue; + return {}; char *end; @@ -193,22 +182,19 @@ uint16_t YamlObject::get(const uint16_t &defaultValue, bool *ok) const if ('\0' != *end || errno == ERANGE || value < std::numeric_limits<uint16_t>::min() || value > std::numeric_limits<uint16_t>::max()) - return defaultValue; + return {}; - setOk(ok, true); return value; } template<> -int32_t YamlObject::get(const int32_t &defaultValue, bool *ok) const +std::optional<int32_t> YamlObject::get() const { - setOk(ok, false); - if (type_ != Type::Value) - return defaultValue; + return {}; if (value_ == "") - return defaultValue; + return {}; char *end; @@ -218,22 +204,19 @@ int32_t YamlObject::get(const int32_t &defaultValue, bool *ok) const if ('\0' != *end || errno == ERANGE || value < std::numeric_limits<int32_t>::min() || value > std::numeric_limits<int32_t>::max()) - return defaultValue; + return {}; - setOk(ok, true); return value; } template<> -uint32_t YamlObject::get(const uint32_t &defaultValue, bool *ok) const +std::optional<uint32_t> YamlObject::get() const { - setOk(ok, false); - if (type_ != Type::Value) - return defaultValue; + return {}; if (value_ == "") - return defaultValue; + return {}; /* * libyaml parses all scalar values as strings. When a string has @@ -244,7 +227,7 @@ uint32_t YamlObject::get(const uint32_t &defaultValue, bool *ok) const */ std::size_t found = value_.find_first_not_of(" \t"); if (found != std::string::npos && value_[found] == '-') - return defaultValue; + return {}; char *end; @@ -254,22 +237,19 @@ uint32_t YamlObject::get(const uint32_t &defaultValue, bool *ok) const if ('\0' != *end || errno == ERANGE || value < std::numeric_limits<uint32_t>::min() || value > std::numeric_limits<uint32_t>::max()) - return defaultValue; + return {}; - setOk(ok, true); return value; } template<> -double YamlObject::get(const double &defaultValue, bool *ok) const +std::optional<double> YamlObject::get() const { - setOk(ok, false); - if (type_ != Type::Value) - return defaultValue; + return {}; if (value_ == "") - return defaultValue; + return {}; char *end; @@ -277,50 +257,38 @@ double YamlObject::get(const double &defaultValue, bool *ok) const double value = std::strtod(value_.c_str(), &end); if ('\0' != *end || errno == ERANGE) - return defaultValue; + return {}; - setOk(ok, true); return value; } template<> -std::string YamlObject::get(const std::string &defaultValue, bool *ok) const +std::optional<std::string> YamlObject::get() const { - setOk(ok, false); - if (type_ != Type::Value) - return defaultValue; + return {}; - setOk(ok, true); return value_; } template<> -Size YamlObject::get(const Size &defaultValue, bool *ok) const +std::optional<Size> YamlObject::get() const { - setOk(ok, false); - if (type_ != Type::List) - return defaultValue; + return {}; if (list_.size() != 2) - return defaultValue; + return {}; - /* - * Add a local variable to validate each dimension in case - * that ok == nullptr. - */ - bool valid; - uint32_t width = list_[0]->get<uint32_t>(0, &valid); - if (!valid) - return defaultValue; + auto width = list_[0]->get<uint32_t>(); + if (!width) + return {}; - uint32_t height = list_[1]->get<uint32_t>(0, &valid); - if (!valid) - return defaultValue; + auto height = list_[1]->get<uint32_t>(); + if (!height) + return {}; - setOk(ok, true); - return Size(width, height); + return Size(*width, *height); } #endif /* __DOXYGEN__ */ diff --git a/test/yaml-parser.cpp b/test/yaml-parser.cpp index 38f848232fa6..ebb654f2ef9c 100644 --- a/test/yaml-parser.cpp +++ b/test/yaml-parser.cpp @@ -148,7 +148,6 @@ protected: } /* Test string object */ - bool ok; auto &strObj = (*root)["string"]; if (strObj.isDictionary()) { @@ -161,27 +160,27 @@ protected: return TestFail; } - if (strObj.get<string>("", &ok) != "libcamera" || !ok) { + if (strObj.get<string>().value_or("") != "libcamera") { cerr << "String object parse as wrong content" << std::endl; return TestFail; } - if (strObj.get<int32_t>(-1, &ok) != -1 || ok) { + if (strObj.get<int32_t>()) { cerr << "String object parse as integer" << std::endl; return TestFail; } - if (strObj.get<uint32_t>(1, &ok) != 1 || ok) { + if (strObj.get<uint32_t>()) { cerr << "String object parse as unsigned integer" << std::endl; return TestFail; } - if (strObj.get<double>(1.0, &ok) != 1.0 || ok) { + if (strObj.get<double>()) { cerr << "String object parse as double" << std::endl; return TestFail; } - if (strObj.get<Size>(Size(0, 0), &ok) != Size(0, 0) || ok) { + if (strObj.get<Size>()) { cerr << "String object parse as Size" << std::endl; return TestFail; } @@ -199,27 +198,27 @@ protected: return TestFail; } - if (int32Obj.get<int32_t>(-100, &ok) != -100 || !ok) { + if (int32Obj.get<int32_t>().value_or(0) != -100) { cerr << "Integer object parse as wrong value" << std::endl; return TestFail; } - if (int32Obj.get<string>("", &ok) != "-100" || !ok) { + if (int32Obj.get<string>().value_or("") != "-100") { cerr << "Integer object fail to parse as string" << std::endl; return TestFail; } - if (int32Obj.get<double>(1.0, &ok) != -100.0 || !ok) { + if (int32Obj.get<double>().value_or(0.0) != -100.0) { cerr << "Integer object fail to parse as double" << std::endl; return TestFail; } - if (int32Obj.get<uint32_t>(1, &ok) != 1 || ok) { + if (int32Obj.get<uint32_t>()) { cerr << "Negative integer object parse as unsigned integer" << std::endl; return TestFail; } - if (int32Obj.get<Size>(Size(0, 0), &ok) != Size(0, 0) || ok) { + if (int32Obj.get<Size>()) { cerr << "Integer object parse as Size" << std::endl; return TestFail; } @@ -237,27 +236,27 @@ protected: return TestFail; } - if (uint32Obj.get<int32_t>(-1, &ok) != 100 || !ok) { + if (uint32Obj.get<int32_t>().value_or(0) != 100) { cerr << "Unsigned integer object fail to parse as integer" << std::endl; return TestFail; } - if (uint32Obj.get<string>("", &ok) != "100" || !ok) { + if (uint32Obj.get<string>().value_or("") != "100") { cerr << "Unsigned integer object fail to parse as string" << std::endl; return TestFail; } - if (uint32Obj.get<double>(1.0, &ok) != 100.0 || !ok) { + if (uint32Obj.get<double>().value_or(0.0) != 100.0) { cerr << "Unsigned integer object fail to parse as double" << std::endl; return TestFail; } - if (uint32Obj.get<uint32_t>(100, &ok) != 100 || !ok) { + if (uint32Obj.get<uint32_t>().value_or(0) != 100) { cerr << "Unsigned integer object parsed as wrong value" << std::endl; return TestFail; } - if (uint32Obj.get<Size>(Size(0, 0), &ok) != Size(0, 0) || ok) { + if (uint32Obj.get<Size>()) { cerr << "Unsigned integer object parsed as Size" << std::endl; return TestFail; } @@ -275,27 +274,27 @@ protected: return TestFail; } - if (doubleObj.get<string>("", &ok) != "3.14159" || !ok) { + if (doubleObj.get<string>().value_or("") != "3.14159") { cerr << "Double object fail to parse as string" << std::endl; return TestFail; } - if (doubleObj.get<double>(1.0, &ok) != 3.14159 || !ok) { + if (doubleObj.get<double>().value_or(0.0) != 3.14159) { cerr << "Double object parse as wrong value" << std::endl; return TestFail; } - if (doubleObj.get<int32_t>(-1, &ok) != -1 || ok) { + if (doubleObj.get<int32_t>()) { cerr << "Double object parse as integer" << std::endl; return TestFail; } - if (doubleObj.get<uint32_t>(1, &ok) != 1 || ok) { + if (doubleObj.get<uint32_t>()) { cerr << "Double object parse as unsigned integer" << std::endl; return TestFail; } - if (doubleObj.get<Size>(Size(0, 0), &ok) != Size(0, 0) || ok) { + if (doubleObj.get<Size>()) { cerr << "Double object parse as Size" << std::endl; return TestFail; } @@ -313,27 +312,27 @@ protected: return TestFail; } - if (sizeObj.get<string>("", &ok) != "" || ok) { + if (sizeObj.get<string>()) { cerr << "Size object parse as string" << std::endl; return TestFail; } - if (sizeObj.get<double>(1.0, &ok) != 1.0 || ok) { + if (sizeObj.get<double>()) { cerr << "Size object parse as double" << std::endl; return TestFail; } - if (sizeObj.get<int32_t>(-1, &ok) != -1 || ok) { + if (sizeObj.get<int32_t>()) { cerr << "Size object parse as integer" << std::endl; return TestFail; } - if (sizeObj.get<uint32_t>(1, &ok) != 1 || ok) { + if (sizeObj.get<uint32_t>()) { cerr << "Size object parse as unsigned integer" << std::endl; return TestFail; } - if (sizeObj.get<Size>(Size(0, 0), &ok) != Size(1920, 1080) || !ok) { + if (sizeObj.get<Size>().value_or(Size(0, 0)) != Size(1920, 1080)) { cerr << "Size object parse as wrong value" << std::endl; return TestFail; } @@ -351,27 +350,27 @@ protected: return TestFail; } - if (listObj.get<string>("", &ok) != "" || ok) { + if (listObj.get<string>()) { cerr << "List object parse as string" << std::endl; return TestFail; } - if (listObj.get<double>(1.0, &ok) != 1.0 || ok) { + if (listObj.get<double>()) { cerr << "List object parse as double" << std::endl; return TestFail; } - if (listObj.get<int32_t>(-1, &ok) != -1 || ok) { + if (listObj.get<int32_t>()) { cerr << "List object parse as integer" << std::endl; return TestFail; } - if (listObj.get<uint32_t>(1, &ok) != 1 || ok) { + if (listObj.get<uint32_t>()) { cerr << "List object parse as unsigne integer" << std::endl; return TestFail; } - if (listObj.get<Size>(Size(0, 0), &ok) != Size(0, 0) || ok) { + if (listObj.get<Size>()) { cerr << "String list object parse as Size" << std::endl; return TestFail; } @@ -424,27 +423,27 @@ protected: return TestFail; } - if (dictObj.get<string>("", &ok) != "" || ok) { + if (dictObj.get<string>()) { cerr << "Dictionary object parse as string" << std::endl; return TestFail; } - if (dictObj.get<double>(1.0, &ok) != 1.0 || ok) { + if (dictObj.get<double>()) { cerr << "Dictionary object parse as double" << std::endl; return TestFail; } - if (dictObj.get<int32_t>(-1, &ok) != -1 || ok) { + if (dictObj.get<int32_t>()) { cerr << "Dictionary object parse as integer" << std::endl; return TestFail; } - if (dictObj.get<uint32_t>(1, &ok) != 1 || ok) { + if (dictObj.get<uint32_t>()) { cerr << "Dictionary object parse as unsigned integer" << std::endl; return TestFail; } - if (dictObj.get<Size>(Size(0, 0), &ok) != Size(0, 0) || ok) { + if (dictObj.get<Size>()) { cerr << "Dictionary object parse as Size" << std::endl; return TestFail; }
The YamlObject::get() function takes a default value and an optional bool ok flag to handle parsing errors. This ad-hoc mechanism complicates error handling in callers. A better API is possible by dropping the default value and ok flag and returning an std::optional. Not only does it simplify the calls, it also lets callers handle errors through the standard std::optional class instead of the current ad-hoc mechanism. Provide a convenience get() wrapper around std::optional::value_or() to further simplify callers that don't need any specific error handling. Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com> --- include/libcamera/internal/yaml_parser.h | 9 +- src/libcamera/yaml_parser.cpp | 138 +++++++++-------------- test/yaml-parser.cpp | 71 ++++++------ 3 files changed, 96 insertions(+), 122 deletions(-)