/* 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(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 ValueNode &; using pointer = const ValueNode *; 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__ */ ValueNode(); ~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() const { return DictAdapter{ list_ }; } ListAdapter asList() const { return ListAdapter{ list_ }; } const ValueNode &operator[](std::size_t index) const; bool contains(std::string_view key) const; 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 */