diff --git a/include/libcamera/internal/value_node.h b/include/libcamera/internal/value_node.h index da68a74c..57841319 100644 --- a/include/libcamera/internal/value_node.h +++ b/include/libcamera/internal/value_node.h @@ -8,6 +8,7 @@ #pragma once +#include #include #include #include @@ -239,6 +240,8 @@ public: ValueNode *add(std::unique_ptr &&child); ValueNode *add(std::string key, std::unique_ptr &&child); + ValueNode *add(std::initializer_list path, + std::unique_ptr &&child); private: LIBCAMERA_DISABLE_COPY_AND_MOVE(ValueNode) diff --git a/src/libcamera/value_node.cpp b/src/libcamera/value_node.cpp index 33c688ed..0f02b3c1 100644 --- a/src/libcamera/value_node.cpp +++ b/src/libcamera/value_node.cpp @@ -13,6 +13,8 @@ #include #include +#include +#include #include /** @@ -22,6 +24,8 @@ namespace libcamera { +LOG_DEFINE_CATEGORY(ValueNode) + namespace { /* Empty static ValueNode as a safe result for invalid operations */ @@ -541,4 +545,58 @@ ValueNode *ValueNode::add(std::string key, std::unique_ptr &&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 path, + std::unique_ptr &&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 obj; + + if (i < path.size() - 1) + obj = std::make_unique(); + + node = node->add(std::string{ name }, + obj ? std::move(obj) : std::move(child)); + if (!node) { + Span 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 */