@@ -8,6 +8,7 @@
#pragma once
+#include <initializer_list>
#include <iterator>
#include <map>
#include <memory>
@@ -239,6 +240,8 @@ public:
ValueNode *add(std::unique_ptr<ValueNode> &&child);
ValueNode *add(std::string key, std::unique_ptr<ValueNode> &&child);
+ ValueNode *add(std::initializer_list<std::string_view> path,
+ std::unique_ptr<ValueNode> &&child);
private:
LIBCAMERA_DISABLE_COPY_AND_MOVE(ValueNode)
@@ -13,6 +13,8 @@
#include <string>
#include <vector>
+#include <libcamera/base/log.h>
+#include <libcamera/base/span.h>
#include <libcamera/base/utils.h>
/**
@@ -22,6 +24,8 @@
namespace libcamera {
+LOG_DEFINE_CATEGORY(ValueNode)
+
namespace {
/* Empty static ValueNode as a safe result for invalid operations */
@@ -539,4 +543,59 @@ ValueNode *ValueNode::add(std::string key, std::unique_ptr<ValueNode> &&child)
return list_.emplace_back(it->first, std::move(child)).value.get();
}
+/**
+ * \brief Add a child node at the given path
+ * \param[in] path The path
+ * \param[in] child The child node
+ *
+ * Add the \a child node at the given \a path starting at this node. Missing
+ * nodes are created along the path. Nodes along the path must be empty (in
+ * which case they are converted to the Type::Dictionary type), be a dictionary,
+ * or be missing. Otherwise, the function returns a nullptr and the \a child is
+ * not modified.
+ *
+ * Path elements are unique in the context of a parent node. If a child with the
+ * same \a key already exist at the end of the path, the function returns a
+ * nullptr and the \a child is not modified.
+ *
+ * \note Any node added along the \a path will remain even if this function
+ * returns a failure.
+ *
+ * \return A pointer to the \a child node if successfully added, nullptr
+ * otherwise
+ */
+ValueNode *ValueNode::add(std::initializer_list<std::string_view> path,
+ std::unique_ptr<ValueNode> &&child)
+{
+ if (!path.size())
+ return nullptr;
+
+ ValueNode *node = this;
+
+ for (const auto [i, name] : utils::enumerate(path)) {
+ auto iter = node->dictionary_.find(name);
+ if (iter == node->dictionary_.end()) {
+ std::unique_ptr<ValueNode> obj;
+
+ if (i < path.size() - 1)
+ obj = std::make_unique<ValueNode>();
+ else
+ obj = std::move(child);
+
+ node = node->add(std::string{ name }, std::move(obj));
+ if (!node) {
+ Span<const std::string_view> pathName{ std::data(path), i + 1 };
+ LOG(ValueNode, Error)
+ << "Failed to populate '"
+ << utils::join(pathName, "/") << "'";
+ return nullptr;
+ }
+ } else {
+ node = iter->second;
+ }
+ }
+
+ return node;
+}
+
} /* namespace libcamera */
The GlobalConfiguration class will need to add nested children to a ValueNode. Add a new overload to the add() function for this purpose. Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com> --- Changes since v1: - Documentation improvements - Replace NULL with nullptr - Don't move child node if add fails --- include/libcamera/internal/value_node.h | 3 ++ src/libcamera/value_node.cpp | 59 +++++++++++++++++++++++++ 2 files changed, 62 insertions(+)