diff --git a/include/libcamera/internal/yaml_parser.h b/include/libcamera/internal/yaml_parser.h index 61f22232..9c85d26a 100644 --- a/include/libcamera/internal/yaml_parser.h +++ b/include/libcamera/internal/yaml_parser.h @@ -25,12 +25,21 @@ class YamlParserContext; class YamlObject { private: - using DictContainer = std::map>; + struct Value { + Value(std::string &&k, std::unique_ptr &&v) + : key(std::move(k)), value(std::move(v)) + { + } + std::string key; + std::unique_ptr value; + }; + + using Container = std::vector; using ListContainer = std::vector>; public: #ifndef __DOXYGEN__ - template + template class Iterator { public: @@ -66,10 +75,10 @@ public: } protected: - typename Container::const_iterator it_; + Container::const_iterator it_; }; - template + template class Adapter { public: @@ -92,7 +101,7 @@ public: const Container &container_; }; - class ListIterator : public Iterator + class ListIterator : public Iterator { public: using value_type = const YamlObject &; @@ -101,16 +110,16 @@ public: value_type operator*() const { - return *it_->get(); + return *it_->value.get(); } pointer operator->() const { - return it_->get(); + return it_->value.get(); } }; - class DictIterator : public Iterator + class DictIterator : public Iterator { public: using value_type = std::pair; @@ -119,17 +128,17 @@ public: value_type operator*() const { - return { it_->first, *it_->second.get() }; + return { it_->key, *it_->value.get() }; } }; - class DictAdapter : public Adapter + class DictAdapter : public Adapter { public: using key_type = std::string; }; - class ListAdapter : public Adapter + class ListAdapter : public Adapter { }; #endif /* __DOXYGEN__ */ @@ -174,7 +183,7 @@ public: return get().value_or(defaultValue); } - DictAdapter asDict() const { return DictAdapter{ dictionary_ }; } + DictAdapter asDict() const { return DictAdapter{ list_ }; } ListAdapter asList() const { return ListAdapter{ list_ }; } const YamlObject &operator[](std::size_t index) const; @@ -196,8 +205,8 @@ private: Type type_; std::string value_; - ListContainer list_; - DictContainer dictionary_; + Container list_; + std::map dictionary_; }; class YamlParser final diff --git a/src/libcamera/yaml_parser.cpp b/src/libcamera/yaml_parser.cpp index 4299f5ab..89c234fb 100644 --- a/src/libcamera/yaml_parser.cpp +++ b/src/libcamera/yaml_parser.cpp @@ -85,7 +85,6 @@ std::size_t YamlObject::size() const { switch (type_) { case Type::Dictionary: - return dictionary_.size(); case Type::List: return list_.size(); default: @@ -280,11 +279,11 @@ std::optional YamlObject::get() const if (list_.size() != 2) return {}; - auto width = list_[0]->get(); + auto width = list_[0].value->get(); if (!width) return {}; - auto height = list_[1]->get(); + auto height = list_[1].value->get(); if (!height) return {}; @@ -347,7 +346,7 @@ const YamlObject &YamlObject::operator[](std::size_t index) const if (type_ != Type::List || index >= size()) return empty; - return *list_[index]; + return *list_[index].value; } /** @@ -363,7 +362,7 @@ const YamlObject &YamlObject::operator[](std::size_t index) const */ bool YamlObject::contains(const std::string &key) const { - if (dictionary_.find(key) == dictionary_.end()) + if (dictionary_.find(std::ref(key)) == dictionary_.end()) return false; return true; @@ -635,16 +634,16 @@ int YamlParserContext::parseNextYamlObject(YamlObject &yamlObject, EventPtr even yamlObject.type_ = YamlObject::Type::List; auto &list = yamlObject.list_; auto handler = [this, &list](EventPtr evt) { - list.emplace_back(new YamlObject()); - return parseNextYamlObject(*list.back(), std::move(evt)); + list.emplace_back(std::string{}, std::make_unique()); + return parseNextYamlObject(*list.back().value, std::move(evt)); }; return parseDictionaryOrList(YamlObject::Type::List, handler); } case YAML_MAPPING_START_EVENT: { yamlObject.type_ = YamlObject::Type::Dictionary; - auto &dictionary = yamlObject.dictionary_; - auto handler = [this, &dictionary](EventPtr evtKey) { + auto &list = yamlObject.list_; + auto handler = [this, &list](EventPtr evtKey) { /* Parse key */ if (evtKey->type != YAML_SCALAR_EVENT) { LOG(YamlParser, Error) << "Expect key at line: " @@ -662,10 +661,19 @@ int YamlParserContext::parseNextYamlObject(YamlObject &yamlObject, EventPtr even if (!evtValue) return -EINVAL; - auto elem = dictionary.emplace(key, std::make_unique()); - return parseNextYamlObject(*elem.first->second.get(), std::move(evtValue)); + auto &elem = list.emplace_back(std::move(key), + std::make_unique()); + return parseNextYamlObject(*elem.value, std::move(evtValue)); }; - return parseDictionaryOrList(YamlObject::Type::Dictionary, handler); + int ret = parseDictionaryOrList(YamlObject::Type::Dictionary, handler); + if (ret) + return ret; + + auto &dictionary = yamlObject.dictionary_; + for (const auto &elem : list) + dictionary.emplace(elem.key, elem.value.get()); + + return 0; } default: @@ -721,6 +729,9 @@ int YamlParserContext::parseNextYamlObject(YamlObject &yamlObject, EventPtr even * The YamlParser::parse() function takes an open FILE, parses its contents, and * returns a pointer to a YamlObject corresponding to the root node of the YAML * document. + * + * The parser preserves the order of items in the YAML file, for both lists and + * dictionaries. */ /**