/* SPDX-License-Identifier: LGPL-2.1-or-later */ /* * Copyright (C) 2022, Google Inc. * Copyright (C) 2026, Ideas on Board * * Data structure to manage tree of values */ #pragma once #include #include #include #include #include #include #include #include #include #include namespace libcamera { class ValueNode { 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(ContainerIterator 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: ContainerIterator it_; }; template class Adapter { public: Adapter(Container &container) : container_(container) { } Iterator begin() const { return Iterator{ container_.begin() }; } Iterator end() const { return Iterator{ container_.end() }; } protected: Container &container_; }; template class ListIterator : public Iterator, ContainerIterator> { private: using Base = Iterator, ContainerIterator>; public: using value_type = Value; using pointer = value_type *; using reference = value_type &; reference operator*() const { return *Base::it_->value.get(); } pointer operator->() const { return Base::it_->value.get(); } }; template class DictIterator : public Iterator, ContainerIterator> { private: using Base = Iterator, ContainerIterator>; public: using value_type = std::pair; using pointer = value_type *; using reference = value_type &; value_type operator*() const { return { Base::it_->key, *Base::it_->value.get() }; } }; class DictAdapter : public Adapter, ValueContainer> { public: using key_type = std::string; }; class ListAdapter : public Adapter, ValueContainer> { }; class ConstDictAdapter : public Adapter, const ValueContainer> { public: using key_type = std::string; }; class ConstListAdapter : public Adapter, const ValueContainer> { }; #endif /* __DOXYGEN__ */ ValueNode(); template ValueNode(T &&value) : type_(Type::Empty) { set(std::forward(value)); } ~ValueNode(); 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() { return DictAdapter{ list_ }; } ListAdapter asList() { return ListAdapter{ list_ }; } ConstDictAdapter asDict() const { return ConstDictAdapter{ list_ }; } ConstListAdapter asList() const { return ConstListAdapter{ list_ }; } ValueNode *at(std::size_t index); const ValueNode &operator[](std::size_t index) const; bool contains(std::string_view key) const; ValueNode *at(std::string_view key); const ValueNode &operator[](std::string_view key) const; ValueNode *add(std::unique_ptr &&child); ValueNode *add(std::string key, std::unique_ptr &&child); private: LIBCAMERA_DISABLE_COPY_AND_MOVE(ValueNode) template friend struct Accessor; enum class Type { Dictionary, List, Value, Empty, }; template struct Accessor { std::optional get(const ValueNode &obj) const; void set(ValueNode &obj, T value); }; Type type_; std::string value_; ValueContainer list_; std::map> dictionary_; }; } /* namespace libcamera */