@@ -14,7 +14,7 @@
#include <libcamera/base/utils.h>
-#include "libcamera/internal/yaml_parser.h"
+#include "libcamera/internal/yaml_object.h"
namespace libcamera {
@@ -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 {
@@ -50,6 +50,7 @@ libcamera_internal_headers = files([
'v4l2_subdevice.h',
'v4l2_videodevice.h',
'vector.h',
+ 'yaml_object.h',
'yaml_parser.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 {
new file mode 100644
@@ -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 */
@@ -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
{
@@ -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"
@@ -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 {
@@ -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"
@@ -11,8 +11,6 @@
#include <libcamera/base/log.h>
-#include "libcamera/internal/yaml_parser.h"
-
#include "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 {
@@ -16,7 +16,7 @@
#include <libcamera/geometry.h>
-#include "libcamera/internal/yaml_parser.h"
+#include "libcamera/internal/yaml_object.h"
namespace libcamera {
@@ -12,7 +12,7 @@
#include <libcamera/base/log.h>
-#include "libcamera/internal/yaml_parser.h"
+#include "libcamera/internal/yaml_object.h"
#include "histogram.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"
@@ -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
@@ -7,7 +7,7 @@
#include "lsc.h"
-#include "libcamera/internal/yaml_parser.h"
+#include "libcamera/internal/yaml_object.h"
namespace libcamera {
@@ -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"
@@ -13,7 +13,7 @@
#include <libcamera/control_ids.h>
-#include "libcamera/internal/yaml_parser.h"
+#include "libcamera/internal/yaml_object.h"
/**
* \file blc.h
@@ -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"
@@ -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"
@@ -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"
@@ -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"
@@ -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"
@@ -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>
@@ -15,7 +15,7 @@
#include <memory>
#include <map>
-#include "libcamera/internal/yaml_parser.h"
+#include "libcamera/internal/yaml_object.h"
#include "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"
@@ -12,7 +12,7 @@
#include <libcamera/base/log.h>
-#include "libcamera/internal/yaml_parser.h"
+#include "libcamera/internal/yaml_object.h"
/**
* \file geometry.h
@@ -58,6 +58,7 @@ libcamera_internal_sources = files([
'v4l2_subdevice.cpp',
'v4l2_videodevice.cpp',
'vector.cpp',
+ 'yaml_object.cpp',
'yaml_parser.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;
@@ -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>
@@ -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"
@@ -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"
new file mode 100644
@@ -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 */
@@ -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