Message ID | 20240613013944.23344-3-laurent.pinchart@ideasonboard.com |
---|---|
State | Accepted |
Headers | show |
Series |
|
Related | show |
On Thu, Jun 13, 2024 at 04:39:35AM +0300, Laurent Pinchart wrote: > The YamlObject::get() function is a function template that gets fully > specialized for various types. This works fine for non-template types, > but specializing it for template types (e.g. a std::vector<U>) would > require partial template specialization, which C++ allows for classes > and variables but not functions. > > To work around this problem, delegate the implementation to a new > YamlObject::Getter structure template, which will support partial > specialization. > > Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com> Reviewed-by: Paul Elder <paul.elder@ideasonboard.com> > --- > include/libcamera/internal/yaml_parser.h | 12 +++- > src/libcamera/yaml_parser.cpp | 78 +++++++++++++----------- > 2 files changed, 55 insertions(+), 35 deletions(-) > > diff --git a/include/libcamera/internal/yaml_parser.h b/include/libcamera/internal/yaml_parser.h > index 81cc0e25ae0f..06a41146ad01 100644 > --- a/include/libcamera/internal/yaml_parser.h > +++ b/include/libcamera/internal/yaml_parser.h > @@ -162,7 +162,10 @@ public: > std::size_t size() const; > > template<typename T> > - std::optional<T> get() const; > + std::optional<T> get() const > + { > + return Getter<T>{}.get(*this); > + } > > template<typename T, typename U> > T get(U &&defaultValue) const > @@ -199,6 +202,8 @@ public: > private: > LIBCAMERA_DISABLE_COPY_AND_MOVE(YamlObject) > > + template<typename T> > + friend struct Getter; > friend class YamlParserContext; > > enum class Type { > @@ -207,6 +212,11 @@ private: > Value, > }; > > + template<typename T> > + struct Getter { > + std::optional<T> get(const YamlObject &obj) const; > + }; > + > Type type_; > > std::string value_; > diff --git a/src/libcamera/yaml_parser.cpp b/src/libcamera/yaml_parser.cpp > index b68a44c15c35..56670ba7a584 100644 > --- a/src/libcamera/yaml_parser.cpp > +++ b/src/libcamera/yaml_parser.cpp > @@ -118,14 +118,15 @@ std::size_t YamlObject::size() const > #ifndef __DOXYGEN__ > > template<> > -std::optional<bool> YamlObject::get() const > +std::optional<bool> > +YamlObject::Getter<bool>::get(const YamlObject &obj) const > { > - if (type_ != Type::Value) > + if (obj.type_ != Type::Value) > return std::nullopt; > > - if (value_ == "true") > + if (obj.value_ == "true") > return true; > - else if (value_ == "false") > + else if (obj.value_ == "false") > return false; > > return std::nullopt; > @@ -182,14 +183,15 @@ bool parseUnsignedInteger(const std::string &str, unsigned long max, > } /* namespace */ > > template<> > -std::optional<int8_t> YamlObject::get() const > +std::optional<int8_t> > +YamlObject::Getter<int8_t>::get(const YamlObject &obj) const > { > - if (type_ != Type::Value) > + if (obj.type_ != Type::Value) > return std::nullopt; > > long value; > > - if (!parseSignedInteger(value_, std::numeric_limits<int8_t>::min(), > + if (!parseSignedInteger(obj.value_, std::numeric_limits<int8_t>::min(), > std::numeric_limits<int8_t>::max(), &value)) > return std::nullopt; > > @@ -197,14 +199,15 @@ std::optional<int8_t> YamlObject::get() const > } > > template<> > -std::optional<uint8_t> YamlObject::get() const > +std::optional<uint8_t> > +YamlObject::Getter<uint8_t>::get(const YamlObject &obj) const > { > - if (type_ != Type::Value) > + if (obj.type_ != Type::Value) > return std::nullopt; > > unsigned long value; > > - if (!parseUnsignedInteger(value_, std::numeric_limits<uint8_t>::max(), > + if (!parseUnsignedInteger(obj.value_, std::numeric_limits<uint8_t>::max(), > &value)) > return std::nullopt; > > @@ -212,14 +215,15 @@ std::optional<uint8_t> YamlObject::get() const > } > > template<> > -std::optional<int16_t> YamlObject::get() const > +std::optional<int16_t> > +YamlObject::Getter<int16_t>::get(const YamlObject &obj) const > { > - if (type_ != Type::Value) > + if (obj.type_ != Type::Value) > return std::nullopt; > > long value; > > - if (!parseSignedInteger(value_, std::numeric_limits<int16_t>::min(), > + if (!parseSignedInteger(obj.value_, std::numeric_limits<int16_t>::min(), > std::numeric_limits<int16_t>::max(), &value)) > return std::nullopt; > > @@ -227,14 +231,15 @@ std::optional<int16_t> YamlObject::get() const > } > > template<> > -std::optional<uint16_t> YamlObject::get() const > +std::optional<uint16_t> > +YamlObject::Getter<uint16_t>::get(const YamlObject &obj) const > { > - if (type_ != Type::Value) > + if (obj.type_ != Type::Value) > return std::nullopt; > > unsigned long value; > > - if (!parseUnsignedInteger(value_, std::numeric_limits<uint16_t>::max(), > + if (!parseUnsignedInteger(obj.value_, std::numeric_limits<uint16_t>::max(), > &value)) > return std::nullopt; > > @@ -242,14 +247,15 @@ std::optional<uint16_t> YamlObject::get() const > } > > template<> > -std::optional<int32_t> YamlObject::get() const > +std::optional<int32_t> > +YamlObject::Getter<int32_t>::get(const YamlObject &obj) const > { > - if (type_ != Type::Value) > + if (obj.type_ != Type::Value) > return std::nullopt; > > long value; > > - if (!parseSignedInteger(value_, std::numeric_limits<int32_t>::min(), > + if (!parseSignedInteger(obj.value_, std::numeric_limits<int32_t>::min(), > std::numeric_limits<int32_t>::max(), &value)) > return std::nullopt; > > @@ -257,14 +263,15 @@ std::optional<int32_t> YamlObject::get() const > } > > template<> > -std::optional<uint32_t> YamlObject::get() const > +std::optional<uint32_t> > +YamlObject::Getter<uint32_t>::get(const YamlObject &obj) const > { > - if (type_ != Type::Value) > + if (obj.type_ != Type::Value) > return std::nullopt; > > unsigned long value; > > - if (!parseUnsignedInteger(value_, std::numeric_limits<uint32_t>::max(), > + if (!parseUnsignedInteger(obj.value_, std::numeric_limits<uint32_t>::max(), > &value)) > return std::nullopt; > > @@ -272,18 +279,19 @@ std::optional<uint32_t> YamlObject::get() const > } > > template<> > -std::optional<double> YamlObject::get() const > +std::optional<double> > +YamlObject::Getter<double>::get(const YamlObject &obj) const > { > - if (type_ != Type::Value) > + if (obj.type_ != Type::Value) > return std::nullopt; > > - if (value_ == "") > + if (obj.value_ == "") > return std::nullopt; > > char *end; > > errno = 0; > - double value = utils::strtod(value_.c_str(), &end); > + double value = utils::strtod(obj.value_.c_str(), &end); > > if ('\0' != *end || errno == ERANGE) > return std::nullopt; > @@ -292,28 +300,30 @@ std::optional<double> YamlObject::get() const > } > > template<> > -std::optional<std::string> YamlObject::get() const > +std::optional<std::string> > +YamlObject::Getter<std::string>::get(const YamlObject &obj) const > { > - if (type_ != Type::Value) > + if (obj.type_ != Type::Value) > return std::nullopt; > > - return value_; > + return obj.value_; > } > > template<> > -std::optional<Size> YamlObject::get() const > +std::optional<Size> > +YamlObject::Getter<Size>::get(const YamlObject &obj) const > { > - if (type_ != Type::List) > + if (obj.type_ != Type::List) > return std::nullopt; > > - if (list_.size() != 2) > + if (obj.list_.size() != 2) > return std::nullopt; > > - auto width = list_[0].value->get<uint32_t>(); > + auto width = obj.list_[0].value->get<uint32_t>(); > if (!width) > return std::nullopt; > > - auto height = list_[1].value->get<uint32_t>(); > + auto height = obj.list_[1].value->get<uint32_t>(); > if (!height) > return std::nullopt; >
Quoting Laurent Pinchart (2024-06-13 02:39:35) > The YamlObject::get() function is a function template that gets fully > specialized for various types. This works fine for non-template types, > but specializing it for template types (e.g. a std::vector<U>) would > require partial template specialization, which C++ allows for classes > and variables but not functions. > > To work around this problem, delegate the implementation to a new > YamlObject::Getter structure template, which will support partial > specialization. > > Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com> > --- > include/libcamera/internal/yaml_parser.h | 12 +++- > src/libcamera/yaml_parser.cpp | 78 +++++++++++++----------- > 2 files changed, 55 insertions(+), 35 deletions(-) > > diff --git a/include/libcamera/internal/yaml_parser.h b/include/libcamera/internal/yaml_parser.h > index 81cc0e25ae0f..06a41146ad01 100644 > --- a/include/libcamera/internal/yaml_parser.h > +++ b/include/libcamera/internal/yaml_parser.h > @@ -162,7 +162,10 @@ public: > std::size_t size() const; > > template<typename T> > - std::optional<T> get() const; > + std::optional<T> get() const > + { > + return Getter<T>{}.get(*this); > + } Aha, this is the magic I missed on my first pass. I was curious how we were changing all these fucntions to now need an object, and I couldn't see core changes not passing it in - but it comes from here. Ok so that's neat - and means nothing else is impacted during the transition... It all falls into place: Reviewed-by: Kieran Bingham <kieran.bingham@ideasonboard.com> > > template<typename T, typename U> > T get(U &&defaultValue) const > @@ -199,6 +202,8 @@ public: > private: > LIBCAMERA_DISABLE_COPY_AND_MOVE(YamlObject) > > + template<typename T> > + friend struct Getter; > friend class YamlParserContext; > > enum class Type { > @@ -207,6 +212,11 @@ private: > Value, > }; > > + template<typename T> > + struct Getter { > + std::optional<T> get(const YamlObject &obj) const; > + }; > + > Type type_; > > std::string value_; > diff --git a/src/libcamera/yaml_parser.cpp b/src/libcamera/yaml_parser.cpp > index b68a44c15c35..56670ba7a584 100644 > --- a/src/libcamera/yaml_parser.cpp > +++ b/src/libcamera/yaml_parser.cpp > @@ -118,14 +118,15 @@ std::size_t YamlObject::size() const > #ifndef __DOXYGEN__ > > template<> > -std::optional<bool> YamlObject::get() const > +std::optional<bool> > +YamlObject::Getter<bool>::get(const YamlObject &obj) const > { > - if (type_ != Type::Value) > + if (obj.type_ != Type::Value) > return std::nullopt; > > - if (value_ == "true") > + if (obj.value_ == "true") > return true; > - else if (value_ == "false") > + else if (obj.value_ == "false") > return false; > > return std::nullopt; > @@ -182,14 +183,15 @@ bool parseUnsignedInteger(const std::string &str, unsigned long max, > } /* namespace */ > > template<> > -std::optional<int8_t> YamlObject::get() const > +std::optional<int8_t> > +YamlObject::Getter<int8_t>::get(const YamlObject &obj) const > { > - if (type_ != Type::Value) > + if (obj.type_ != Type::Value) > return std::nullopt; > > long value; > > - if (!parseSignedInteger(value_, std::numeric_limits<int8_t>::min(), > + if (!parseSignedInteger(obj.value_, std::numeric_limits<int8_t>::min(), > std::numeric_limits<int8_t>::max(), &value)) > return std::nullopt; > > @@ -197,14 +199,15 @@ std::optional<int8_t> YamlObject::get() const > } > > template<> > -std::optional<uint8_t> YamlObject::get() const > +std::optional<uint8_t> > +YamlObject::Getter<uint8_t>::get(const YamlObject &obj) const > { > - if (type_ != Type::Value) > + if (obj.type_ != Type::Value) > return std::nullopt; > > unsigned long value; > > - if (!parseUnsignedInteger(value_, std::numeric_limits<uint8_t>::max(), > + if (!parseUnsignedInteger(obj.value_, std::numeric_limits<uint8_t>::max(), > &value)) > return std::nullopt; > > @@ -212,14 +215,15 @@ std::optional<uint8_t> YamlObject::get() const > } > > template<> > -std::optional<int16_t> YamlObject::get() const > +std::optional<int16_t> > +YamlObject::Getter<int16_t>::get(const YamlObject &obj) const > { > - if (type_ != Type::Value) > + if (obj.type_ != Type::Value) > return std::nullopt; > > long value; > > - if (!parseSignedInteger(value_, std::numeric_limits<int16_t>::min(), > + if (!parseSignedInteger(obj.value_, std::numeric_limits<int16_t>::min(), > std::numeric_limits<int16_t>::max(), &value)) > return std::nullopt; > > @@ -227,14 +231,15 @@ std::optional<int16_t> YamlObject::get() const > } > > template<> > -std::optional<uint16_t> YamlObject::get() const > +std::optional<uint16_t> > +YamlObject::Getter<uint16_t>::get(const YamlObject &obj) const > { > - if (type_ != Type::Value) > + if (obj.type_ != Type::Value) > return std::nullopt; > > unsigned long value; > > - if (!parseUnsignedInteger(value_, std::numeric_limits<uint16_t>::max(), > + if (!parseUnsignedInteger(obj.value_, std::numeric_limits<uint16_t>::max(), > &value)) > return std::nullopt; > > @@ -242,14 +247,15 @@ std::optional<uint16_t> YamlObject::get() const > } > > template<> > -std::optional<int32_t> YamlObject::get() const > +std::optional<int32_t> > +YamlObject::Getter<int32_t>::get(const YamlObject &obj) const > { > - if (type_ != Type::Value) > + if (obj.type_ != Type::Value) > return std::nullopt; > > long value; > > - if (!parseSignedInteger(value_, std::numeric_limits<int32_t>::min(), > + if (!parseSignedInteger(obj.value_, std::numeric_limits<int32_t>::min(), > std::numeric_limits<int32_t>::max(), &value)) > return std::nullopt; > > @@ -257,14 +263,15 @@ std::optional<int32_t> YamlObject::get() const > } > > template<> > -std::optional<uint32_t> YamlObject::get() const > +std::optional<uint32_t> > +YamlObject::Getter<uint32_t>::get(const YamlObject &obj) const > { > - if (type_ != Type::Value) > + if (obj.type_ != Type::Value) > return std::nullopt; > > unsigned long value; > > - if (!parseUnsignedInteger(value_, std::numeric_limits<uint32_t>::max(), > + if (!parseUnsignedInteger(obj.value_, std::numeric_limits<uint32_t>::max(), > &value)) > return std::nullopt; > > @@ -272,18 +279,19 @@ std::optional<uint32_t> YamlObject::get() const > } > > template<> > -std::optional<double> YamlObject::get() const > +std::optional<double> > +YamlObject::Getter<double>::get(const YamlObject &obj) const > { > - if (type_ != Type::Value) > + if (obj.type_ != Type::Value) > return std::nullopt; > > - if (value_ == "") > + if (obj.value_ == "") > return std::nullopt; > > char *end; > > errno = 0; > - double value = utils::strtod(value_.c_str(), &end); > + double value = utils::strtod(obj.value_.c_str(), &end); > > if ('\0' != *end || errno == ERANGE) > return std::nullopt; > @@ -292,28 +300,30 @@ std::optional<double> YamlObject::get() const > } > > template<> > -std::optional<std::string> YamlObject::get() const > +std::optional<std::string> > +YamlObject::Getter<std::string>::get(const YamlObject &obj) const > { > - if (type_ != Type::Value) > + if (obj.type_ != Type::Value) > return std::nullopt; > > - return value_; > + return obj.value_; > } > > template<> > -std::optional<Size> YamlObject::get() const > +std::optional<Size> > +YamlObject::Getter<Size>::get(const YamlObject &obj) const > { > - if (type_ != Type::List) > + if (obj.type_ != Type::List) > return std::nullopt; > > - if (list_.size() != 2) > + if (obj.list_.size() != 2) > return std::nullopt; > > - auto width = list_[0].value->get<uint32_t>(); > + auto width = obj.list_[0].value->get<uint32_t>(); > if (!width) > return std::nullopt; > > - auto height = list_[1].value->get<uint32_t>(); > + auto height = obj.list_[1].value->get<uint32_t>(); > if (!height) > return std::nullopt; > > -- > Regards, > > Laurent Pinchart >
diff --git a/include/libcamera/internal/yaml_parser.h b/include/libcamera/internal/yaml_parser.h index 81cc0e25ae0f..06a41146ad01 100644 --- a/include/libcamera/internal/yaml_parser.h +++ b/include/libcamera/internal/yaml_parser.h @@ -162,7 +162,10 @@ public: std::size_t size() const; template<typename T> - std::optional<T> get() const; + std::optional<T> get() const + { + return Getter<T>{}.get(*this); + } template<typename T, typename U> T get(U &&defaultValue) const @@ -199,6 +202,8 @@ public: private: LIBCAMERA_DISABLE_COPY_AND_MOVE(YamlObject) + template<typename T> + friend struct Getter; friend class YamlParserContext; enum class Type { @@ -207,6 +212,11 @@ private: Value, }; + template<typename T> + struct Getter { + std::optional<T> get(const YamlObject &obj) const; + }; + Type type_; std::string value_; diff --git a/src/libcamera/yaml_parser.cpp b/src/libcamera/yaml_parser.cpp index b68a44c15c35..56670ba7a584 100644 --- a/src/libcamera/yaml_parser.cpp +++ b/src/libcamera/yaml_parser.cpp @@ -118,14 +118,15 @@ std::size_t YamlObject::size() const #ifndef __DOXYGEN__ template<> -std::optional<bool> YamlObject::get() const +std::optional<bool> +YamlObject::Getter<bool>::get(const YamlObject &obj) const { - if (type_ != Type::Value) + if (obj.type_ != Type::Value) return std::nullopt; - if (value_ == "true") + if (obj.value_ == "true") return true; - else if (value_ == "false") + else if (obj.value_ == "false") return false; return std::nullopt; @@ -182,14 +183,15 @@ bool parseUnsignedInteger(const std::string &str, unsigned long max, } /* namespace */ template<> -std::optional<int8_t> YamlObject::get() const +std::optional<int8_t> +YamlObject::Getter<int8_t>::get(const YamlObject &obj) const { - if (type_ != Type::Value) + if (obj.type_ != Type::Value) return std::nullopt; long value; - if (!parseSignedInteger(value_, std::numeric_limits<int8_t>::min(), + if (!parseSignedInteger(obj.value_, std::numeric_limits<int8_t>::min(), std::numeric_limits<int8_t>::max(), &value)) return std::nullopt; @@ -197,14 +199,15 @@ std::optional<int8_t> YamlObject::get() const } template<> -std::optional<uint8_t> YamlObject::get() const +std::optional<uint8_t> +YamlObject::Getter<uint8_t>::get(const YamlObject &obj) const { - if (type_ != Type::Value) + if (obj.type_ != Type::Value) return std::nullopt; unsigned long value; - if (!parseUnsignedInteger(value_, std::numeric_limits<uint8_t>::max(), + if (!parseUnsignedInteger(obj.value_, std::numeric_limits<uint8_t>::max(), &value)) return std::nullopt; @@ -212,14 +215,15 @@ std::optional<uint8_t> YamlObject::get() const } template<> -std::optional<int16_t> YamlObject::get() const +std::optional<int16_t> +YamlObject::Getter<int16_t>::get(const YamlObject &obj) const { - if (type_ != Type::Value) + if (obj.type_ != Type::Value) return std::nullopt; long value; - if (!parseSignedInteger(value_, std::numeric_limits<int16_t>::min(), + if (!parseSignedInteger(obj.value_, std::numeric_limits<int16_t>::min(), std::numeric_limits<int16_t>::max(), &value)) return std::nullopt; @@ -227,14 +231,15 @@ std::optional<int16_t> YamlObject::get() const } template<> -std::optional<uint16_t> YamlObject::get() const +std::optional<uint16_t> +YamlObject::Getter<uint16_t>::get(const YamlObject &obj) const { - if (type_ != Type::Value) + if (obj.type_ != Type::Value) return std::nullopt; unsigned long value; - if (!parseUnsignedInteger(value_, std::numeric_limits<uint16_t>::max(), + if (!parseUnsignedInteger(obj.value_, std::numeric_limits<uint16_t>::max(), &value)) return std::nullopt; @@ -242,14 +247,15 @@ std::optional<uint16_t> YamlObject::get() const } template<> -std::optional<int32_t> YamlObject::get() const +std::optional<int32_t> +YamlObject::Getter<int32_t>::get(const YamlObject &obj) const { - if (type_ != Type::Value) + if (obj.type_ != Type::Value) return std::nullopt; long value; - if (!parseSignedInteger(value_, std::numeric_limits<int32_t>::min(), + if (!parseSignedInteger(obj.value_, std::numeric_limits<int32_t>::min(), std::numeric_limits<int32_t>::max(), &value)) return std::nullopt; @@ -257,14 +263,15 @@ std::optional<int32_t> YamlObject::get() const } template<> -std::optional<uint32_t> YamlObject::get() const +std::optional<uint32_t> +YamlObject::Getter<uint32_t>::get(const YamlObject &obj) const { - if (type_ != Type::Value) + if (obj.type_ != Type::Value) return std::nullopt; unsigned long value; - if (!parseUnsignedInteger(value_, std::numeric_limits<uint32_t>::max(), + if (!parseUnsignedInteger(obj.value_, std::numeric_limits<uint32_t>::max(), &value)) return std::nullopt; @@ -272,18 +279,19 @@ std::optional<uint32_t> YamlObject::get() const } template<> -std::optional<double> YamlObject::get() const +std::optional<double> +YamlObject::Getter<double>::get(const YamlObject &obj) const { - if (type_ != Type::Value) + if (obj.type_ != Type::Value) return std::nullopt; - if (value_ == "") + if (obj.value_ == "") return std::nullopt; char *end; errno = 0; - double value = utils::strtod(value_.c_str(), &end); + double value = utils::strtod(obj.value_.c_str(), &end); if ('\0' != *end || errno == ERANGE) return std::nullopt; @@ -292,28 +300,30 @@ std::optional<double> YamlObject::get() const } template<> -std::optional<std::string> YamlObject::get() const +std::optional<std::string> +YamlObject::Getter<std::string>::get(const YamlObject &obj) const { - if (type_ != Type::Value) + if (obj.type_ != Type::Value) return std::nullopt; - return value_; + return obj.value_; } template<> -std::optional<Size> YamlObject::get() const +std::optional<Size> +YamlObject::Getter<Size>::get(const YamlObject &obj) const { - if (type_ != Type::List) + if (obj.type_ != Type::List) return std::nullopt; - if (list_.size() != 2) + if (obj.list_.size() != 2) return std::nullopt; - auto width = list_[0].value->get<uint32_t>(); + auto width = obj.list_[0].value->get<uint32_t>(); if (!width) return std::nullopt; - auto height = list_[1].value->get<uint32_t>(); + auto height = obj.list_[1].value->get<uint32_t>(); if (!height) return std::nullopt;
The YamlObject::get() function is a function template that gets fully specialized for various types. This works fine for non-template types, but specializing it for template types (e.g. a std::vector<U>) would require partial template specialization, which C++ allows for classes and variables but not functions. To work around this problem, delegate the implementation to a new YamlObject::Getter structure template, which will support partial specialization. Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com> --- include/libcamera/internal/yaml_parser.h | 12 +++- src/libcamera/yaml_parser.cpp | 78 +++++++++++++----------- 2 files changed, 55 insertions(+), 35 deletions(-)