| Message ID | 20260113000808.15395-18-laurent.pinchart@ideasonboard.com |
|---|---|
| State | New |
| Headers | show |
| Series |
|
| Related | show |
2026. 01. 13. 1:07 keltezéssel, Laurent Pinchart írta: > The YamlObject class was designed to represent data parsed from YAML > files. It is outgrowing the initial needs. Move it to a separate file to > prepare for a rename. > > Most files that include yaml_parser.h only need access to a YamlObject. > Switch them to yaml_object.h. pipeline_base.cpp was including > yaml_parser.h indirectly through pipeline_base.h, include it directly > now. > > Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com> > --- Looks ok to me. Reviewed-by: Barnabás Pőcze <barnabas.pocze@ideasonboard.com> > .../libcamera/internal/global_configuration.h | 2 +- > include/libcamera/internal/matrix.h | 2 +- > include/libcamera/internal/meson.build | 1 + > include/libcamera/internal/vector.h | 2 +- > include/libcamera/internal/yaml_object.h | 226 +++++++++ > include/libcamera/internal/yaml_parser.h | 212 +------- > src/ipa/libipa/agc_mean_luminance.h | 2 +- > src/ipa/libipa/awb.h | 2 +- > src/ipa/libipa/awb_bayes.h | 2 +- > src/ipa/libipa/interpolator.cpp | 2 - > src/ipa/libipa/interpolator.h | 2 +- > src/ipa/libipa/lsc_polynomial.h | 2 +- > src/ipa/libipa/lux.cpp | 2 +- > src/ipa/libipa/module.h | 2 +- > src/ipa/mali-c55/algorithms/blc.cpp | 2 +- > src/ipa/mali-c55/algorithms/lsc.cpp | 2 +- > src/ipa/rkisp1/algorithms/agc.cpp | 2 +- > src/ipa/rkisp1/algorithms/blc.cpp | 2 +- > src/ipa/rkisp1/algorithms/ccm.cpp | 2 +- > src/ipa/rkisp1/algorithms/dpcc.cpp | 2 +- > src/ipa/rkisp1/algorithms/goc.cpp | 2 +- > src/ipa/rkisp1/algorithms/gsl.cpp | 2 +- > src/ipa/rkisp1/algorithms/lsc.cpp | 2 +- > src/ipa/rkisp1/algorithms/wdr.cpp | 2 +- > src/ipa/rpi/controller/algorithm.h | 2 +- > src/ipa/rpi/controller/controller.h | 2 +- > src/libcamera/geometry.cpp | 2 +- > src/libcamera/meson.build | 1 + > .../pipeline/rpi/common/pipeline_base.cpp | 1 + > .../pipeline/rpi/common/pipeline_base.h | 2 +- > .../pipeline/virtual/config_parser.h | 2 +- > src/libcamera/pipeline/virtual/virtual.cpp | 2 +- > src/libcamera/yaml_object.cpp | 477 ++++++++++++++++++ > src/libcamera/yaml_parser.cpp | 458 +---------------- > 34 files changed, 736 insertions(+), 694 deletions(-) > create mode 100644 include/libcamera/internal/yaml_object.h > create mode 100644 src/libcamera/yaml_object.cpp > > diff --git a/include/libcamera/internal/global_configuration.h b/include/libcamera/internal/global_configuration.h > index 8d09517edca1..16c6a21f2a8a 100644 > --- a/include/libcamera/internal/global_configuration.h > +++ b/include/libcamera/internal/global_configuration.h > @@ -14,7 +14,7 @@ > > #include <libcamera/base/utils.h> > > -#include "libcamera/internal/yaml_parser.h" > +#include "libcamera/internal/yaml_object.h" > > namespace libcamera { > > diff --git a/include/libcamera/internal/matrix.h b/include/libcamera/internal/matrix.h > index 67761cb6037d..11fccd27547e 100644 > --- a/include/libcamera/internal/matrix.h > +++ b/include/libcamera/internal/matrix.h > @@ -14,7 +14,7 @@ > #include <libcamera/base/log.h> > #include <libcamera/base/span.h> > > -#include "libcamera/internal/yaml_parser.h" > +#include "libcamera/internal/yaml_object.h" > > namespace libcamera { > > diff --git a/include/libcamera/internal/meson.build b/include/libcamera/internal/meson.build > index dc48619e5ac8..c24c9f062f29 100644 > --- a/include/libcamera/internal/meson.build > +++ b/include/libcamera/internal/meson.build > @@ -50,6 +50,7 @@ libcamera_internal_headers = files([ > 'v4l2_subdevice.h', > 'v4l2_videodevice.h', > 'vector.h', > + 'yaml_object.h', > 'yaml_parser.h', > ]) > > diff --git a/include/libcamera/internal/vector.h b/include/libcamera/internal/vector.h > index cfd8882ce0e6..af24485f3bb1 100644 > --- a/include/libcamera/internal/vector.h > +++ b/include/libcamera/internal/vector.h > @@ -19,7 +19,7 @@ > #include <libcamera/base/span.h> > > #include "libcamera/internal/matrix.h" > -#include "libcamera/internal/yaml_parser.h" > +#include "libcamera/internal/yaml_object.h" > > namespace libcamera { > > diff --git a/include/libcamera/internal/yaml_object.h b/include/libcamera/internal/yaml_object.h > new file mode 100644 > index 000000000000..1771f8821e2e > --- /dev/null > +++ b/include/libcamera/internal/yaml_object.h > @@ -0,0 +1,226 @@ > +/* SPDX-License-Identifier: LGPL-2.1-or-later */ > +/* > + * Copyright (C) 2022, Google Inc. > + * Copyright (C) 2025, Ideas on Board > + * > + * libcamera YAML object > + */ > + > +#pragma once > + > +#include <iterator> > +#include <map> > +#include <memory> > +#include <optional> > +#include <string> > +#include <string_view> > +#include <type_traits> > +#include <utility> > +#include <vector> > + > +#include <libcamera/base/class.h> > + > +namespace libcamera { > + > +class YamlObject > +{ > +private: > + struct Value { > + Value(std::string &&k, std::unique_ptr<YamlObject> &&v) > + : key(std::move(k)), value(std::move(v)) > + { > + } > + std::string key; > + std::unique_ptr<YamlObject> value; > + }; > + > + using ValueContainer = std::vector<Value>; > + > +public: > +#ifndef __DOXYGEN__ > + template<typename Derived> > + class Iterator > + { > + public: > + using difference_type = std::ptrdiff_t; > + using iterator_category = std::forward_iterator_tag; > + > + Iterator(typename ValueContainer::const_iterator it) > + : it_(it) > + { > + } > + > + Derived &operator++() > + { > + ++it_; > + return *static_cast<Derived *>(this); > + } > + > + Derived operator++(int) > + { > + Derived it = *static_cast<Derived *>(this); > + it_++; > + return it; > + } > + > + friend bool operator==(const Iterator &a, const Iterator &b) > + { > + return a.it_ == b.it_; > + } > + > + friend bool operator!=(const Iterator &a, const Iterator &b) > + { > + return a.it_ != b.it_; > + } > + > + protected: > + ValueContainer::const_iterator it_; > + }; > + > + template<typename Iterator> > + class Adapter > + { > + public: > + Adapter(const ValueContainer &container) > + : container_(container) > + { > + } > + > + Iterator begin() const > + { > + return Iterator{ container_.begin() }; > + } > + > + Iterator end() const > + { > + return Iterator{ container_.end() }; > + } > + > + protected: > + const ValueContainer &container_; > + }; > + > + class ListIterator : public Iterator<ListIterator> > + { > + public: > + using value_type = const YamlObject &; > + using pointer = const YamlObject *; > + using reference = value_type; > + > + value_type operator*() const > + { > + return *it_->value.get(); > + } > + > + pointer operator->() const > + { > + return it_->value.get(); > + } > + }; > + > + class DictIterator : public Iterator<DictIterator> > + { > + public: > + using value_type = std::pair<const std::string &, const YamlObject &>; > + using pointer = value_type *; > + using reference = value_type &; > + > + value_type operator*() const > + { > + return { it_->key, *it_->value.get() }; > + } > + }; > + > + class DictAdapter : public Adapter<DictIterator> > + { > + public: > + using key_type = std::string; > + }; > + > + class ListAdapter : public Adapter<ListIterator> > + { > + }; > +#endif /* __DOXYGEN__ */ > + > + YamlObject(); > + ~YamlObject(); > + > + bool isValue() const > + { > + return type_ == Type::Value; > + } > + bool isList() const > + { > + return type_ == Type::List; > + } > + bool isDictionary() const > + { > + return type_ == Type::Dictionary; > + } > + bool isEmpty() const > + { > + return type_ == Type::Empty; > + } > + explicit operator bool() const > + { > + return type_ != Type::Empty; > + } > + > + std::size_t size() const; > + > + template<typename T> > + std::optional<T> get() const > + { > + return Accessor<T>{}.get(*this); > + } > + > + template<typename T, typename U> > + T get(U &&defaultValue) const > + { > + return get<T>().value_or(std::forward<U>(defaultValue)); > + } > + > + template<typename T> > + void set(T &&value) > + { > + return Accessor<std::remove_reference_t<T>>{}.set(*this, std::forward<T>(value)); > + } > + > + DictAdapter asDict() const { return DictAdapter{ list_ }; } > + ListAdapter asList() const { return ListAdapter{ list_ }; } > + > + const YamlObject &operator[](std::size_t index) const; > + > + bool contains(std::string_view key) const; > + const YamlObject &operator[](std::string_view key) const; > + > + YamlObject *add(std::unique_ptr<YamlObject> child); > + YamlObject *add(std::string key, std::unique_ptr<YamlObject> child); > + > +private: > + LIBCAMERA_DISABLE_COPY_AND_MOVE(YamlObject) > + > + template<typename T> > + friend struct Accessor; > + > + enum class Type { > + Dictionary, > + List, > + Value, > + Empty, > + }; > + > + template<typename T, typename Enable = void> > + struct Accessor { > + std::optional<T> get(const YamlObject &obj) const; > + void set(YamlObject &obj, T value); > + }; > + > + Type type_; > + > + std::string value_; > + ValueContainer list_; > + std::map<std::string, YamlObject *, std::less<>> dictionary_; > +}; > + > +} /* namespace libcamera */ > diff --git a/include/libcamera/internal/yaml_parser.h b/include/libcamera/internal/yaml_parser.h > index 7b6d16de1a04..e503e83a80da 100644 > --- a/include/libcamera/internal/yaml_parser.h > +++ b/include/libcamera/internal/yaml_parser.h > @@ -7,221 +7,13 @@ > > #pragma once > > -#include <iterator> > -#include <map> > -#include <optional> > -#include <stdint.h> > -#include <string> > -#include <string_view> > -#include <vector> > +#include <memory> > > -#include <libcamera/base/class.h> > +#include "libcamera/internal/yaml_object.h" > > namespace libcamera { > > class File; > -class YamlParserContext; > - > -class YamlObject > -{ > -private: > - struct Value { > - Value(std::string &&k, std::unique_ptr<YamlObject> &&v) > - : key(std::move(k)), value(std::move(v)) > - { > - } > - std::string key; > - std::unique_ptr<YamlObject> value; > - }; > - > - using ValueContainer = std::vector<Value>; > - > -public: > -#ifndef __DOXYGEN__ > - template<typename Derived> > - class Iterator > - { > - public: > - using difference_type = std::ptrdiff_t; > - using iterator_category = std::forward_iterator_tag; > - > - Iterator(typename ValueContainer::const_iterator it) > - : it_(it) > - { > - } > - > - Derived &operator++() > - { > - ++it_; > - return *static_cast<Derived *>(this); > - } > - > - Derived operator++(int) > - { > - Derived it = *static_cast<Derived *>(this); > - it_++; > - return it; > - } > - > - friend bool operator==(const Iterator &a, const Iterator &b) > - { > - return a.it_ == b.it_; > - } > - > - friend bool operator!=(const Iterator &a, const Iterator &b) > - { > - return a.it_ != b.it_; > - } > - > - protected: > - ValueContainer::const_iterator it_; > - }; > - > - template<typename Iterator> > - class Adapter > - { > - public: > - Adapter(const ValueContainer &container) > - : container_(container) > - { > - } > - > - Iterator begin() const > - { > - return Iterator{ container_.begin() }; > - } > - > - Iterator end() const > - { > - return Iterator{ container_.end() }; > - } > - > - protected: > - const ValueContainer &container_; > - }; > - > - class ListIterator : public Iterator<ListIterator> > - { > - public: > - using value_type = const YamlObject &; > - using pointer = const YamlObject *; > - using reference = value_type; > - > - value_type operator*() const > - { > - return *it_->value.get(); > - } > - > - pointer operator->() const > - { > - return it_->value.get(); > - } > - }; > - > - class DictIterator : public Iterator<DictIterator> > - { > - public: > - using value_type = std::pair<const std::string &, const YamlObject &>; > - using pointer = value_type *; > - using reference = value_type &; > - > - value_type operator*() const > - { > - return { it_->key, *it_->value.get() }; > - } > - }; > - > - class DictAdapter : public Adapter<DictIterator> > - { > - public: > - using key_type = std::string; > - }; > - > - class ListAdapter : public Adapter<ListIterator> > - { > - }; > -#endif /* __DOXYGEN__ */ > - > - YamlObject(); > - ~YamlObject(); > - > - bool isValue() const > - { > - return type_ == Type::Value; > - } > - bool isList() const > - { > - return type_ == Type::List; > - } > - bool isDictionary() const > - { > - return type_ == Type::Dictionary; > - } > - bool isEmpty() const > - { > - return type_ == Type::Empty; > - } > - explicit operator bool() const > - { > - return type_ != Type::Empty; > - } > - > - std::size_t size() const; > - > - template<typename T> > - std::optional<T> get() const > - { > - return Accessor<T>{}.get(*this); > - } > - > - template<typename T, typename U> > - T get(U &&defaultValue) const > - { > - return get<T>().value_or(std::forward<U>(defaultValue)); > - } > - > - template<typename T> > - void set(T &&value) > - { > - return Accessor<std::remove_reference_t<T>>{}.set(*this, std::forward<T>(value)); > - } > - > - DictAdapter asDict() const { return DictAdapter{ list_ }; } > - ListAdapter asList() const { return ListAdapter{ list_ }; } > - > - const YamlObject &operator[](std::size_t index) const; > - > - bool contains(std::string_view key) const; > - const YamlObject &operator[](std::string_view key) const; > - > - YamlObject *add(std::unique_ptr<YamlObject> child); > - YamlObject *add(std::string key, std::unique_ptr<YamlObject> child); > - > -private: > - LIBCAMERA_DISABLE_COPY_AND_MOVE(YamlObject) > - > - template<typename T> > - friend struct Accessor; > - > - enum class Type { > - Dictionary, > - List, > - Value, > - Empty, > - }; > - > - template<typename T, typename Enable = void> > - struct Accessor { > - std::optional<T> get(const YamlObject &obj) const; > - void set(YamlObject &obj, T value); > - }; > - > - Type type_; > - > - std::string value_; > - ValueContainer list_; > - std::map<std::string, YamlObject *, std::less<>> dictionary_; > -}; > > class YamlParser final > { > diff --git a/src/ipa/libipa/agc_mean_luminance.h b/src/ipa/libipa/agc_mean_luminance.h > index 0df97b27332d..dfe1ccbe948b 100644 > --- a/src/ipa/libipa/agc_mean_luminance.h > +++ b/src/ipa/libipa/agc_mean_luminance.h > @@ -16,7 +16,7 @@ > > #include <libcamera/controls.h> > > -#include "libcamera/internal/yaml_parser.h" > +#include "libcamera/internal/yaml_object.h" > > #include "exposure_mode_helper.h" > #include "histogram.h" > diff --git a/src/ipa/libipa/awb.h b/src/ipa/libipa/awb.h > index f4a86038635f..3f25d13feaa8 100644 > --- a/src/ipa/libipa/awb.h > +++ b/src/ipa/libipa/awb.h > @@ -14,7 +14,7 @@ > #include <libcamera/controls.h> > > #include "libcamera/internal/vector.h" > -#include "libcamera/internal/yaml_parser.h" > +#include "libcamera/internal/yaml_object.h" > > namespace libcamera { > > diff --git a/src/ipa/libipa/awb_bayes.h b/src/ipa/libipa/awb_bayes.h > index 47ef3cce4d58..79334ad3e7a3 100644 > --- a/src/ipa/libipa/awb_bayes.h > +++ b/src/ipa/libipa/awb_bayes.h > @@ -10,7 +10,7 @@ > #include <libcamera/controls.h> > > #include "libcamera/internal/vector.h" > -#include "libcamera/internal/yaml_parser.h" > +#include "libcamera/internal/yaml_object.h" > > #include "awb.h" > #include "interpolator.h" > diff --git a/src/ipa/libipa/interpolator.cpp b/src/ipa/libipa/interpolator.cpp > index f901a86e4c74..9355802f796a 100644 > --- a/src/ipa/libipa/interpolator.cpp > +++ b/src/ipa/libipa/interpolator.cpp > @@ -11,8 +11,6 @@ > > #include <libcamera/base/log.h> > > -#include "libcamera/internal/yaml_parser.h" > - > #include "interpolator.h" > > /** > diff --git a/src/ipa/libipa/interpolator.h b/src/ipa/libipa/interpolator.h > index 7880db6976d1..08003a06dbba 100644 > --- a/src/ipa/libipa/interpolator.h > +++ b/src/ipa/libipa/interpolator.h > @@ -15,7 +15,7 @@ > > #include <libcamera/base/log.h> > > -#include "libcamera/internal/yaml_parser.h" > +#include "libcamera/internal/yaml_object.h" > > namespace libcamera { > > diff --git a/src/ipa/libipa/lsc_polynomial.h b/src/ipa/libipa/lsc_polynomial.h > index c71f215de3fc..19da46860849 100644 > --- a/src/ipa/libipa/lsc_polynomial.h > +++ b/src/ipa/libipa/lsc_polynomial.h > @@ -16,7 +16,7 @@ > > #include <libcamera/geometry.h> > > -#include "libcamera/internal/yaml_parser.h" > +#include "libcamera/internal/yaml_object.h" > > namespace libcamera { > > diff --git a/src/ipa/libipa/lux.cpp b/src/ipa/libipa/lux.cpp > index 899e88248f04..d79b116a3339 100644 > --- a/src/ipa/libipa/lux.cpp > +++ b/src/ipa/libipa/lux.cpp > @@ -12,7 +12,7 @@ > > #include <libcamera/base/log.h> > > -#include "libcamera/internal/yaml_parser.h" > +#include "libcamera/internal/yaml_object.h" > > #include "histogram.h" > > diff --git a/src/ipa/libipa/module.h b/src/ipa/libipa/module.h > index c27af7718feb..8e6c658a6b63 100644 > --- a/src/ipa/libipa/module.h > +++ b/src/ipa/libipa/module.h > @@ -15,7 +15,7 @@ > #include <libcamera/base/log.h> > #include <libcamera/base/utils.h> > > -#include "libcamera/internal/yaml_parser.h" > +#include "libcamera/internal/yaml_object.h" > > #include "algorithm.h" > > diff --git a/src/ipa/mali-c55/algorithms/blc.cpp b/src/ipa/mali-c55/algorithms/blc.cpp > index d099219c3e43..3bdf19141e1d 100644 > --- a/src/ipa/mali-c55/algorithms/blc.cpp > +++ b/src/ipa/mali-c55/algorithms/blc.cpp > @@ -10,7 +10,7 @@ > #include <libcamera/base/log.h> > #include <libcamera/control_ids.h> > > -#include "libcamera/internal/yaml_parser.h" > +#include "libcamera/internal/yaml_object.h" > > /** > * \file blc.h > diff --git a/src/ipa/mali-c55/algorithms/lsc.cpp b/src/ipa/mali-c55/algorithms/lsc.cpp > index f75b9cd7b7b8..e32f5a83485e 100644 > --- a/src/ipa/mali-c55/algorithms/lsc.cpp > +++ b/src/ipa/mali-c55/algorithms/lsc.cpp > @@ -7,7 +7,7 @@ > > #include "lsc.h" > > -#include "libcamera/internal/yaml_parser.h" > +#include "libcamera/internal/yaml_object.h" > > namespace libcamera { > > diff --git a/src/ipa/rkisp1/algorithms/agc.cpp b/src/ipa/rkisp1/algorithms/agc.cpp > index 7cc06f91ac2b..ef16a3775056 100644 > --- a/src/ipa/rkisp1/algorithms/agc.cpp > +++ b/src/ipa/rkisp1/algorithms/agc.cpp > @@ -19,7 +19,7 @@ > #include <libcamera/control_ids.h> > #include <libcamera/ipa/core_ipa_interface.h> > > -#include "libcamera/internal/yaml_parser.h" > +#include "libcamera/internal/yaml_object.h" > > #include "libipa/histogram.h" > > diff --git a/src/ipa/rkisp1/algorithms/blc.cpp b/src/ipa/rkisp1/algorithms/blc.cpp > index 32fc44ffff92..19c262fffa73 100644 > --- a/src/ipa/rkisp1/algorithms/blc.cpp > +++ b/src/ipa/rkisp1/algorithms/blc.cpp > @@ -13,7 +13,7 @@ > > #include <libcamera/control_ids.h> > > -#include "libcamera/internal/yaml_parser.h" > +#include "libcamera/internal/yaml_object.h" > > /** > * \file blc.h > diff --git a/src/ipa/rkisp1/algorithms/ccm.cpp b/src/ipa/rkisp1/algorithms/ccm.cpp > index de2b6fe775aa..3ed307280677 100644 > --- a/src/ipa/rkisp1/algorithms/ccm.cpp > +++ b/src/ipa/rkisp1/algorithms/ccm.cpp > @@ -16,7 +16,7 @@ > > #include <libcamera/ipa/core_ipa_interface.h> > > -#include "libcamera/internal/yaml_parser.h" > +#include "libcamera/internal/yaml_object.h" > > #include "libipa/fixedpoint.h" > #include "libipa/interpolator.h" > diff --git a/src/ipa/rkisp1/algorithms/dpcc.cpp b/src/ipa/rkisp1/algorithms/dpcc.cpp > index 7894628144f3..c195334750e1 100644 > --- a/src/ipa/rkisp1/algorithms/dpcc.cpp > +++ b/src/ipa/rkisp1/algorithms/dpcc.cpp > @@ -9,7 +9,7 @@ > > #include <libcamera/base/log.h> > > -#include "libcamera/internal/yaml_parser.h" > +#include "libcamera/internal/yaml_object.h" > > #include "linux/rkisp1-config.h" > > diff --git a/src/ipa/rkisp1/algorithms/goc.cpp b/src/ipa/rkisp1/algorithms/goc.cpp > index a0e7030fe5db..6c07bd8c71e5 100644 > --- a/src/ipa/rkisp1/algorithms/goc.cpp > +++ b/src/ipa/rkisp1/algorithms/goc.cpp > @@ -13,7 +13,7 @@ > > #include <libcamera/control_ids.h> > > -#include "libcamera/internal/yaml_parser.h" > +#include "libcamera/internal/yaml_object.h" > > #include "linux/rkisp1-config.h" > > diff --git a/src/ipa/rkisp1/algorithms/gsl.cpp b/src/ipa/rkisp1/algorithms/gsl.cpp > index 7ac5dc215850..292d0e80dc57 100644 > --- a/src/ipa/rkisp1/algorithms/gsl.cpp > +++ b/src/ipa/rkisp1/algorithms/gsl.cpp > @@ -10,7 +10,7 @@ > #include <libcamera/base/log.h> > #include <libcamera/base/utils.h> > > -#include "libcamera/internal/yaml_parser.h" > +#include "libcamera/internal/yaml_object.h" > > #include "linux/rkisp1-config.h" > > diff --git a/src/ipa/rkisp1/algorithms/lsc.cpp b/src/ipa/rkisp1/algorithms/lsc.cpp > index 429565a0b51f..9c0ed44b3943 100644 > --- a/src/ipa/rkisp1/algorithms/lsc.cpp > +++ b/src/ipa/rkisp1/algorithms/lsc.cpp > @@ -14,7 +14,7 @@ > #include <libcamera/base/log.h> > #include <libcamera/base/utils.h> > > -#include "libcamera/internal/yaml_parser.h" > +#include "libcamera/internal/yaml_object.h" > > #include "libipa/lsc_polynomial.h" > #include "linux/rkisp1-config.h" > diff --git a/src/ipa/rkisp1/algorithms/wdr.cpp b/src/ipa/rkisp1/algorithms/wdr.cpp > index ed81628c032c..9e2688a05179 100644 > --- a/src/ipa/rkisp1/algorithms/wdr.cpp > +++ b/src/ipa/rkisp1/algorithms/wdr.cpp > @@ -10,7 +10,7 @@ > #include <libcamera/base/log.h> > #include <libcamera/base/utils.h> > > -#include "libcamera/internal/yaml_parser.h" > +#include "libcamera/internal/yaml_object.h" > > #include <libipa/agc_mean_luminance.h> > #include <libipa/histogram.h> > diff --git a/src/ipa/rpi/controller/algorithm.h b/src/ipa/rpi/controller/algorithm.h > index 1971bfdcc8ad..8839daa90916 100644 > --- a/src/ipa/rpi/controller/algorithm.h > +++ b/src/ipa/rpi/controller/algorithm.h > @@ -15,7 +15,7 @@ > #include <memory> > #include <map> > > -#include "libcamera/internal/yaml_parser.h" > +#include "libcamera/internal/yaml_object.h" > > #include "controller.h" > > diff --git a/src/ipa/rpi/controller/controller.h b/src/ipa/rpi/controller/controller.h > index fdb46557de9c..573942886bc0 100644 > --- a/src/ipa/rpi/controller/controller.h > +++ b/src/ipa/rpi/controller/controller.h > @@ -16,7 +16,7 @@ > #include <string> > > #include <libcamera/base/utils.h> > -#include "libcamera/internal/yaml_parser.h" > +#include "libcamera/internal/yaml_object.h" > > #include "camera_mode.h" > #include "device_status.h" > diff --git a/src/libcamera/geometry.cpp b/src/libcamera/geometry.cpp > index 2e8e9e33ea78..621008844c74 100644 > --- a/src/libcamera/geometry.cpp > +++ b/src/libcamera/geometry.cpp > @@ -12,7 +12,7 @@ > > #include <libcamera/base/log.h> > > -#include "libcamera/internal/yaml_parser.h" > +#include "libcamera/internal/yaml_object.h" > > /** > * \file geometry.h > diff --git a/src/libcamera/meson.build b/src/libcamera/meson.build > index 6f952bd9832a..da89aa3714c3 100644 > --- a/src/libcamera/meson.build > +++ b/src/libcamera/meson.build > @@ -58,6 +58,7 @@ libcamera_internal_sources = files([ > 'v4l2_subdevice.cpp', > 'v4l2_videodevice.cpp', > 'vector.cpp', > + 'yaml_object.cpp', > 'yaml_parser.cpp', > ]) > > diff --git a/src/libcamera/pipeline/rpi/common/pipeline_base.cpp b/src/libcamera/pipeline/rpi/common/pipeline_base.cpp > index 7eb197ce435c..684438bd5fb7 100644 > --- a/src/libcamera/pipeline/rpi/common/pipeline_base.cpp > +++ b/src/libcamera/pipeline/rpi/common/pipeline_base.cpp > @@ -21,6 +21,7 @@ > > #include "libcamera/internal/camera_lens.h" > #include "libcamera/internal/v4l2_subdevice.h" > +#include "libcamera/internal/yaml_parser.h" > > using namespace std::chrono_literals; > > diff --git a/src/libcamera/pipeline/rpi/common/pipeline_base.h b/src/libcamera/pipeline/rpi/common/pipeline_base.h > index 6257a93467df..c69a690f580c 100644 > --- a/src/libcamera/pipeline/rpi/common/pipeline_base.h > +++ b/src/libcamera/pipeline/rpi/common/pipeline_base.h > @@ -26,7 +26,7 @@ > #include "libcamera/internal/pipeline_handler.h" > #include "libcamera/internal/request.h" > #include "libcamera/internal/v4l2_videodevice.h" > -#include "libcamera/internal/yaml_parser.h" > +#include "libcamera/internal/yaml_object.h" > > #include <libcamera/ipa/raspberrypi_ipa_interface.h> > #include <libcamera/ipa/raspberrypi_ipa_proxy.h> > diff --git a/src/libcamera/pipeline/virtual/config_parser.h b/src/libcamera/pipeline/virtual/config_parser.h > index d2000de9c12f..f696d8862897 100644 > --- a/src/libcamera/pipeline/virtual/config_parser.h > +++ b/src/libcamera/pipeline/virtual/config_parser.h > @@ -13,7 +13,7 @@ > #include <libcamera/base/file.h> > > #include "libcamera/internal/pipeline_handler.h" > -#include "libcamera/internal/yaml_parser.h" > +#include "libcamera/internal/yaml_object.h" > > #include "virtual.h" > > diff --git a/src/libcamera/pipeline/virtual/virtual.cpp b/src/libcamera/pipeline/virtual/virtual.cpp > index 40c35264c568..b032db54ded4 100644 > --- a/src/libcamera/pipeline/virtual/virtual.cpp > +++ b/src/libcamera/pipeline/virtual/virtual.cpp > @@ -36,7 +36,7 @@ > #include "libcamera/internal/framebuffer.h" > #include "libcamera/internal/pipeline_handler.h" > #include "libcamera/internal/request.h" > -#include "libcamera/internal/yaml_parser.h" > +#include "libcamera/internal/yaml_object.h" > > #include "pipeline/virtual/config_parser.h" > > diff --git a/src/libcamera/yaml_object.cpp b/src/libcamera/yaml_object.cpp > new file mode 100644 > index 000000000000..5e92189fdb8e > --- /dev/null > +++ b/src/libcamera/yaml_object.cpp > @@ -0,0 +1,477 @@ > +/* SPDX-License-Identifier: LGPL-2.1-or-later */ > +/* > + * Copyright (C) 2022, Google Inc. > + * Copyright (C) 2025, Ideas on Board. > + * > + * libcamera YAML object > + */ > + > +#include "libcamera/internal/yaml_object.h" > + > +#include <charconv> > +#include <errno.h> > +#include <string> > +#include <vector> > + > +#include <libcamera/base/utils.h> > + > +/** > + * \file yaml_object.h > + * \brief YAML objects > + */ > + > +namespace libcamera { > + > +namespace { > + > +/* Empty static YamlObject as a safe result for invalid operations */ > +static const YamlObject empty; > + > +} /* namespace */ > + > +/** > + * \class YamlObject > + * \brief A class representing the tree structure of the YAML content > + * > + * The YamlObject class represents the tree structure of YAML content. A > + * YamlObject can be empty, a dictionary or list of YamlObjects, or a value if a > + * tree leaf. > + */ > + > +YamlObject::YamlObject() > + : type_(Type::Empty) > +{ > +} > + > +YamlObject::~YamlObject() = default; > + > +/** > + * \fn YamlObject::isValue() > + * \brief Return whether the YamlObject is a value > + * > + * \return True if the YamlObject is a value, false otherwise > + */ > + > +/** > + * \fn YamlObject::isList() > + * \brief Return whether the YamlObject is a list > + * > + * \return True if the YamlObject is a list, false otherwise > + */ > + > +/** > + * \fn YamlObject::isDictionary() > + * \brief Return whether the YamlObject is a dictionary > + * > + * \return True if the YamlObject is a dictionary, false otherwise > + */ > + > +/** > + * \fn YamlObject::isEmpty() > + * \brief Return whether the YamlObject is an empty > + * > + * \return True if the YamlObject is empty, false otherwise > + */ > + > +/** > + * \fn YamlObject::operator bool() > + * \brief Return whether the YamlObject is a non-empty > + * > + * \return False if the YamlObject is empty, true otherwise > + */ > + > +/** > + * \fn YamlObject::size() > + * \brief Retrieve the number of elements in a dictionary or list YamlObject > + * > + * This function retrieves the size of the YamlObject, defined as the number of > + * child elements it contains. Only YamlObject instances of Dictionary or List > + * types have a size, calling this function on other types of instances is > + * invalid and results in undefined behaviour. > + * > + * \return The size of the YamlObject > + */ > +std::size_t YamlObject::size() const > +{ > + switch (type_) { > + case Type::Dictionary: > + case Type::List: > + return list_.size(); > + default: > + return 0; > + } > +} > + > +/** > + * \fn template<typename T> YamlObject::get<T>() 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 > + */ > + > +/** > + * \fn template<typename T, typename U> YamlObject::get<T>(U &&defaultValue) const > + * \brief Parse the YamlObject as a \a T value > + * \param[in] defaultValue The default value when failing to parse > + * > + * 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. > + * > + * 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 > + */ > + > +/** > + * \fn template<typename T> YamlObject::set<T>(T &&value) > + * \brief Set the value of a YamlObject > + * \param[in] value The value > + * > + * This function sets the value stored in a YamlObject to \a value. The value is > + * converted to a string in an implementation-specific way that guarantees that > + * subsequent calls to get<T>() will return the same value. > + * > + * Values can only be set on YamlObject of Type::Value type or empty YamlObject. > + * Attempting to set a value on an object of type Type::Dict or Type::List does > + * not modify the YamlObject. > + */ > + > +#ifndef __DOXYGEN__ > + > +template<> > +std::optional<bool> > +YamlObject::Accessor<bool>::get(const YamlObject &obj) const > +{ > + if (obj.type_ != Type::Value) > + return std::nullopt; > + > + if (obj.value_ == "true") > + return true; > + else if (obj.value_ == "false") > + return false; > + > + return std::nullopt; > +} > + > +template<> > +void YamlObject::Accessor<bool>::set(YamlObject &obj, bool value) > +{ > + if (obj.type_ != Type::Empty && obj.type_ != Type::Value) > + return; > + > + obj.type_ = Type::Value; > + obj.value_ = value ? "true" : "false"; > +} > + > +template<typename T> > +struct YamlObject::Accessor<T, std::enable_if_t< > + std::is_same_v<int8_t, T> || > + std::is_same_v<uint8_t, T> || > + std::is_same_v<int16_t, T> || > + std::is_same_v<uint16_t, T> || > + std::is_same_v<int32_t, T> || > + std::is_same_v<uint32_t, T>>> > +{ > + std::optional<T> get(const YamlObject &obj) const > + { > + if (obj.type_ != Type::Value) > + return std::nullopt; > + > + const std::string &str = obj.value_; > + T value; > + > + auto [ptr, ec] = std::from_chars(str.data(), str.data() + str.size(), > + value); > + if (ptr != str.data() + str.size() || ec != std::errc()) > + return std::nullopt; > + > + return value; > + } > + > + void set(YamlObject &obj, T value) > + { > + if (obj.type_ != Type::Empty && obj.type_ != Type::Value) > + return; > + > + obj.type_ = Type::Value; > + obj.value_ = std::to_string(value); > + } > +}; > + > +template struct YamlObject::Accessor<int8_t>; > +template struct YamlObject::Accessor<uint8_t>; > +template struct YamlObject::Accessor<int16_t>; > +template struct YamlObject::Accessor<uint16_t>; > +template struct YamlObject::Accessor<int32_t>; > +template struct YamlObject::Accessor<uint32_t>; > + > +template<> > +std::optional<float> > +YamlObject::Accessor<float>::get(const YamlObject &obj) const > +{ > + return obj.get<double>(); > +} > + > +template<> > +void YamlObject::Accessor<float>::set(YamlObject &obj, float value) > +{ > + obj.set<double>(std::forward<float>(value)); > +} > + > +template<> > +std::optional<double> > +YamlObject::Accessor<double>::get(const YamlObject &obj) const > +{ > + if (obj.type_ != Type::Value) > + return std::nullopt; > + > + if (obj.value_.empty()) > + return std::nullopt; > + > + char *end; > + > + errno = 0; > + double value = utils::strtod(obj.value_.c_str(), &end); > + > + if ('\0' != *end || errno == ERANGE) > + return std::nullopt; > + > + return value; > +} > + > +template<> > +void YamlObject::Accessor<double>::set(YamlObject &obj, double value) > +{ > + if (obj.type_ != Type::Empty && obj.type_ != Type::Value) > + return; > + > + obj.type_ = Type::Value; > + obj.value_ = std::to_string(value); > +} > + > +template<> > +std::optional<std::string> > +YamlObject::Accessor<std::string>::get(const YamlObject &obj) const > +{ > + if (obj.type_ != Type::Value) > + return std::nullopt; > + > + return obj.value_; > +} > + > +template<> > +void YamlObject::Accessor<std::string>::set(YamlObject &obj, std::string value) > +{ > + if (obj.type_ != Type::Empty && obj.type_ != Type::Value) > + return; > + > + obj.type_ = Type::Value; > + obj.value_ = std::move(value); > +} > + > +template<typename T> > +struct YamlObject::Accessor<std::vector<T>, std::enable_if_t< > + std::is_same_v<bool, T> || > + std::is_same_v<float, T> || > + std::is_same_v<double, T> || > + std::is_same_v<int8_t, T> || > + std::is_same_v<uint8_t, T> || > + std::is_same_v<int16_t, T> || > + std::is_same_v<uint16_t, T> || > + std::is_same_v<int32_t, T> || > + std::is_same_v<uint32_t, T> || > + std::is_same_v<std::string, T>>> > +{ > + std::optional<std::vector<T>> get(const YamlObject &obj) const > + { > + if (obj.type_ != Type::List) > + return std::nullopt; > + > + std::vector<T> values; > + values.reserve(obj.list_.size()); > + > + for (const YamlObject &entry : obj.asList()) { > + const auto value = entry.get<T>(); > + if (!value) > + return std::nullopt; > + values.emplace_back(*value); > + } > + > + return values; > + } > +}; > + > +template struct YamlObject::Accessor<std::vector<bool>>; > +template struct YamlObject::Accessor<std::vector<float>>; > +template struct YamlObject::Accessor<std::vector<double>>; > +template struct YamlObject::Accessor<std::vector<int8_t>>; > +template struct YamlObject::Accessor<std::vector<uint8_t>>; > +template struct YamlObject::Accessor<std::vector<int16_t>>; > +template struct YamlObject::Accessor<std::vector<uint16_t>>; > +template struct YamlObject::Accessor<std::vector<int32_t>>; > +template struct YamlObject::Accessor<std::vector<uint32_t>>; > +template struct YamlObject::Accessor<std::vector<std::string>>; > +#endif /* __DOXYGEN__ */ > + > +/** > + * \fn YamlObject::asDict() const > + * \brief Wrap a dictionary YamlObject in an adapter that exposes iterators > + * > + * The YamlObject class doesn't directly implement iterators, as the iterator > + * type depends on whether the object is a Dictionary or List. This function > + * wraps a YamlObject of Dictionary type into an adapter that exposes > + * iterators, as well as begin() and end() functions, allowing usage of > + * range-based for loops with YamlObject. As YAML mappings are not ordered, the > + * iteration order is not specified. > + * > + * The iterator's value_type is a > + * <em>std::pair<const std::string &, const \ref YamlObject &></em>. > + * > + * If the YamlObject is not of Dictionary type, the returned adapter operates > + * as an empty container. > + * > + * \return An adapter of unspecified type compatible with range-based for loops > + */ > + > +/** > + * \fn YamlObject::asList() const > + * \brief Wrap a list YamlObject in an adapter that exposes iterators > + * > + * The YamlObject class doesn't directly implement iterators, as the iterator > + * type depends on whether the object is a Dictionary or List. This function > + * wraps a YamlObject of List type into an adapter that exposes iterators, as > + * well as begin() and end() functions, allowing usage of range-based for loops > + * with YamlObject. As YAML lists are ordered, the iteration order is identical > + * to the list order in the YAML data. > + * > + * The iterator's value_type is a <em>const YamlObject &</em>. > + * > + * If the YamlObject is not of List type, the returned adapter operates as an > + * empty container. > + * > + * \return An adapter of unspecified type compatible with range-based for loops > + */ > + > +/** > + * \fn YamlObject::operator[](std::size_t index) const > + * \brief Retrieve the element from list YamlObject by index > + * > + * This function retrieves an element of the YamlObject. Only YamlObject > + * instances of List type associate elements with index, calling this function > + * on other types of instances or with an invalid index results in an empty > + * object. > + * > + * \return The YamlObject as an element of the list > + */ > +const YamlObject &YamlObject::operator[](std::size_t index) const > +{ > + if (type_ != Type::List || index >= size()) > + return empty; > + > + return *list_[index].value; > +} > + > +/** > + * \fn YamlObject::contains() > + * \brief Check if an element of a dictionary exists > + * > + * This function check if the YamlObject contains an element. Only YamlObject > + * instances of Dictionary type associate elements with names, calling this > + * function on other types of instances is invalid and results in undefined > + * behaviour. > + * > + * \return True if an element exists, false otherwise > + */ > +bool YamlObject::contains(std::string_view key) const > +{ > + return dictionary_.find(key) != dictionary_.end(); > +} > + > +/** > + * \fn YamlObject::operator[](std::string_view key) const > + * \brief Retrieve a member by name from the dictionary > + * > + * This function retrieve a member of a YamlObject by name. Only YamlObject > + * instances of Dictionary type associate elements with names, calling this > + * function on other types of instances or with a nonexistent key results in an > + * empty object. > + * > + * \return The YamlObject corresponding to the \a key member > + */ > +const YamlObject &YamlObject::operator[](std::string_view key) const > +{ > + if (type_ != Type::Dictionary) > + return empty; > + > + auto iter = dictionary_.find(key); > + if (iter == dictionary_.end()) > + return empty; > + > + return *iter->second; > +} > + > +/** > + * \brief Add a child object to a list > + * \param[in] child The child object > + * > + * Append the \a child node as the last element of this node's children list. > + * This node must be empty, in which case it is converted to the Type::List > + * type, or be a list. Otherwise, the \a child is discarded and the function > + * returns a nullptr. > + * > + * \return The child object if successfully added, nullptr otherwise > + */ > +YamlObject *YamlObject::add(std::unique_ptr<YamlObject> child) > +{ > + if (type_ == Type::Empty) > + type_ = Type::List; > + > + if (type_ != Type::List) > + return nullptr; > + > + Value &elem = list_.emplace_back(std::string{}, std::move(child)); > + return elem.value.get(); > +} > + > +/** > + * \brief Add a child object to a dictionary > + * \param[in] key The dictionary key > + * \param[in] child The child object > + * > + * Add the \a child node with the given \a key to this node's children. This > + * node must be empty, in which case it is converted to the Type::Dictionary > + * type, or be a dictionary. Otherwise, the \a child is discarded and the > + * function returns a nullptr. > + * > + * Keys are unique. If a child with the same \a key already exist, the \a child > + * is discarded and the function returns a nullptr. > + * > + * \return The child object if successfully added, nullptr otherwise > + */ > +YamlObject *YamlObject::add(std::string key, std::unique_ptr<YamlObject> child) > +{ > + if (type_ == Type::Empty) > + type_ = Type::Dictionary; > + > + if (type_ != Type::Dictionary) > + return nullptr; > + > + if (dictionary_.find(key) != dictionary_.end()) > + return nullptr; > + > + Value &elem = list_.emplace_back(std::move(key), std::move(child)); > + dictionary_.emplace(elem.key, elem.value.get()); > + return elem.value.get(); > +} > + > +} /* namespace libcamera */ > diff --git a/src/libcamera/yaml_parser.cpp b/src/libcamera/yaml_parser.cpp > index 0ef1f3ea303b..d83df0fb9597 100644 > --- a/src/libcamera/yaml_parser.cpp > +++ b/src/libcamera/yaml_parser.cpp > @@ -7,11 +7,10 @@ > > #include "libcamera/internal/yaml_parser.h" > > -#include <charconv> > #include <errno.h> > #include <functional> > -#include <limits> > -#include <stdlib.h> > +#include <memory> > +#include <string> > > #include <libcamera/base/file.h> > #include <libcamera/base/log.h> > @@ -27,459 +26,6 @@ namespace libcamera { > > LOG_DEFINE_CATEGORY(YamlParser) > > -namespace { > - > -/* Empty static YamlObject as a safe result for invalid operations */ > -static const YamlObject empty; > - > -} /* namespace */ > - > -/** > - * \class YamlObject > - * \brief A class representing the tree structure of the YAML content > - * > - * The YamlObject class represents the tree structure of YAML content. A > - * YamlObject can be empty, a dictionary or list of YamlObjects, or a value if a > - * tree leaf. > - */ > - > -YamlObject::YamlObject() > - : type_(Type::Empty) > -{ > -} > - > -YamlObject::~YamlObject() = default; > - > -/** > - * \fn YamlObject::isValue() > - * \brief Return whether the YamlObject is a value > - * > - * \return True if the YamlObject is a value, false otherwise > - */ > - > -/** > - * \fn YamlObject::isList() > - * \brief Return whether the YamlObject is a list > - * > - * \return True if the YamlObject is a list, false otherwise > - */ > - > -/** > - * \fn YamlObject::isDictionary() > - * \brief Return whether the YamlObject is a dictionary > - * > - * \return True if the YamlObject is a dictionary, false otherwise > - */ > - > -/** > - * \fn YamlObject::isEmpty() > - * \brief Return whether the YamlObject is an empty > - * > - * \return True if the YamlObject is empty, false otherwise > - */ > - > -/** > - * \fn YamlObject::operator bool() > - * \brief Return whether the YamlObject is a non-empty > - * > - * \return False if the YamlObject is empty, true otherwise > - */ > - > -/** > - * \brief Retrieve the number of elements in a dictionary or list YamlObject > - * > - * This function retrieves the size of the YamlObject, defined as the number of > - * child elements it contains. Only YamlObject instances of Dictionary or List > - * types have a size, calling this function on other types of instances is > - * invalid and results in undefined behaviour. > - * > - * \return The size of the YamlObject > - */ > -std::size_t YamlObject::size() const > -{ > - switch (type_) { > - case Type::Dictionary: > - case Type::List: > - return list_.size(); > - default: > - return 0; > - } > -} > - > -/** > - * \fn template<typename T> YamlObject::get<T>() 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 > - */ > - > -/** > - * \fn template<typename T, typename U> YamlObject::get<T>(U &&defaultValue) const > - * \brief Parse the YamlObject as a \a T value > - * \param[in] defaultValue The default value when failing to parse > - * > - * 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. > - * > - * 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 > - */ > - > -/** > - * \fn template<typename T> YamlObject::set<T>(T &&value) > - * \brief Set the value of a YamlObject > - * \param[in] value The value > - * > - * This function sets the value stored in a YamlObject to \a value. The value is > - * converted to a string in an implementation-specific way that guarantees that > - * subsequent calls to get<T>() will return the same value. > - * > - * Values can only be set on YamlObject of Type::Value type or empty YamlObject. > - * Attempting to set a value on an object of type Type::Dict or Type::List does > - * not modify the YamlObject. > - */ > - > -#ifndef __DOXYGEN__ > - > -template<> > -std::optional<bool> > -YamlObject::Accessor<bool>::get(const YamlObject &obj) const > -{ > - if (obj.type_ != Type::Value) > - return std::nullopt; > - > - if (obj.value_ == "true") > - return true; > - else if (obj.value_ == "false") > - return false; > - > - return std::nullopt; > -} > - > -template<> > -void YamlObject::Accessor<bool>::set(YamlObject &obj, bool value) > -{ > - if (obj.type_ != Type::Empty && obj.type_ != Type::Value) > - return; > - > - obj.type_ = Type::Value; > - obj.value_ = value ? "true" : "false"; > -} > - > -template<typename T> > -struct YamlObject::Accessor<T, std::enable_if_t< > - std::is_same_v<int8_t, T> || > - std::is_same_v<uint8_t, T> || > - std::is_same_v<int16_t, T> || > - std::is_same_v<uint16_t, T> || > - std::is_same_v<int32_t, T> || > - std::is_same_v<uint32_t, T>>> > -{ > - std::optional<T> get(const YamlObject &obj) const > - { > - if (obj.type_ != Type::Value) > - return std::nullopt; > - > - const std::string &str = obj.value_; > - T value; > - > - auto [ptr, ec] = std::from_chars(str.data(), str.data() + str.size(), > - value); > - if (ptr != str.data() + str.size() || ec != std::errc()) > - return std::nullopt; > - > - return value; > - } > - > - void set(YamlObject &obj, T value) > - { > - if (obj.type_ != Type::Empty && obj.type_ != Type::Value) > - return; > - > - obj.type_ = Type::Value; > - obj.value_ = std::to_string(value); > - } > -}; > - > -template struct YamlObject::Accessor<int8_t>; > -template struct YamlObject::Accessor<uint8_t>; > -template struct YamlObject::Accessor<int16_t>; > -template struct YamlObject::Accessor<uint16_t>; > -template struct YamlObject::Accessor<int32_t>; > -template struct YamlObject::Accessor<uint32_t>; > - > -template<> > -std::optional<float> > -YamlObject::Accessor<float>::get(const YamlObject &obj) const > -{ > - return obj.get<double>(); > -} > - > -template<> > -void YamlObject::Accessor<float>::set(YamlObject &obj, float value) > -{ > - obj.set<double>(std::forward<float>(value)); > -} > - > -template<> > -std::optional<double> > -YamlObject::Accessor<double>::get(const YamlObject &obj) const > -{ > - if (obj.type_ != Type::Value) > - return std::nullopt; > - > - if (obj.value_.empty()) > - return std::nullopt; > - > - char *end; > - > - errno = 0; > - double value = utils::strtod(obj.value_.c_str(), &end); > - > - if ('\0' != *end || errno == ERANGE) > - return std::nullopt; > - > - return value; > -} > - > -template<> > -void YamlObject::Accessor<double>::set(YamlObject &obj, double value) > -{ > - if (obj.type_ != Type::Empty && obj.type_ != Type::Value) > - return; > - > - obj.type_ = Type::Value; > - obj.value_ = std::to_string(value); > -} > - > -template<> > -std::optional<std::string> > -YamlObject::Accessor<std::string>::get(const YamlObject &obj) const > -{ > - if (obj.type_ != Type::Value) > - return std::nullopt; > - > - return obj.value_; > -} > - > -template<> > -void YamlObject::Accessor<std::string>::set(YamlObject &obj, std::string value) > -{ > - if (obj.type_ != Type::Empty && obj.type_ != Type::Value) > - return; > - > - obj.type_ = Type::Value; > - obj.value_ = std::move(value); > -} > - > -template<typename T> > -struct YamlObject::Accessor<std::vector<T>, std::enable_if_t< > - std::is_same_v<bool, T> || > - std::is_same_v<float, T> || > - std::is_same_v<double, T> || > - std::is_same_v<int8_t, T> || > - std::is_same_v<uint8_t, T> || > - std::is_same_v<int16_t, T> || > - std::is_same_v<uint16_t, T> || > - std::is_same_v<int32_t, T> || > - std::is_same_v<uint32_t, T> || > - std::is_same_v<std::string, T>>> > -{ > - std::optional<std::vector<T>> get(const YamlObject &obj) const > - { > - if (obj.type_ != Type::List) > - return std::nullopt; > - > - std::vector<T> values; > - values.reserve(obj.list_.size()); > - > - for (const YamlObject &entry : obj.asList()) { > - const auto value = entry.get<T>(); > - if (!value) > - return std::nullopt; > - values.emplace_back(*value); > - } > - > - return values; > - } > -}; > - > -template struct YamlObject::Accessor<std::vector<bool>>; > -template struct YamlObject::Accessor<std::vector<float>>; > -template struct YamlObject::Accessor<std::vector<double>>; > -template struct YamlObject::Accessor<std::vector<int8_t>>; > -template struct YamlObject::Accessor<std::vector<uint8_t>>; > -template struct YamlObject::Accessor<std::vector<int16_t>>; > -template struct YamlObject::Accessor<std::vector<uint16_t>>; > -template struct YamlObject::Accessor<std::vector<int32_t>>; > -template struct YamlObject::Accessor<std::vector<uint32_t>>; > -template struct YamlObject::Accessor<std::vector<std::string>>; > -#endif /* __DOXYGEN__ */ > - > -/** > - * \fn YamlObject::asDict() const > - * \brief Wrap a dictionary YamlObject in an adapter that exposes iterators > - * > - * The YamlObject class doesn't directly implement iterators, as the iterator > - * type depends on whether the object is a Dictionary or List. This function > - * wraps a YamlObject of Dictionary type into an adapter that exposes > - * iterators, as well as begin() and end() functions, allowing usage of > - * range-based for loops with YamlObject. As YAML mappings are not ordered, the > - * iteration order is not specified. > - * > - * The iterator's value_type is a > - * <em>std::pair<const std::string &, const \ref YamlObject &></em>. > - * > - * If the YamlObject is not of Dictionary type, the returned adapter operates > - * as an empty container. > - * > - * \return An adapter of unspecified type compatible with range-based for loops > - */ > - > -/** > - * \fn YamlObject::asList() const > - * \brief Wrap a list YamlObject in an adapter that exposes iterators > - * > - * The YamlObject class doesn't directly implement iterators, as the iterator > - * type depends on whether the object is a Dictionary or List. This function > - * wraps a YamlObject of List type into an adapter that exposes iterators, as > - * well as begin() and end() functions, allowing usage of range-based for loops > - * with YamlObject. As YAML lists are ordered, the iteration order is identical > - * to the list order in the YAML data. > - * > - * The iterator's value_type is a <em>const YamlObject &</em>. > - * > - * If the YamlObject is not of List type, the returned adapter operates as an > - * empty container. > - * > - * \return An adapter of unspecified type compatible with range-based for loops > - */ > - > -/** > - * \fn YamlObject::operator[](std::size_t index) const > - * \brief Retrieve the element from list YamlObject by index > - * > - * This function retrieves an element of the YamlObject. Only YamlObject > - * instances of List type associate elements with index, calling this function > - * on other types of instances or with an invalid index results in an empty > - * object. > - * > - * \return The YamlObject as an element of the list > - */ > -const YamlObject &YamlObject::operator[](std::size_t index) const > -{ > - if (type_ != Type::List || index >= size()) > - return empty; > - > - return *list_[index].value; > -} > - > -/** > - * \fn YamlObject::contains() > - * \brief Check if an element of a dictionary exists > - * > - * This function check if the YamlObject contains an element. Only YamlObject > - * instances of Dictionary type associate elements with names, calling this > - * function on other types of instances is invalid and results in undefined > - * behaviour. > - * > - * \return True if an element exists, false otherwise > - */ > -bool YamlObject::contains(std::string_view key) const > -{ > - return dictionary_.find(key) != dictionary_.end(); > -} > - > -/** > - * \fn YamlObject::operator[](std::string_view key) const > - * \brief Retrieve a member by name from the dictionary > - * > - * This function retrieve a member of a YamlObject by name. Only YamlObject > - * instances of Dictionary type associate elements with names, calling this > - * function on other types of instances or with a nonexistent key results in an > - * empty object. > - * > - * \return The YamlObject corresponding to the \a key member > - */ > -const YamlObject &YamlObject::operator[](std::string_view key) const > -{ > - if (type_ != Type::Dictionary) > - return empty; > - > - auto iter = dictionary_.find(key); > - if (iter == dictionary_.end()) > - return empty; > - > - return *iter->second; > -} > - > -/** > - * \brief Add a child object to a list > - * \param[in] child The child object > - * > - * Append the \a child node as the last element of this node's children list. > - * This node must be empty, in which case it is converted to the Type::List > - * type, or be a list. Otherwise, the \a child is discarded and the function > - * returns a nullptr. > - * > - * \return A pointer to the child object if successfully added, nullptr > - * otherwise > - */ > -YamlObject *YamlObject::add(std::unique_ptr<YamlObject> child) > -{ > - if (type_ == Type::Empty) > - type_ = Type::List; > - > - if (type_ != Type::List) > - return nullptr; > - > - Value &elem = list_.emplace_back(std::string{}, std::move(child)); > - return elem.value.get(); > -} > - > -/** > - * \brief Add a child object to a dictionary > - * \param[in] key The dictionary key > - * \param[in] child The child object > - * > - * Add the \a child node with the given \a key to this node's children. This > - * node must be empty, in which case it is converted to the Type::Dictionary > - * type, or be a dictionary. Otherwise, the \a child is discarded and the > - * function returns a nullptr. > - * > - * Keys are unique. If a child with the same \a key already exist, the \a child > - * is discarded and the function returns a nullptr. > - * > - * \return A pointer to the child object if successfully added, nullptr > - * otherwise > - */ > -YamlObject *YamlObject::add(std::string key, std::unique_ptr<YamlObject> child) > -{ > - if (type_ == Type::Empty) > - type_ = Type::Dictionary; > - > - if (type_ != Type::Dictionary) > - return nullptr; > - > - if (dictionary_.find(key) != dictionary_.end()) > - return nullptr; > - > - Value &elem = list_.emplace_back(std::move(key), std::move(child)); > - dictionary_.emplace(elem.key, elem.value.get()); > - return elem.value.get(); > -} > - > #ifndef __DOXYGEN__ > > class YamlParserContext
diff --git a/include/libcamera/internal/global_configuration.h b/include/libcamera/internal/global_configuration.h index 8d09517edca1..16c6a21f2a8a 100644 --- a/include/libcamera/internal/global_configuration.h +++ b/include/libcamera/internal/global_configuration.h @@ -14,7 +14,7 @@ #include <libcamera/base/utils.h> -#include "libcamera/internal/yaml_parser.h" +#include "libcamera/internal/yaml_object.h" namespace libcamera { diff --git a/include/libcamera/internal/matrix.h b/include/libcamera/internal/matrix.h index 67761cb6037d..11fccd27547e 100644 --- a/include/libcamera/internal/matrix.h +++ b/include/libcamera/internal/matrix.h @@ -14,7 +14,7 @@ #include <libcamera/base/log.h> #include <libcamera/base/span.h> -#include "libcamera/internal/yaml_parser.h" +#include "libcamera/internal/yaml_object.h" namespace libcamera { diff --git a/include/libcamera/internal/meson.build b/include/libcamera/internal/meson.build index dc48619e5ac8..c24c9f062f29 100644 --- a/include/libcamera/internal/meson.build +++ b/include/libcamera/internal/meson.build @@ -50,6 +50,7 @@ libcamera_internal_headers = files([ 'v4l2_subdevice.h', 'v4l2_videodevice.h', 'vector.h', + 'yaml_object.h', 'yaml_parser.h', ]) diff --git a/include/libcamera/internal/vector.h b/include/libcamera/internal/vector.h index cfd8882ce0e6..af24485f3bb1 100644 --- a/include/libcamera/internal/vector.h +++ b/include/libcamera/internal/vector.h @@ -19,7 +19,7 @@ #include <libcamera/base/span.h> #include "libcamera/internal/matrix.h" -#include "libcamera/internal/yaml_parser.h" +#include "libcamera/internal/yaml_object.h" namespace libcamera { diff --git a/include/libcamera/internal/yaml_object.h b/include/libcamera/internal/yaml_object.h new file mode 100644 index 000000000000..1771f8821e2e --- /dev/null +++ b/include/libcamera/internal/yaml_object.h @@ -0,0 +1,226 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2022, Google Inc. + * Copyright (C) 2025, Ideas on Board + * + * libcamera YAML object + */ + +#pragma once + +#include <iterator> +#include <map> +#include <memory> +#include <optional> +#include <string> +#include <string_view> +#include <type_traits> +#include <utility> +#include <vector> + +#include <libcamera/base/class.h> + +namespace libcamera { + +class YamlObject +{ +private: + struct Value { + Value(std::string &&k, std::unique_ptr<YamlObject> &&v) + : key(std::move(k)), value(std::move(v)) + { + } + std::string key; + std::unique_ptr<YamlObject> value; + }; + + using ValueContainer = std::vector<Value>; + +public: +#ifndef __DOXYGEN__ + template<typename Derived> + class Iterator + { + public: + using difference_type = std::ptrdiff_t; + using iterator_category = std::forward_iterator_tag; + + Iterator(typename ValueContainer::const_iterator it) + : it_(it) + { + } + + Derived &operator++() + { + ++it_; + return *static_cast<Derived *>(this); + } + + Derived operator++(int) + { + Derived it = *static_cast<Derived *>(this); + it_++; + return it; + } + + friend bool operator==(const Iterator &a, const Iterator &b) + { + return a.it_ == b.it_; + } + + friend bool operator!=(const Iterator &a, const Iterator &b) + { + return a.it_ != b.it_; + } + + protected: + ValueContainer::const_iterator it_; + }; + + template<typename Iterator> + class Adapter + { + public: + Adapter(const ValueContainer &container) + : container_(container) + { + } + + Iterator begin() const + { + return Iterator{ container_.begin() }; + } + + Iterator end() const + { + return Iterator{ container_.end() }; + } + + protected: + const ValueContainer &container_; + }; + + class ListIterator : public Iterator<ListIterator> + { + public: + using value_type = const YamlObject &; + using pointer = const YamlObject *; + using reference = value_type; + + value_type operator*() const + { + return *it_->value.get(); + } + + pointer operator->() const + { + return it_->value.get(); + } + }; + + class DictIterator : public Iterator<DictIterator> + { + public: + using value_type = std::pair<const std::string &, const YamlObject &>; + using pointer = value_type *; + using reference = value_type &; + + value_type operator*() const + { + return { it_->key, *it_->value.get() }; + } + }; + + class DictAdapter : public Adapter<DictIterator> + { + public: + using key_type = std::string; + }; + + class ListAdapter : public Adapter<ListIterator> + { + }; +#endif /* __DOXYGEN__ */ + + YamlObject(); + ~YamlObject(); + + bool isValue() const + { + return type_ == Type::Value; + } + bool isList() const + { + return type_ == Type::List; + } + bool isDictionary() const + { + return type_ == Type::Dictionary; + } + bool isEmpty() const + { + return type_ == Type::Empty; + } + explicit operator bool() const + { + return type_ != Type::Empty; + } + + std::size_t size() const; + + template<typename T> + std::optional<T> get() const + { + return Accessor<T>{}.get(*this); + } + + template<typename T, typename U> + T get(U &&defaultValue) const + { + return get<T>().value_or(std::forward<U>(defaultValue)); + } + + template<typename T> + void set(T &&value) + { + return Accessor<std::remove_reference_t<T>>{}.set(*this, std::forward<T>(value)); + } + + DictAdapter asDict() const { return DictAdapter{ list_ }; } + ListAdapter asList() const { return ListAdapter{ list_ }; } + + const YamlObject &operator[](std::size_t index) const; + + bool contains(std::string_view key) const; + const YamlObject &operator[](std::string_view key) const; + + YamlObject *add(std::unique_ptr<YamlObject> child); + YamlObject *add(std::string key, std::unique_ptr<YamlObject> child); + +private: + LIBCAMERA_DISABLE_COPY_AND_MOVE(YamlObject) + + template<typename T> + friend struct Accessor; + + enum class Type { + Dictionary, + List, + Value, + Empty, + }; + + template<typename T, typename Enable = void> + struct Accessor { + std::optional<T> get(const YamlObject &obj) const; + void set(YamlObject &obj, T value); + }; + + Type type_; + + std::string value_; + ValueContainer list_; + std::map<std::string, YamlObject *, std::less<>> dictionary_; +}; + +} /* namespace libcamera */ diff --git a/include/libcamera/internal/yaml_parser.h b/include/libcamera/internal/yaml_parser.h index 7b6d16de1a04..e503e83a80da 100644 --- a/include/libcamera/internal/yaml_parser.h +++ b/include/libcamera/internal/yaml_parser.h @@ -7,221 +7,13 @@ #pragma once -#include <iterator> -#include <map> -#include <optional> -#include <stdint.h> -#include <string> -#include <string_view> -#include <vector> +#include <memory> -#include <libcamera/base/class.h> +#include "libcamera/internal/yaml_object.h" namespace libcamera { class File; -class YamlParserContext; - -class YamlObject -{ -private: - struct Value { - Value(std::string &&k, std::unique_ptr<YamlObject> &&v) - : key(std::move(k)), value(std::move(v)) - { - } - std::string key; - std::unique_ptr<YamlObject> value; - }; - - using ValueContainer = std::vector<Value>; - -public: -#ifndef __DOXYGEN__ - template<typename Derived> - class Iterator - { - public: - using difference_type = std::ptrdiff_t; - using iterator_category = std::forward_iterator_tag; - - Iterator(typename ValueContainer::const_iterator it) - : it_(it) - { - } - - Derived &operator++() - { - ++it_; - return *static_cast<Derived *>(this); - } - - Derived operator++(int) - { - Derived it = *static_cast<Derived *>(this); - it_++; - return it; - } - - friend bool operator==(const Iterator &a, const Iterator &b) - { - return a.it_ == b.it_; - } - - friend bool operator!=(const Iterator &a, const Iterator &b) - { - return a.it_ != b.it_; - } - - protected: - ValueContainer::const_iterator it_; - }; - - template<typename Iterator> - class Adapter - { - public: - Adapter(const ValueContainer &container) - : container_(container) - { - } - - Iterator begin() const - { - return Iterator{ container_.begin() }; - } - - Iterator end() const - { - return Iterator{ container_.end() }; - } - - protected: - const ValueContainer &container_; - }; - - class ListIterator : public Iterator<ListIterator> - { - public: - using value_type = const YamlObject &; - using pointer = const YamlObject *; - using reference = value_type; - - value_type operator*() const - { - return *it_->value.get(); - } - - pointer operator->() const - { - return it_->value.get(); - } - }; - - class DictIterator : public Iterator<DictIterator> - { - public: - using value_type = std::pair<const std::string &, const YamlObject &>; - using pointer = value_type *; - using reference = value_type &; - - value_type operator*() const - { - return { it_->key, *it_->value.get() }; - } - }; - - class DictAdapter : public Adapter<DictIterator> - { - public: - using key_type = std::string; - }; - - class ListAdapter : public Adapter<ListIterator> - { - }; -#endif /* __DOXYGEN__ */ - - YamlObject(); - ~YamlObject(); - - bool isValue() const - { - return type_ == Type::Value; - } - bool isList() const - { - return type_ == Type::List; - } - bool isDictionary() const - { - return type_ == Type::Dictionary; - } - bool isEmpty() const - { - return type_ == Type::Empty; - } - explicit operator bool() const - { - return type_ != Type::Empty; - } - - std::size_t size() const; - - template<typename T> - std::optional<T> get() const - { - return Accessor<T>{}.get(*this); - } - - template<typename T, typename U> - T get(U &&defaultValue) const - { - return get<T>().value_or(std::forward<U>(defaultValue)); - } - - template<typename T> - void set(T &&value) - { - return Accessor<std::remove_reference_t<T>>{}.set(*this, std::forward<T>(value)); - } - - DictAdapter asDict() const { return DictAdapter{ list_ }; } - ListAdapter asList() const { return ListAdapter{ list_ }; } - - const YamlObject &operator[](std::size_t index) const; - - bool contains(std::string_view key) const; - const YamlObject &operator[](std::string_view key) const; - - YamlObject *add(std::unique_ptr<YamlObject> child); - YamlObject *add(std::string key, std::unique_ptr<YamlObject> child); - -private: - LIBCAMERA_DISABLE_COPY_AND_MOVE(YamlObject) - - template<typename T> - friend struct Accessor; - - enum class Type { - Dictionary, - List, - Value, - Empty, - }; - - template<typename T, typename Enable = void> - struct Accessor { - std::optional<T> get(const YamlObject &obj) const; - void set(YamlObject &obj, T value); - }; - - Type type_; - - std::string value_; - ValueContainer list_; - std::map<std::string, YamlObject *, std::less<>> dictionary_; -}; class YamlParser final { diff --git a/src/ipa/libipa/agc_mean_luminance.h b/src/ipa/libipa/agc_mean_luminance.h index 0df97b27332d..dfe1ccbe948b 100644 --- a/src/ipa/libipa/agc_mean_luminance.h +++ b/src/ipa/libipa/agc_mean_luminance.h @@ -16,7 +16,7 @@ #include <libcamera/controls.h> -#include "libcamera/internal/yaml_parser.h" +#include "libcamera/internal/yaml_object.h" #include "exposure_mode_helper.h" #include "histogram.h" diff --git a/src/ipa/libipa/awb.h b/src/ipa/libipa/awb.h index f4a86038635f..3f25d13feaa8 100644 --- a/src/ipa/libipa/awb.h +++ b/src/ipa/libipa/awb.h @@ -14,7 +14,7 @@ #include <libcamera/controls.h> #include "libcamera/internal/vector.h" -#include "libcamera/internal/yaml_parser.h" +#include "libcamera/internal/yaml_object.h" namespace libcamera { diff --git a/src/ipa/libipa/awb_bayes.h b/src/ipa/libipa/awb_bayes.h index 47ef3cce4d58..79334ad3e7a3 100644 --- a/src/ipa/libipa/awb_bayes.h +++ b/src/ipa/libipa/awb_bayes.h @@ -10,7 +10,7 @@ #include <libcamera/controls.h> #include "libcamera/internal/vector.h" -#include "libcamera/internal/yaml_parser.h" +#include "libcamera/internal/yaml_object.h" #include "awb.h" #include "interpolator.h" diff --git a/src/ipa/libipa/interpolator.cpp b/src/ipa/libipa/interpolator.cpp index f901a86e4c74..9355802f796a 100644 --- a/src/ipa/libipa/interpolator.cpp +++ b/src/ipa/libipa/interpolator.cpp @@ -11,8 +11,6 @@ #include <libcamera/base/log.h> -#include "libcamera/internal/yaml_parser.h" - #include "interpolator.h" /** diff --git a/src/ipa/libipa/interpolator.h b/src/ipa/libipa/interpolator.h index 7880db6976d1..08003a06dbba 100644 --- a/src/ipa/libipa/interpolator.h +++ b/src/ipa/libipa/interpolator.h @@ -15,7 +15,7 @@ #include <libcamera/base/log.h> -#include "libcamera/internal/yaml_parser.h" +#include "libcamera/internal/yaml_object.h" namespace libcamera { diff --git a/src/ipa/libipa/lsc_polynomial.h b/src/ipa/libipa/lsc_polynomial.h index c71f215de3fc..19da46860849 100644 --- a/src/ipa/libipa/lsc_polynomial.h +++ b/src/ipa/libipa/lsc_polynomial.h @@ -16,7 +16,7 @@ #include <libcamera/geometry.h> -#include "libcamera/internal/yaml_parser.h" +#include "libcamera/internal/yaml_object.h" namespace libcamera { diff --git a/src/ipa/libipa/lux.cpp b/src/ipa/libipa/lux.cpp index 899e88248f04..d79b116a3339 100644 --- a/src/ipa/libipa/lux.cpp +++ b/src/ipa/libipa/lux.cpp @@ -12,7 +12,7 @@ #include <libcamera/base/log.h> -#include "libcamera/internal/yaml_parser.h" +#include "libcamera/internal/yaml_object.h" #include "histogram.h" diff --git a/src/ipa/libipa/module.h b/src/ipa/libipa/module.h index c27af7718feb..8e6c658a6b63 100644 --- a/src/ipa/libipa/module.h +++ b/src/ipa/libipa/module.h @@ -15,7 +15,7 @@ #include <libcamera/base/log.h> #include <libcamera/base/utils.h> -#include "libcamera/internal/yaml_parser.h" +#include "libcamera/internal/yaml_object.h" #include "algorithm.h" diff --git a/src/ipa/mali-c55/algorithms/blc.cpp b/src/ipa/mali-c55/algorithms/blc.cpp index d099219c3e43..3bdf19141e1d 100644 --- a/src/ipa/mali-c55/algorithms/blc.cpp +++ b/src/ipa/mali-c55/algorithms/blc.cpp @@ -10,7 +10,7 @@ #include <libcamera/base/log.h> #include <libcamera/control_ids.h> -#include "libcamera/internal/yaml_parser.h" +#include "libcamera/internal/yaml_object.h" /** * \file blc.h diff --git a/src/ipa/mali-c55/algorithms/lsc.cpp b/src/ipa/mali-c55/algorithms/lsc.cpp index f75b9cd7b7b8..e32f5a83485e 100644 --- a/src/ipa/mali-c55/algorithms/lsc.cpp +++ b/src/ipa/mali-c55/algorithms/lsc.cpp @@ -7,7 +7,7 @@ #include "lsc.h" -#include "libcamera/internal/yaml_parser.h" +#include "libcamera/internal/yaml_object.h" namespace libcamera { diff --git a/src/ipa/rkisp1/algorithms/agc.cpp b/src/ipa/rkisp1/algorithms/agc.cpp index 7cc06f91ac2b..ef16a3775056 100644 --- a/src/ipa/rkisp1/algorithms/agc.cpp +++ b/src/ipa/rkisp1/algorithms/agc.cpp @@ -19,7 +19,7 @@ #include <libcamera/control_ids.h> #include <libcamera/ipa/core_ipa_interface.h> -#include "libcamera/internal/yaml_parser.h" +#include "libcamera/internal/yaml_object.h" #include "libipa/histogram.h" diff --git a/src/ipa/rkisp1/algorithms/blc.cpp b/src/ipa/rkisp1/algorithms/blc.cpp index 32fc44ffff92..19c262fffa73 100644 --- a/src/ipa/rkisp1/algorithms/blc.cpp +++ b/src/ipa/rkisp1/algorithms/blc.cpp @@ -13,7 +13,7 @@ #include <libcamera/control_ids.h> -#include "libcamera/internal/yaml_parser.h" +#include "libcamera/internal/yaml_object.h" /** * \file blc.h diff --git a/src/ipa/rkisp1/algorithms/ccm.cpp b/src/ipa/rkisp1/algorithms/ccm.cpp index de2b6fe775aa..3ed307280677 100644 --- a/src/ipa/rkisp1/algorithms/ccm.cpp +++ b/src/ipa/rkisp1/algorithms/ccm.cpp @@ -16,7 +16,7 @@ #include <libcamera/ipa/core_ipa_interface.h> -#include "libcamera/internal/yaml_parser.h" +#include "libcamera/internal/yaml_object.h" #include "libipa/fixedpoint.h" #include "libipa/interpolator.h" diff --git a/src/ipa/rkisp1/algorithms/dpcc.cpp b/src/ipa/rkisp1/algorithms/dpcc.cpp index 7894628144f3..c195334750e1 100644 --- a/src/ipa/rkisp1/algorithms/dpcc.cpp +++ b/src/ipa/rkisp1/algorithms/dpcc.cpp @@ -9,7 +9,7 @@ #include <libcamera/base/log.h> -#include "libcamera/internal/yaml_parser.h" +#include "libcamera/internal/yaml_object.h" #include "linux/rkisp1-config.h" diff --git a/src/ipa/rkisp1/algorithms/goc.cpp b/src/ipa/rkisp1/algorithms/goc.cpp index a0e7030fe5db..6c07bd8c71e5 100644 --- a/src/ipa/rkisp1/algorithms/goc.cpp +++ b/src/ipa/rkisp1/algorithms/goc.cpp @@ -13,7 +13,7 @@ #include <libcamera/control_ids.h> -#include "libcamera/internal/yaml_parser.h" +#include "libcamera/internal/yaml_object.h" #include "linux/rkisp1-config.h" diff --git a/src/ipa/rkisp1/algorithms/gsl.cpp b/src/ipa/rkisp1/algorithms/gsl.cpp index 7ac5dc215850..292d0e80dc57 100644 --- a/src/ipa/rkisp1/algorithms/gsl.cpp +++ b/src/ipa/rkisp1/algorithms/gsl.cpp @@ -10,7 +10,7 @@ #include <libcamera/base/log.h> #include <libcamera/base/utils.h> -#include "libcamera/internal/yaml_parser.h" +#include "libcamera/internal/yaml_object.h" #include "linux/rkisp1-config.h" diff --git a/src/ipa/rkisp1/algorithms/lsc.cpp b/src/ipa/rkisp1/algorithms/lsc.cpp index 429565a0b51f..9c0ed44b3943 100644 --- a/src/ipa/rkisp1/algorithms/lsc.cpp +++ b/src/ipa/rkisp1/algorithms/lsc.cpp @@ -14,7 +14,7 @@ #include <libcamera/base/log.h> #include <libcamera/base/utils.h> -#include "libcamera/internal/yaml_parser.h" +#include "libcamera/internal/yaml_object.h" #include "libipa/lsc_polynomial.h" #include "linux/rkisp1-config.h" diff --git a/src/ipa/rkisp1/algorithms/wdr.cpp b/src/ipa/rkisp1/algorithms/wdr.cpp index ed81628c032c..9e2688a05179 100644 --- a/src/ipa/rkisp1/algorithms/wdr.cpp +++ b/src/ipa/rkisp1/algorithms/wdr.cpp @@ -10,7 +10,7 @@ #include <libcamera/base/log.h> #include <libcamera/base/utils.h> -#include "libcamera/internal/yaml_parser.h" +#include "libcamera/internal/yaml_object.h" #include <libipa/agc_mean_luminance.h> #include <libipa/histogram.h> diff --git a/src/ipa/rpi/controller/algorithm.h b/src/ipa/rpi/controller/algorithm.h index 1971bfdcc8ad..8839daa90916 100644 --- a/src/ipa/rpi/controller/algorithm.h +++ b/src/ipa/rpi/controller/algorithm.h @@ -15,7 +15,7 @@ #include <memory> #include <map> -#include "libcamera/internal/yaml_parser.h" +#include "libcamera/internal/yaml_object.h" #include "controller.h" diff --git a/src/ipa/rpi/controller/controller.h b/src/ipa/rpi/controller/controller.h index fdb46557de9c..573942886bc0 100644 --- a/src/ipa/rpi/controller/controller.h +++ b/src/ipa/rpi/controller/controller.h @@ -16,7 +16,7 @@ #include <string> #include <libcamera/base/utils.h> -#include "libcamera/internal/yaml_parser.h" +#include "libcamera/internal/yaml_object.h" #include "camera_mode.h" #include "device_status.h" diff --git a/src/libcamera/geometry.cpp b/src/libcamera/geometry.cpp index 2e8e9e33ea78..621008844c74 100644 --- a/src/libcamera/geometry.cpp +++ b/src/libcamera/geometry.cpp @@ -12,7 +12,7 @@ #include <libcamera/base/log.h> -#include "libcamera/internal/yaml_parser.h" +#include "libcamera/internal/yaml_object.h" /** * \file geometry.h diff --git a/src/libcamera/meson.build b/src/libcamera/meson.build index 6f952bd9832a..da89aa3714c3 100644 --- a/src/libcamera/meson.build +++ b/src/libcamera/meson.build @@ -58,6 +58,7 @@ libcamera_internal_sources = files([ 'v4l2_subdevice.cpp', 'v4l2_videodevice.cpp', 'vector.cpp', + 'yaml_object.cpp', 'yaml_parser.cpp', ]) diff --git a/src/libcamera/pipeline/rpi/common/pipeline_base.cpp b/src/libcamera/pipeline/rpi/common/pipeline_base.cpp index 7eb197ce435c..684438bd5fb7 100644 --- a/src/libcamera/pipeline/rpi/common/pipeline_base.cpp +++ b/src/libcamera/pipeline/rpi/common/pipeline_base.cpp @@ -21,6 +21,7 @@ #include "libcamera/internal/camera_lens.h" #include "libcamera/internal/v4l2_subdevice.h" +#include "libcamera/internal/yaml_parser.h" using namespace std::chrono_literals; diff --git a/src/libcamera/pipeline/rpi/common/pipeline_base.h b/src/libcamera/pipeline/rpi/common/pipeline_base.h index 6257a93467df..c69a690f580c 100644 --- a/src/libcamera/pipeline/rpi/common/pipeline_base.h +++ b/src/libcamera/pipeline/rpi/common/pipeline_base.h @@ -26,7 +26,7 @@ #include "libcamera/internal/pipeline_handler.h" #include "libcamera/internal/request.h" #include "libcamera/internal/v4l2_videodevice.h" -#include "libcamera/internal/yaml_parser.h" +#include "libcamera/internal/yaml_object.h" #include <libcamera/ipa/raspberrypi_ipa_interface.h> #include <libcamera/ipa/raspberrypi_ipa_proxy.h> diff --git a/src/libcamera/pipeline/virtual/config_parser.h b/src/libcamera/pipeline/virtual/config_parser.h index d2000de9c12f..f696d8862897 100644 --- a/src/libcamera/pipeline/virtual/config_parser.h +++ b/src/libcamera/pipeline/virtual/config_parser.h @@ -13,7 +13,7 @@ #include <libcamera/base/file.h> #include "libcamera/internal/pipeline_handler.h" -#include "libcamera/internal/yaml_parser.h" +#include "libcamera/internal/yaml_object.h" #include "virtual.h" diff --git a/src/libcamera/pipeline/virtual/virtual.cpp b/src/libcamera/pipeline/virtual/virtual.cpp index 40c35264c568..b032db54ded4 100644 --- a/src/libcamera/pipeline/virtual/virtual.cpp +++ b/src/libcamera/pipeline/virtual/virtual.cpp @@ -36,7 +36,7 @@ #include "libcamera/internal/framebuffer.h" #include "libcamera/internal/pipeline_handler.h" #include "libcamera/internal/request.h" -#include "libcamera/internal/yaml_parser.h" +#include "libcamera/internal/yaml_object.h" #include "pipeline/virtual/config_parser.h" diff --git a/src/libcamera/yaml_object.cpp b/src/libcamera/yaml_object.cpp new file mode 100644 index 000000000000..5e92189fdb8e --- /dev/null +++ b/src/libcamera/yaml_object.cpp @@ -0,0 +1,477 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2022, Google Inc. + * Copyright (C) 2025, Ideas on Board. + * + * libcamera YAML object + */ + +#include "libcamera/internal/yaml_object.h" + +#include <charconv> +#include <errno.h> +#include <string> +#include <vector> + +#include <libcamera/base/utils.h> + +/** + * \file yaml_object.h + * \brief YAML objects + */ + +namespace libcamera { + +namespace { + +/* Empty static YamlObject as a safe result for invalid operations */ +static const YamlObject empty; + +} /* namespace */ + +/** + * \class YamlObject + * \brief A class representing the tree structure of the YAML content + * + * The YamlObject class represents the tree structure of YAML content. A + * YamlObject can be empty, a dictionary or list of YamlObjects, or a value if a + * tree leaf. + */ + +YamlObject::YamlObject() + : type_(Type::Empty) +{ +} + +YamlObject::~YamlObject() = default; + +/** + * \fn YamlObject::isValue() + * \brief Return whether the YamlObject is a value + * + * \return True if the YamlObject is a value, false otherwise + */ + +/** + * \fn YamlObject::isList() + * \brief Return whether the YamlObject is a list + * + * \return True if the YamlObject is a list, false otherwise + */ + +/** + * \fn YamlObject::isDictionary() + * \brief Return whether the YamlObject is a dictionary + * + * \return True if the YamlObject is a dictionary, false otherwise + */ + +/** + * \fn YamlObject::isEmpty() + * \brief Return whether the YamlObject is an empty + * + * \return True if the YamlObject is empty, false otherwise + */ + +/** + * \fn YamlObject::operator bool() + * \brief Return whether the YamlObject is a non-empty + * + * \return False if the YamlObject is empty, true otherwise + */ + +/** + * \fn YamlObject::size() + * \brief Retrieve the number of elements in a dictionary or list YamlObject + * + * This function retrieves the size of the YamlObject, defined as the number of + * child elements it contains. Only YamlObject instances of Dictionary or List + * types have a size, calling this function on other types of instances is + * invalid and results in undefined behaviour. + * + * \return The size of the YamlObject + */ +std::size_t YamlObject::size() const +{ + switch (type_) { + case Type::Dictionary: + case Type::List: + return list_.size(); + default: + return 0; + } +} + +/** + * \fn template<typename T> YamlObject::get<T>() 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 + */ + +/** + * \fn template<typename T, typename U> YamlObject::get<T>(U &&defaultValue) const + * \brief Parse the YamlObject as a \a T value + * \param[in] defaultValue The default value when failing to parse + * + * 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. + * + * 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 + */ + +/** + * \fn template<typename T> YamlObject::set<T>(T &&value) + * \brief Set the value of a YamlObject + * \param[in] value The value + * + * This function sets the value stored in a YamlObject to \a value. The value is + * converted to a string in an implementation-specific way that guarantees that + * subsequent calls to get<T>() will return the same value. + * + * Values can only be set on YamlObject of Type::Value type or empty YamlObject. + * Attempting to set a value on an object of type Type::Dict or Type::List does + * not modify the YamlObject. + */ + +#ifndef __DOXYGEN__ + +template<> +std::optional<bool> +YamlObject::Accessor<bool>::get(const YamlObject &obj) const +{ + if (obj.type_ != Type::Value) + return std::nullopt; + + if (obj.value_ == "true") + return true; + else if (obj.value_ == "false") + return false; + + return std::nullopt; +} + +template<> +void YamlObject::Accessor<bool>::set(YamlObject &obj, bool value) +{ + if (obj.type_ != Type::Empty && obj.type_ != Type::Value) + return; + + obj.type_ = Type::Value; + obj.value_ = value ? "true" : "false"; +} + +template<typename T> +struct YamlObject::Accessor<T, std::enable_if_t< + std::is_same_v<int8_t, T> || + std::is_same_v<uint8_t, T> || + std::is_same_v<int16_t, T> || + std::is_same_v<uint16_t, T> || + std::is_same_v<int32_t, T> || + std::is_same_v<uint32_t, T>>> +{ + std::optional<T> get(const YamlObject &obj) const + { + if (obj.type_ != Type::Value) + return std::nullopt; + + const std::string &str = obj.value_; + T value; + + auto [ptr, ec] = std::from_chars(str.data(), str.data() + str.size(), + value); + if (ptr != str.data() + str.size() || ec != std::errc()) + return std::nullopt; + + return value; + } + + void set(YamlObject &obj, T value) + { + if (obj.type_ != Type::Empty && obj.type_ != Type::Value) + return; + + obj.type_ = Type::Value; + obj.value_ = std::to_string(value); + } +}; + +template struct YamlObject::Accessor<int8_t>; +template struct YamlObject::Accessor<uint8_t>; +template struct YamlObject::Accessor<int16_t>; +template struct YamlObject::Accessor<uint16_t>; +template struct YamlObject::Accessor<int32_t>; +template struct YamlObject::Accessor<uint32_t>; + +template<> +std::optional<float> +YamlObject::Accessor<float>::get(const YamlObject &obj) const +{ + return obj.get<double>(); +} + +template<> +void YamlObject::Accessor<float>::set(YamlObject &obj, float value) +{ + obj.set<double>(std::forward<float>(value)); +} + +template<> +std::optional<double> +YamlObject::Accessor<double>::get(const YamlObject &obj) const +{ + if (obj.type_ != Type::Value) + return std::nullopt; + + if (obj.value_.empty()) + return std::nullopt; + + char *end; + + errno = 0; + double value = utils::strtod(obj.value_.c_str(), &end); + + if ('\0' != *end || errno == ERANGE) + return std::nullopt; + + return value; +} + +template<> +void YamlObject::Accessor<double>::set(YamlObject &obj, double value) +{ + if (obj.type_ != Type::Empty && obj.type_ != Type::Value) + return; + + obj.type_ = Type::Value; + obj.value_ = std::to_string(value); +} + +template<> +std::optional<std::string> +YamlObject::Accessor<std::string>::get(const YamlObject &obj) const +{ + if (obj.type_ != Type::Value) + return std::nullopt; + + return obj.value_; +} + +template<> +void YamlObject::Accessor<std::string>::set(YamlObject &obj, std::string value) +{ + if (obj.type_ != Type::Empty && obj.type_ != Type::Value) + return; + + obj.type_ = Type::Value; + obj.value_ = std::move(value); +} + +template<typename T> +struct YamlObject::Accessor<std::vector<T>, std::enable_if_t< + std::is_same_v<bool, T> || + std::is_same_v<float, T> || + std::is_same_v<double, T> || + std::is_same_v<int8_t, T> || + std::is_same_v<uint8_t, T> || + std::is_same_v<int16_t, T> || + std::is_same_v<uint16_t, T> || + std::is_same_v<int32_t, T> || + std::is_same_v<uint32_t, T> || + std::is_same_v<std::string, T>>> +{ + std::optional<std::vector<T>> get(const YamlObject &obj) const + { + if (obj.type_ != Type::List) + return std::nullopt; + + std::vector<T> values; + values.reserve(obj.list_.size()); + + for (const YamlObject &entry : obj.asList()) { + const auto value = entry.get<T>(); + if (!value) + return std::nullopt; + values.emplace_back(*value); + } + + return values; + } +}; + +template struct YamlObject::Accessor<std::vector<bool>>; +template struct YamlObject::Accessor<std::vector<float>>; +template struct YamlObject::Accessor<std::vector<double>>; +template struct YamlObject::Accessor<std::vector<int8_t>>; +template struct YamlObject::Accessor<std::vector<uint8_t>>; +template struct YamlObject::Accessor<std::vector<int16_t>>; +template struct YamlObject::Accessor<std::vector<uint16_t>>; +template struct YamlObject::Accessor<std::vector<int32_t>>; +template struct YamlObject::Accessor<std::vector<uint32_t>>; +template struct YamlObject::Accessor<std::vector<std::string>>; +#endif /* __DOXYGEN__ */ + +/** + * \fn YamlObject::asDict() const + * \brief Wrap a dictionary YamlObject in an adapter that exposes iterators + * + * The YamlObject class doesn't directly implement iterators, as the iterator + * type depends on whether the object is a Dictionary or List. This function + * wraps a YamlObject of Dictionary type into an adapter that exposes + * iterators, as well as begin() and end() functions, allowing usage of + * range-based for loops with YamlObject. As YAML mappings are not ordered, the + * iteration order is not specified. + * + * The iterator's value_type is a + * <em>std::pair<const std::string &, const \ref YamlObject &></em>. + * + * If the YamlObject is not of Dictionary type, the returned adapter operates + * as an empty container. + * + * \return An adapter of unspecified type compatible with range-based for loops + */ + +/** + * \fn YamlObject::asList() const + * \brief Wrap a list YamlObject in an adapter that exposes iterators + * + * The YamlObject class doesn't directly implement iterators, as the iterator + * type depends on whether the object is a Dictionary or List. This function + * wraps a YamlObject of List type into an adapter that exposes iterators, as + * well as begin() and end() functions, allowing usage of range-based for loops + * with YamlObject. As YAML lists are ordered, the iteration order is identical + * to the list order in the YAML data. + * + * The iterator's value_type is a <em>const YamlObject &</em>. + * + * If the YamlObject is not of List type, the returned adapter operates as an + * empty container. + * + * \return An adapter of unspecified type compatible with range-based for loops + */ + +/** + * \fn YamlObject::operator[](std::size_t index) const + * \brief Retrieve the element from list YamlObject by index + * + * This function retrieves an element of the YamlObject. Only YamlObject + * instances of List type associate elements with index, calling this function + * on other types of instances or with an invalid index results in an empty + * object. + * + * \return The YamlObject as an element of the list + */ +const YamlObject &YamlObject::operator[](std::size_t index) const +{ + if (type_ != Type::List || index >= size()) + return empty; + + return *list_[index].value; +} + +/** + * \fn YamlObject::contains() + * \brief Check if an element of a dictionary exists + * + * This function check if the YamlObject contains an element. Only YamlObject + * instances of Dictionary type associate elements with names, calling this + * function on other types of instances is invalid and results in undefined + * behaviour. + * + * \return True if an element exists, false otherwise + */ +bool YamlObject::contains(std::string_view key) const +{ + return dictionary_.find(key) != dictionary_.end(); +} + +/** + * \fn YamlObject::operator[](std::string_view key) const + * \brief Retrieve a member by name from the dictionary + * + * This function retrieve a member of a YamlObject by name. Only YamlObject + * instances of Dictionary type associate elements with names, calling this + * function on other types of instances or with a nonexistent key results in an + * empty object. + * + * \return The YamlObject corresponding to the \a key member + */ +const YamlObject &YamlObject::operator[](std::string_view key) const +{ + if (type_ != Type::Dictionary) + return empty; + + auto iter = dictionary_.find(key); + if (iter == dictionary_.end()) + return empty; + + return *iter->second; +} + +/** + * \brief Add a child object to a list + * \param[in] child The child object + * + * Append the \a child node as the last element of this node's children list. + * This node must be empty, in which case it is converted to the Type::List + * type, or be a list. Otherwise, the \a child is discarded and the function + * returns a nullptr. + * + * \return The child object if successfully added, nullptr otherwise + */ +YamlObject *YamlObject::add(std::unique_ptr<YamlObject> child) +{ + if (type_ == Type::Empty) + type_ = Type::List; + + if (type_ != Type::List) + return nullptr; + + Value &elem = list_.emplace_back(std::string{}, std::move(child)); + return elem.value.get(); +} + +/** + * \brief Add a child object to a dictionary + * \param[in] key The dictionary key + * \param[in] child The child object + * + * Add the \a child node with the given \a key to this node's children. This + * node must be empty, in which case it is converted to the Type::Dictionary + * type, or be a dictionary. Otherwise, the \a child is discarded and the + * function returns a nullptr. + * + * Keys are unique. If a child with the same \a key already exist, the \a child + * is discarded and the function returns a nullptr. + * + * \return The child object if successfully added, nullptr otherwise + */ +YamlObject *YamlObject::add(std::string key, std::unique_ptr<YamlObject> child) +{ + if (type_ == Type::Empty) + type_ = Type::Dictionary; + + if (type_ != Type::Dictionary) + return nullptr; + + if (dictionary_.find(key) != dictionary_.end()) + return nullptr; + + Value &elem = list_.emplace_back(std::move(key), std::move(child)); + dictionary_.emplace(elem.key, elem.value.get()); + return elem.value.get(); +} + +} /* namespace libcamera */ diff --git a/src/libcamera/yaml_parser.cpp b/src/libcamera/yaml_parser.cpp index 0ef1f3ea303b..d83df0fb9597 100644 --- a/src/libcamera/yaml_parser.cpp +++ b/src/libcamera/yaml_parser.cpp @@ -7,11 +7,10 @@ #include "libcamera/internal/yaml_parser.h" -#include <charconv> #include <errno.h> #include <functional> -#include <limits> -#include <stdlib.h> +#include <memory> +#include <string> #include <libcamera/base/file.h> #include <libcamera/base/log.h> @@ -27,459 +26,6 @@ namespace libcamera { LOG_DEFINE_CATEGORY(YamlParser) -namespace { - -/* Empty static YamlObject as a safe result for invalid operations */ -static const YamlObject empty; - -} /* namespace */ - -/** - * \class YamlObject - * \brief A class representing the tree structure of the YAML content - * - * The YamlObject class represents the tree structure of YAML content. A - * YamlObject can be empty, a dictionary or list of YamlObjects, or a value if a - * tree leaf. - */ - -YamlObject::YamlObject() - : type_(Type::Empty) -{ -} - -YamlObject::~YamlObject() = default; - -/** - * \fn YamlObject::isValue() - * \brief Return whether the YamlObject is a value - * - * \return True if the YamlObject is a value, false otherwise - */ - -/** - * \fn YamlObject::isList() - * \brief Return whether the YamlObject is a list - * - * \return True if the YamlObject is a list, false otherwise - */ - -/** - * \fn YamlObject::isDictionary() - * \brief Return whether the YamlObject is a dictionary - * - * \return True if the YamlObject is a dictionary, false otherwise - */ - -/** - * \fn YamlObject::isEmpty() - * \brief Return whether the YamlObject is an empty - * - * \return True if the YamlObject is empty, false otherwise - */ - -/** - * \fn YamlObject::operator bool() - * \brief Return whether the YamlObject is a non-empty - * - * \return False if the YamlObject is empty, true otherwise - */ - -/** - * \brief Retrieve the number of elements in a dictionary or list YamlObject - * - * This function retrieves the size of the YamlObject, defined as the number of - * child elements it contains. Only YamlObject instances of Dictionary or List - * types have a size, calling this function on other types of instances is - * invalid and results in undefined behaviour. - * - * \return The size of the YamlObject - */ -std::size_t YamlObject::size() const -{ - switch (type_) { - case Type::Dictionary: - case Type::List: - return list_.size(); - default: - return 0; - } -} - -/** - * \fn template<typename T> YamlObject::get<T>() 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 - */ - -/** - * \fn template<typename T, typename U> YamlObject::get<T>(U &&defaultValue) const - * \brief Parse the YamlObject as a \a T value - * \param[in] defaultValue The default value when failing to parse - * - * 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. - * - * 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 - */ - -/** - * \fn template<typename T> YamlObject::set<T>(T &&value) - * \brief Set the value of a YamlObject - * \param[in] value The value - * - * This function sets the value stored in a YamlObject to \a value. The value is - * converted to a string in an implementation-specific way that guarantees that - * subsequent calls to get<T>() will return the same value. - * - * Values can only be set on YamlObject of Type::Value type or empty YamlObject. - * Attempting to set a value on an object of type Type::Dict or Type::List does - * not modify the YamlObject. - */ - -#ifndef __DOXYGEN__ - -template<> -std::optional<bool> -YamlObject::Accessor<bool>::get(const YamlObject &obj) const -{ - if (obj.type_ != Type::Value) - return std::nullopt; - - if (obj.value_ == "true") - return true; - else if (obj.value_ == "false") - return false; - - return std::nullopt; -} - -template<> -void YamlObject::Accessor<bool>::set(YamlObject &obj, bool value) -{ - if (obj.type_ != Type::Empty && obj.type_ != Type::Value) - return; - - obj.type_ = Type::Value; - obj.value_ = value ? "true" : "false"; -} - -template<typename T> -struct YamlObject::Accessor<T, std::enable_if_t< - std::is_same_v<int8_t, T> || - std::is_same_v<uint8_t, T> || - std::is_same_v<int16_t, T> || - std::is_same_v<uint16_t, T> || - std::is_same_v<int32_t, T> || - std::is_same_v<uint32_t, T>>> -{ - std::optional<T> get(const YamlObject &obj) const - { - if (obj.type_ != Type::Value) - return std::nullopt; - - const std::string &str = obj.value_; - T value; - - auto [ptr, ec] = std::from_chars(str.data(), str.data() + str.size(), - value); - if (ptr != str.data() + str.size() || ec != std::errc()) - return std::nullopt; - - return value; - } - - void set(YamlObject &obj, T value) - { - if (obj.type_ != Type::Empty && obj.type_ != Type::Value) - return; - - obj.type_ = Type::Value; - obj.value_ = std::to_string(value); - } -}; - -template struct YamlObject::Accessor<int8_t>; -template struct YamlObject::Accessor<uint8_t>; -template struct YamlObject::Accessor<int16_t>; -template struct YamlObject::Accessor<uint16_t>; -template struct YamlObject::Accessor<int32_t>; -template struct YamlObject::Accessor<uint32_t>; - -template<> -std::optional<float> -YamlObject::Accessor<float>::get(const YamlObject &obj) const -{ - return obj.get<double>(); -} - -template<> -void YamlObject::Accessor<float>::set(YamlObject &obj, float value) -{ - obj.set<double>(std::forward<float>(value)); -} - -template<> -std::optional<double> -YamlObject::Accessor<double>::get(const YamlObject &obj) const -{ - if (obj.type_ != Type::Value) - return std::nullopt; - - if (obj.value_.empty()) - return std::nullopt; - - char *end; - - errno = 0; - double value = utils::strtod(obj.value_.c_str(), &end); - - if ('\0' != *end || errno == ERANGE) - return std::nullopt; - - return value; -} - -template<> -void YamlObject::Accessor<double>::set(YamlObject &obj, double value) -{ - if (obj.type_ != Type::Empty && obj.type_ != Type::Value) - return; - - obj.type_ = Type::Value; - obj.value_ = std::to_string(value); -} - -template<> -std::optional<std::string> -YamlObject::Accessor<std::string>::get(const YamlObject &obj) const -{ - if (obj.type_ != Type::Value) - return std::nullopt; - - return obj.value_; -} - -template<> -void YamlObject::Accessor<std::string>::set(YamlObject &obj, std::string value) -{ - if (obj.type_ != Type::Empty && obj.type_ != Type::Value) - return; - - obj.type_ = Type::Value; - obj.value_ = std::move(value); -} - -template<typename T> -struct YamlObject::Accessor<std::vector<T>, std::enable_if_t< - std::is_same_v<bool, T> || - std::is_same_v<float, T> || - std::is_same_v<double, T> || - std::is_same_v<int8_t, T> || - std::is_same_v<uint8_t, T> || - std::is_same_v<int16_t, T> || - std::is_same_v<uint16_t, T> || - std::is_same_v<int32_t, T> || - std::is_same_v<uint32_t, T> || - std::is_same_v<std::string, T>>> -{ - std::optional<std::vector<T>> get(const YamlObject &obj) const - { - if (obj.type_ != Type::List) - return std::nullopt; - - std::vector<T> values; - values.reserve(obj.list_.size()); - - for (const YamlObject &entry : obj.asList()) { - const auto value = entry.get<T>(); - if (!value) - return std::nullopt; - values.emplace_back(*value); - } - - return values; - } -}; - -template struct YamlObject::Accessor<std::vector<bool>>; -template struct YamlObject::Accessor<std::vector<float>>; -template struct YamlObject::Accessor<std::vector<double>>; -template struct YamlObject::Accessor<std::vector<int8_t>>; -template struct YamlObject::Accessor<std::vector<uint8_t>>; -template struct YamlObject::Accessor<std::vector<int16_t>>; -template struct YamlObject::Accessor<std::vector<uint16_t>>; -template struct YamlObject::Accessor<std::vector<int32_t>>; -template struct YamlObject::Accessor<std::vector<uint32_t>>; -template struct YamlObject::Accessor<std::vector<std::string>>; -#endif /* __DOXYGEN__ */ - -/** - * \fn YamlObject::asDict() const - * \brief Wrap a dictionary YamlObject in an adapter that exposes iterators - * - * The YamlObject class doesn't directly implement iterators, as the iterator - * type depends on whether the object is a Dictionary or List. This function - * wraps a YamlObject of Dictionary type into an adapter that exposes - * iterators, as well as begin() and end() functions, allowing usage of - * range-based for loops with YamlObject. As YAML mappings are not ordered, the - * iteration order is not specified. - * - * The iterator's value_type is a - * <em>std::pair<const std::string &, const \ref YamlObject &></em>. - * - * If the YamlObject is not of Dictionary type, the returned adapter operates - * as an empty container. - * - * \return An adapter of unspecified type compatible with range-based for loops - */ - -/** - * \fn YamlObject::asList() const - * \brief Wrap a list YamlObject in an adapter that exposes iterators - * - * The YamlObject class doesn't directly implement iterators, as the iterator - * type depends on whether the object is a Dictionary or List. This function - * wraps a YamlObject of List type into an adapter that exposes iterators, as - * well as begin() and end() functions, allowing usage of range-based for loops - * with YamlObject. As YAML lists are ordered, the iteration order is identical - * to the list order in the YAML data. - * - * The iterator's value_type is a <em>const YamlObject &</em>. - * - * If the YamlObject is not of List type, the returned adapter operates as an - * empty container. - * - * \return An adapter of unspecified type compatible with range-based for loops - */ - -/** - * \fn YamlObject::operator[](std::size_t index) const - * \brief Retrieve the element from list YamlObject by index - * - * This function retrieves an element of the YamlObject. Only YamlObject - * instances of List type associate elements with index, calling this function - * on other types of instances or with an invalid index results in an empty - * object. - * - * \return The YamlObject as an element of the list - */ -const YamlObject &YamlObject::operator[](std::size_t index) const -{ - if (type_ != Type::List || index >= size()) - return empty; - - return *list_[index].value; -} - -/** - * \fn YamlObject::contains() - * \brief Check if an element of a dictionary exists - * - * This function check if the YamlObject contains an element. Only YamlObject - * instances of Dictionary type associate elements with names, calling this - * function on other types of instances is invalid and results in undefined - * behaviour. - * - * \return True if an element exists, false otherwise - */ -bool YamlObject::contains(std::string_view key) const -{ - return dictionary_.find(key) != dictionary_.end(); -} - -/** - * \fn YamlObject::operator[](std::string_view key) const - * \brief Retrieve a member by name from the dictionary - * - * This function retrieve a member of a YamlObject by name. Only YamlObject - * instances of Dictionary type associate elements with names, calling this - * function on other types of instances or with a nonexistent key results in an - * empty object. - * - * \return The YamlObject corresponding to the \a key member - */ -const YamlObject &YamlObject::operator[](std::string_view key) const -{ - if (type_ != Type::Dictionary) - return empty; - - auto iter = dictionary_.find(key); - if (iter == dictionary_.end()) - return empty; - - return *iter->second; -} - -/** - * \brief Add a child object to a list - * \param[in] child The child object - * - * Append the \a child node as the last element of this node's children list. - * This node must be empty, in which case it is converted to the Type::List - * type, or be a list. Otherwise, the \a child is discarded and the function - * returns a nullptr. - * - * \return A pointer to the child object if successfully added, nullptr - * otherwise - */ -YamlObject *YamlObject::add(std::unique_ptr<YamlObject> child) -{ - if (type_ == Type::Empty) - type_ = Type::List; - - if (type_ != Type::List) - return nullptr; - - Value &elem = list_.emplace_back(std::string{}, std::move(child)); - return elem.value.get(); -} - -/** - * \brief Add a child object to a dictionary - * \param[in] key The dictionary key - * \param[in] child The child object - * - * Add the \a child node with the given \a key to this node's children. This - * node must be empty, in which case it is converted to the Type::Dictionary - * type, or be a dictionary. Otherwise, the \a child is discarded and the - * function returns a nullptr. - * - * Keys are unique. If a child with the same \a key already exist, the \a child - * is discarded and the function returns a nullptr. - * - * \return A pointer to the child object if successfully added, nullptr - * otherwise - */ -YamlObject *YamlObject::add(std::string key, std::unique_ptr<YamlObject> child) -{ - if (type_ == Type::Empty) - type_ = Type::Dictionary; - - if (type_ != Type::Dictionary) - return nullptr; - - if (dictionary_.find(key) != dictionary_.end()) - return nullptr; - - Value &elem = list_.emplace_back(std::move(key), std::move(child)); - dictionary_.emplace(elem.key, elem.value.get()); - return elem.value.get(); -} - #ifndef __DOXYGEN__ class YamlParserContext
The YamlObject class was designed to represent data parsed from YAML files. It is outgrowing the initial needs. Move it to a separate file to prepare for a rename. Most files that include yaml_parser.h only need access to a YamlObject. Switch them to yaml_object.h. pipeline_base.cpp was including yaml_parser.h indirectly through pipeline_base.h, include it directly now. Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com> --- .../libcamera/internal/global_configuration.h | 2 +- include/libcamera/internal/matrix.h | 2 +- include/libcamera/internal/meson.build | 1 + include/libcamera/internal/vector.h | 2 +- include/libcamera/internal/yaml_object.h | 226 +++++++++ include/libcamera/internal/yaml_parser.h | 212 +------- src/ipa/libipa/agc_mean_luminance.h | 2 +- src/ipa/libipa/awb.h | 2 +- src/ipa/libipa/awb_bayes.h | 2 +- src/ipa/libipa/interpolator.cpp | 2 - src/ipa/libipa/interpolator.h | 2 +- src/ipa/libipa/lsc_polynomial.h | 2 +- src/ipa/libipa/lux.cpp | 2 +- src/ipa/libipa/module.h | 2 +- src/ipa/mali-c55/algorithms/blc.cpp | 2 +- src/ipa/mali-c55/algorithms/lsc.cpp | 2 +- src/ipa/rkisp1/algorithms/agc.cpp | 2 +- src/ipa/rkisp1/algorithms/blc.cpp | 2 +- src/ipa/rkisp1/algorithms/ccm.cpp | 2 +- src/ipa/rkisp1/algorithms/dpcc.cpp | 2 +- src/ipa/rkisp1/algorithms/goc.cpp | 2 +- src/ipa/rkisp1/algorithms/gsl.cpp | 2 +- src/ipa/rkisp1/algorithms/lsc.cpp | 2 +- src/ipa/rkisp1/algorithms/wdr.cpp | 2 +- src/ipa/rpi/controller/algorithm.h | 2 +- src/ipa/rpi/controller/controller.h | 2 +- src/libcamera/geometry.cpp | 2 +- src/libcamera/meson.build | 1 + .../pipeline/rpi/common/pipeline_base.cpp | 1 + .../pipeline/rpi/common/pipeline_base.h | 2 +- .../pipeline/virtual/config_parser.h | 2 +- src/libcamera/pipeline/virtual/virtual.cpp | 2 +- src/libcamera/yaml_object.cpp | 477 ++++++++++++++++++ src/libcamera/yaml_parser.cpp | 458 +---------------- 34 files changed, 736 insertions(+), 694 deletions(-) create mode 100644 include/libcamera/internal/yaml_object.h create mode 100644 src/libcamera/yaml_object.cpp