From patchwork Tue Jan 13 00:07:49 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 25737 Return-Path: X-Original-To: parsemail@patchwork.libcamera.org Delivered-To: parsemail@patchwork.libcamera.org Received: from lancelot.ideasonboard.com (lancelot.ideasonboard.com [92.243.16.209]) by patchwork.libcamera.org (Postfix) with ESMTPS id DA3D5C32DE for ; Tue, 13 Jan 2026 00:08:57 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 6A17761FD7; Tue, 13 Jan 2026 01:08:57 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="LMwBATiy"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 2F83C61FC8 for ; Tue, 13 Jan 2026 01:08:56 +0100 (CET) Received: from pendragon.ideasonboard.com (81-175-209-152.bb.dnainternet.fi [81.175.209.152]) by perceval.ideasonboard.com (Postfix) with UTF8SMTPSA id 49F4CF06 for ; Tue, 13 Jan 2026 01:08:30 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1768262910; bh=3/3XeS833dC0RKDMMaIuW6uxZHlGpT0KH70GyKfUqTw=; h=From:To:Subject:Date:In-Reply-To:References:From; b=LMwBATiy2UPzCZdIzZSQMDZE5eLzVQEc/ibhMeo9EkZHAELUWTv2W1jvsVZ307giW mMpmLYDAGYHE/sNwZLFPD1GDc7mpu1k93qy6UvfImCeEcKhJ9R2QdaCadOY5ckvLQg ut5IPTJM8+pVr0e8Cbqp/84EZZuBUCyBgKZHaWf0= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Subject: [PATCH 17/36] libcamera: yaml_parser: Split YamlObject from YamlParser Date: Tue, 13 Jan 2026 02:07:49 +0200 Message-ID: <20260113000808.15395-18-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.51.2 In-Reply-To: <20260113000808.15395-1-laurent.pinchart@ideasonboard.com> References: <20260113000808.15395-1-laurent.pinchart@ideasonboard.com> MIME-Version: 1.0 X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: libcamera-devel-bounces@lists.libcamera.org Sender: "libcamera-devel" 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 --- .../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 -#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 #include -#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 #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 +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +namespace libcamera { + +class YamlObject +{ +private: + 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 ValueContainer = std::vector; + +public: +#ifndef __DOXYGEN__ + template + 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(this); + } + + Derived operator++(int) + { + Derived it = *static_cast(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 + 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 + { + 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 + { + public: + using value_type = std::pair; + using pointer = value_type *; + using reference = value_type &; + + value_type operator*() const + { + return { it_->key, *it_->value.get() }; + } + }; + + class DictAdapter : public Adapter + { + public: + using key_type = std::string; + }; + + class ListAdapter : public Adapter + { + }; +#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 + std::optional get() const + { + return Accessor{}.get(*this); + } + + template + T get(U &&defaultValue) const + { + return get().value_or(std::forward(defaultValue)); + } + + template + void set(T &&value) + { + return Accessor>{}.set(*this, std::forward(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 child); + YamlObject *add(std::string key, std::unique_ptr child); + +private: + LIBCAMERA_DISABLE_COPY_AND_MOVE(YamlObject) + + template + friend struct Accessor; + + enum class Type { + Dictionary, + List, + Value, + Empty, + }; + + template + struct Accessor { + std::optional get(const YamlObject &obj) const; + void set(YamlObject &obj, T value); + }; + + Type type_; + + std::string value_; + ValueContainer list_; + std::map> 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 -#include -#include -#include -#include -#include -#include +#include -#include +#include "libcamera/internal/yaml_object.h" namespace libcamera { class File; -class YamlParserContext; - -class YamlObject -{ -private: - 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 ValueContainer = std::vector; - -public: -#ifndef __DOXYGEN__ - template - 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(this); - } - - Derived operator++(int) - { - Derived it = *static_cast(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 - 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 - { - 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 - { - public: - using value_type = std::pair; - using pointer = value_type *; - using reference = value_type &; - - value_type operator*() const - { - return { it_->key, *it_->value.get() }; - } - }; - - class DictAdapter : public Adapter - { - public: - using key_type = std::string; - }; - - class ListAdapter : public Adapter - { - }; -#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 - std::optional get() const - { - return Accessor{}.get(*this); - } - - template - T get(U &&defaultValue) const - { - return get().value_or(std::forward(defaultValue)); - } - - template - void set(T &&value) - { - return Accessor>{}.set(*this, std::forward(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 child); - YamlObject *add(std::string key, std::unique_ptr child); - -private: - LIBCAMERA_DISABLE_COPY_AND_MOVE(YamlObject) - - template - friend struct Accessor; - - enum class Type { - Dictionary, - List, - Value, - Empty, - }; - - template - struct Accessor { - std::optional get(const YamlObject &obj) const; - void set(YamlObject &obj, T value); - }; - - Type type_; - - std::string value_; - ValueContainer list_; - std::map> 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 -#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 #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 #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 -#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 -#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 -#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 -#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 #include -#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 #include -#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 #include -#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 -#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 -#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 -#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 -#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 #include -#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 #include -#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 #include -#include "libcamera/internal/yaml_parser.h" +#include "libcamera/internal/yaml_object.h" #include #include 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 #include -#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 #include -#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 -#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 #include 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 #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 +#include +#include +#include + +#include + +/** + * \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 YamlObject::get() 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 YamlObject::get(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 YamlObject::set(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() 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 +YamlObject::Accessor::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::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 +struct YamlObject::Accessor || + std::is_same_v || + std::is_same_v || + std::is_same_v || + std::is_same_v || + std::is_same_v>> +{ + std::optional 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; +template struct YamlObject::Accessor; +template struct YamlObject::Accessor; +template struct YamlObject::Accessor; +template struct YamlObject::Accessor; +template struct YamlObject::Accessor; + +template<> +std::optional +YamlObject::Accessor::get(const YamlObject &obj) const +{ + return obj.get(); +} + +template<> +void YamlObject::Accessor::set(YamlObject &obj, float value) +{ + obj.set(std::forward(value)); +} + +template<> +std::optional +YamlObject::Accessor::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::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 +YamlObject::Accessor::get(const YamlObject &obj) const +{ + if (obj.type_ != Type::Value) + return std::nullopt; + + return obj.value_; +} + +template<> +void YamlObject::Accessor::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 +struct YamlObject::Accessor, std::enable_if_t< + std::is_same_v || + std::is_same_v || + std::is_same_v || + std::is_same_v || + std::is_same_v || + std::is_same_v || + std::is_same_v || + std::is_same_v || + std::is_same_v || + std::is_same_v>> +{ + std::optional> get(const YamlObject &obj) const + { + if (obj.type_ != Type::List) + return std::nullopt; + + std::vector values; + values.reserve(obj.list_.size()); + + for (const YamlObject &entry : obj.asList()) { + const auto value = entry.get(); + if (!value) + return std::nullopt; + values.emplace_back(*value); + } + + return values; + } +}; + +template struct YamlObject::Accessor>; +template struct YamlObject::Accessor>; +template struct YamlObject::Accessor>; +template struct YamlObject::Accessor>; +template struct YamlObject::Accessor>; +template struct YamlObject::Accessor>; +template struct YamlObject::Accessor>; +template struct YamlObject::Accessor>; +template struct YamlObject::Accessor>; +template struct YamlObject::Accessor>; +#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 + * std::pair. + * + * 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 const YamlObject &. + * + * 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 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 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 #include #include -#include -#include +#include +#include #include #include @@ -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 YamlObject::get() 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 YamlObject::get(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 YamlObject::set(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() 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 -YamlObject::Accessor::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::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 -struct YamlObject::Accessor || - std::is_same_v || - std::is_same_v || - std::is_same_v || - std::is_same_v || - std::is_same_v>> -{ - std::optional 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; -template struct YamlObject::Accessor; -template struct YamlObject::Accessor; -template struct YamlObject::Accessor; -template struct YamlObject::Accessor; -template struct YamlObject::Accessor; - -template<> -std::optional -YamlObject::Accessor::get(const YamlObject &obj) const -{ - return obj.get(); -} - -template<> -void YamlObject::Accessor::set(YamlObject &obj, float value) -{ - obj.set(std::forward(value)); -} - -template<> -std::optional -YamlObject::Accessor::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::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 -YamlObject::Accessor::get(const YamlObject &obj) const -{ - if (obj.type_ != Type::Value) - return std::nullopt; - - return obj.value_; -} - -template<> -void YamlObject::Accessor::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 -struct YamlObject::Accessor, std::enable_if_t< - std::is_same_v || - std::is_same_v || - std::is_same_v || - std::is_same_v || - std::is_same_v || - std::is_same_v || - std::is_same_v || - std::is_same_v || - std::is_same_v || - std::is_same_v>> -{ - std::optional> get(const YamlObject &obj) const - { - if (obj.type_ != Type::List) - return std::nullopt; - - std::vector values; - values.reserve(obj.list_.size()); - - for (const YamlObject &entry : obj.asList()) { - const auto value = entry.get(); - if (!value) - return std::nullopt; - values.emplace_back(*value); - } - - return values; - } -}; - -template struct YamlObject::Accessor>; -template struct YamlObject::Accessor>; -template struct YamlObject::Accessor>; -template struct YamlObject::Accessor>; -template struct YamlObject::Accessor>; -template struct YamlObject::Accessor>; -template struct YamlObject::Accessor>; -template struct YamlObject::Accessor>; -template struct YamlObject::Accessor>; -template struct YamlObject::Accessor>; -#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 - * std::pair. - * - * 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 const YamlObject &. - * - * 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 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 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