Files
external_libcamera/include/libcamera/internal/value_node.h
Laurent Pinchart 49aa81b9ec libcamera: value_node: Rework templates to prepare for mutable views
ValueNode provides adapter classes to expose the object as an iteratable
list or dictionary. The Iterator and Adapter classes hardcode the
assumption that the ValueNode is const. To prepare for mutable views,
move the const specifier to the top-level DictAdapter and ListAdapter
class templates.

Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Reviewed-by: Barnabás Pőcze <barnabas.pocze@ideasonboard.com>
Reviewed-by: Isaac Scott <isaac.scott@ideasonboard.com>
2026-04-24 18:08:36 +03:00

252 lines
4.7 KiB
C++

/* 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 <iterator>
#include <map>
#include <memory>
#include <optional>
#include <string>
#include <string_view>
#include <type_traits>
#include <utility>
#include <vector>
#include <libcamera/base/class.h>
namespace libcamera {
class ValueNode
{
private:
struct Value {
Value(std::string k, std::unique_ptr<ValueNode> &&v)
: key(std::move(k)), value(std::move(v))
{
}
std::string key;
std::unique_ptr<ValueNode> value;
};
using ValueContainer = std::vector<Value>;
public:
#ifndef __DOXYGEN__
template<typename Derived, typename ContainerIterator>
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<Derived *>(this);
}
Derived operator++(int)
{
Derived it = *static_cast<Derived *>(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<typename Iterator, typename Container>
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<typename Value, typename ContainerIterator>
class ListIterator : public Iterator<ListIterator<Value, ContainerIterator>,
ContainerIterator>
{
private:
using Base = Iterator<ListIterator<Value, ContainerIterator>,
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<typename Value, typename ContainerIterator>
class DictIterator : public Iterator<DictIterator<Value, ContainerIterator>,
ContainerIterator>
{
private:
using Base = Iterator<DictIterator<Value, ContainerIterator>,
ContainerIterator>;
public:
using value_type = std::pair<const std::string &, Value &>;
using pointer = value_type *;
using reference = value_type &;
value_type operator*() const
{
return { Base::it_->key, *Base::it_->value.get() };
}
};
class DictAdapter : public Adapter<DictIterator<const ValueNode,
ValueContainer::const_iterator>,
const ValueContainer>
{
public:
using key_type = std::string;
};
class ListAdapter : public Adapter<ListIterator<const ValueNode,
ValueContainer::const_iterator>,
const ValueContainer>
{
};
#endif /* __DOXYGEN__ */
ValueNode();
template<typename T>
ValueNode(T &&value)
: type_(Type::Empty)
{
set(std::forward<T>(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<typename T>
std::optional<T> get() const
{
return Accessor<T>{}.get(*this);
}
template<typename T, typename U>
T get(U &&defaultValue) const
{
return get<T>().value_or(std::forward<U>(defaultValue));
}
template<typename T>
void set(T &&value)
{
return Accessor<std::remove_cv_t<std::remove_reference_t<T>>>{}
.set(*this, std::forward<T>(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<ValueNode> &&child);
ValueNode *add(std::string key, std::unique_ptr<ValueNode> &&child);
private:
LIBCAMERA_DISABLE_COPY_AND_MOVE(ValueNode)
template<typename T>
friend struct Accessor;
enum class Type {
Dictionary,
List,
Value,
Empty,
};
template<typename T, typename Enable = void>
struct Accessor {
std::optional<T> get(const ValueNode &obj) const;
void set(ValueNode &obj, T value);
};
Type type_;
std::string value_;
ValueContainer list_;
std::map<std::string, ValueNode *, std::less<>> dictionary_;
};
} /* namespace libcamera */