libcamera: yaml_parser: Split YamlObject from YamlParser
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 <laurent.pinchart@ideasonboard.com> Reviewed-by: Barnabás Pőcze <barnabas.pocze@ideasonboard.com> Reviewed-by: Isaac Scott <isaac.scott@ideasonboard.com>
This commit is contained in:
@@ -14,7 +14,7 @@
|
||||
|
||||
#include <libcamera/base/utils.h>
|
||||
|
||||
#include "libcamera/internal/yaml_parser.h"
|
||||
#include "libcamera/internal/yaml_object.h"
|
||||
|
||||
namespace libcamera {
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
#include <libcamera/base/log.h>
|
||||
#include <libcamera/base/span.h>
|
||||
|
||||
#include "libcamera/internal/yaml_parser.h"
|
||||
#include "libcamera/internal/yaml_object.h"
|
||||
|
||||
namespace libcamera {
|
||||
|
||||
|
||||
@@ -49,6 +49,7 @@ libcamera_internal_headers = files([
|
||||
'v4l2_subdevice.h',
|
||||
'v4l2_videodevice.h',
|
||||
'vector.h',
|
||||
'yaml_object.h',
|
||||
'yaml_parser.h',
|
||||
])
|
||||
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
#include <libcamera/base/span.h>
|
||||
|
||||
#include "libcamera/internal/matrix.h"
|
||||
#include "libcamera/internal/yaml_parser.h"
|
||||
#include "libcamera/internal/yaml_object.h"
|
||||
|
||||
namespace libcamera {
|
||||
|
||||
|
||||
@@ -0,0 +1,227 @@
|
||||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
/*
|
||||
* Copyright (C) 2022, Google Inc.
|
||||
* Copyright (C) 2026, Ideas on Board
|
||||
*
|
||||
* libcamera YAML object
|
||||
*/
|
||||
|
||||
#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 YamlObject
|
||||
{
|
||||
private:
|
||||
struct Value {
|
||||
Value(std::string k, std::unique_ptr<YamlObject> &&v)
|
||||
: key(std::move(k)), value(std::move(v))
|
||||
{
|
||||
}
|
||||
std::string key;
|
||||
std::unique_ptr<YamlObject> value;
|
||||
};
|
||||
|
||||
using ValueContainer = std::vector<Value>;
|
||||
|
||||
public:
|
||||
#ifndef __DOXYGEN__
|
||||
template<typename Derived>
|
||||
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<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:
|
||||
ValueContainer::const_iterator it_;
|
||||
};
|
||||
|
||||
template<typename Iterator>
|
||||
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<ListIterator>
|
||||
{
|
||||
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<DictIterator>
|
||||
{
|
||||
public:
|
||||
using value_type = std::pair<const std::string &, const YamlObject &>;
|
||||
using pointer = value_type *;
|
||||
using reference = value_type &;
|
||||
|
||||
value_type operator*() const
|
||||
{
|
||||
return { it_->key, *it_->value.get() };
|
||||
}
|
||||
};
|
||||
|
||||
class DictAdapter : public Adapter<DictIterator>
|
||||
{
|
||||
public:
|
||||
using key_type = std::string;
|
||||
};
|
||||
|
||||
class ListAdapter : public Adapter<ListIterator>
|
||||
{
|
||||
};
|
||||
#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<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 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<YamlObject> &&child);
|
||||
YamlObject *add(std::string key, std::unique_ptr<YamlObject> &&child);
|
||||
|
||||
private:
|
||||
LIBCAMERA_DISABLE_COPY_AND_MOVE(YamlObject)
|
||||
|
||||
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 YamlObject &obj) const;
|
||||
void set(YamlObject &obj, T value);
|
||||
};
|
||||
|
||||
Type type_;
|
||||
|
||||
std::string value_;
|
||||
ValueContainer list_;
|
||||
std::map<std::string, YamlObject *, std::less<>> dictionary_;
|
||||
};
|
||||
|
||||
} /* namespace libcamera */
|
||||
@@ -7,222 +7,13 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <iterator>
|
||||
#include <map>
|
||||
#include <optional>
|
||||
#include <stdint.h>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
|
||||
#include <libcamera/base/class.h>
|
||||
#include "libcamera/internal/yaml_object.h"
|
||||
|
||||
namespace libcamera {
|
||||
|
||||
class File;
|
||||
class YamlParserContext;
|
||||
|
||||
class YamlObject
|
||||
{
|
||||
private:
|
||||
struct Value {
|
||||
Value(std::string k, std::unique_ptr<YamlObject> &&v)
|
||||
: key(std::move(k)), value(std::move(v))
|
||||
{
|
||||
}
|
||||
std::string key;
|
||||
std::unique_ptr<YamlObject> value;
|
||||
};
|
||||
|
||||
using ValueContainer = std::vector<Value>;
|
||||
|
||||
public:
|
||||
#ifndef __DOXYGEN__
|
||||
template<typename Derived>
|
||||
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<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:
|
||||
ValueContainer::const_iterator it_;
|
||||
};
|
||||
|
||||
template<typename Iterator>
|
||||
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<ListIterator>
|
||||
{
|
||||
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<DictIterator>
|
||||
{
|
||||
public:
|
||||
using value_type = std::pair<const std::string &, const YamlObject &>;
|
||||
using pointer = value_type *;
|
||||
using reference = value_type &;
|
||||
|
||||
value_type operator*() const
|
||||
{
|
||||
return { it_->key, *it_->value.get() };
|
||||
}
|
||||
};
|
||||
|
||||
class DictAdapter : public Adapter<DictIterator>
|
||||
{
|
||||
public:
|
||||
using key_type = std::string;
|
||||
};
|
||||
|
||||
class ListAdapter : public Adapter<ListIterator>
|
||||
{
|
||||
};
|
||||
#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<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 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<YamlObject> &&child);
|
||||
YamlObject *add(std::string key, std::unique_ptr<YamlObject> &&child);
|
||||
|
||||
private:
|
||||
LIBCAMERA_DISABLE_COPY_AND_MOVE(YamlObject)
|
||||
|
||||
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 YamlObject &obj) const;
|
||||
void set(YamlObject &obj, T value);
|
||||
};
|
||||
|
||||
Type type_;
|
||||
|
||||
std::string value_;
|
||||
ValueContainer list_;
|
||||
std::map<std::string, YamlObject *, std::less<>> dictionary_;
|
||||
};
|
||||
|
||||
class YamlParser final
|
||||
{
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
|
||||
#include <libcamera/controls.h>
|
||||
|
||||
#include "libcamera/internal/yaml_parser.h"
|
||||
#include "libcamera/internal/yaml_object.h"
|
||||
|
||||
#include "exposure_mode_helper.h"
|
||||
#include "histogram.h"
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
#include <libcamera/controls.h>
|
||||
|
||||
#include "libcamera/internal/vector.h"
|
||||
#include "libcamera/internal/yaml_parser.h"
|
||||
#include "libcamera/internal/yaml_object.h"
|
||||
|
||||
namespace libcamera {
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
#include <libcamera/controls.h>
|
||||
|
||||
#include "libcamera/internal/vector.h"
|
||||
#include "libcamera/internal/yaml_parser.h"
|
||||
#include "libcamera/internal/yaml_object.h"
|
||||
|
||||
#include "awb.h"
|
||||
#include "interpolator.h"
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
|
||||
#include <libcamera/base/log.h>
|
||||
|
||||
#include "libcamera/internal/yaml_parser.h"
|
||||
#include "libcamera/internal/yaml_object.h"
|
||||
|
||||
namespace libcamera {
|
||||
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
|
||||
#include <libcamera/geometry.h>
|
||||
|
||||
#include "libcamera/internal/yaml_parser.h"
|
||||
#include "libcamera/internal/yaml_object.h"
|
||||
|
||||
namespace libcamera {
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
|
||||
#include <libcamera/base/log.h>
|
||||
|
||||
#include "libcamera/internal/yaml_parser.h"
|
||||
#include "libcamera/internal/yaml_object.h"
|
||||
|
||||
#include "histogram.h"
|
||||
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
#include <libcamera/base/log.h>
|
||||
#include <libcamera/base/utils.h>
|
||||
|
||||
#include "libcamera/internal/yaml_parser.h"
|
||||
#include "libcamera/internal/yaml_object.h"
|
||||
|
||||
#include "algorithm.h"
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
#include <libcamera/base/log.h>
|
||||
#include <libcamera/control_ids.h>
|
||||
|
||||
#include "libcamera/internal/yaml_parser.h"
|
||||
#include "libcamera/internal/yaml_object.h"
|
||||
|
||||
/**
|
||||
* \file blc.h
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
|
||||
#include "lsc.h"
|
||||
|
||||
#include "libcamera/internal/yaml_parser.h"
|
||||
#include "libcamera/internal/yaml_object.h"
|
||||
|
||||
namespace libcamera {
|
||||
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
#include <libcamera/control_ids.h>
|
||||
#include <libcamera/ipa/core_ipa_interface.h>
|
||||
|
||||
#include "libcamera/internal/yaml_parser.h"
|
||||
#include "libcamera/internal/yaml_object.h"
|
||||
|
||||
#include "libipa/histogram.h"
|
||||
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
|
||||
#include <libcamera/control_ids.h>
|
||||
|
||||
#include "libcamera/internal/yaml_parser.h"
|
||||
#include "libcamera/internal/yaml_object.h"
|
||||
|
||||
/**
|
||||
* \file blc.h
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
|
||||
#include <libcamera/ipa/core_ipa_interface.h>
|
||||
|
||||
#include "libcamera/internal/yaml_parser.h"
|
||||
#include "libcamera/internal/yaml_object.h"
|
||||
|
||||
#include "libipa/fixedpoint.h"
|
||||
#include "libipa/interpolator.h"
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
|
||||
#include <libcamera/base/log.h>
|
||||
|
||||
#include "libcamera/internal/yaml_parser.h"
|
||||
#include "libcamera/internal/yaml_object.h"
|
||||
|
||||
#include "linux/rkisp1-config.h"
|
||||
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
|
||||
#include <libcamera/control_ids.h>
|
||||
|
||||
#include "libcamera/internal/yaml_parser.h"
|
||||
#include "libcamera/internal/yaml_object.h"
|
||||
|
||||
#include "linux/rkisp1-config.h"
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
#include <libcamera/base/log.h>
|
||||
#include <libcamera/base/utils.h>
|
||||
|
||||
#include "libcamera/internal/yaml_parser.h"
|
||||
#include "libcamera/internal/yaml_object.h"
|
||||
|
||||
#include "linux/rkisp1-config.h"
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
#include <libcamera/base/log.h>
|
||||
#include <libcamera/base/utils.h>
|
||||
|
||||
#include "libcamera/internal/yaml_parser.h"
|
||||
#include "libcamera/internal/yaml_object.h"
|
||||
|
||||
#include "libipa/lsc_polynomial.h"
|
||||
#include "linux/rkisp1-config.h"
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
#include <libcamera/base/log.h>
|
||||
#include <libcamera/base/utils.h>
|
||||
|
||||
#include "libcamera/internal/yaml_parser.h"
|
||||
#include "libcamera/internal/yaml_object.h"
|
||||
|
||||
#include <libipa/agc_mean_luminance.h>
|
||||
#include <libipa/histogram.h>
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
#include <memory>
|
||||
#include <map>
|
||||
|
||||
#include "libcamera/internal/yaml_parser.h"
|
||||
#include "libcamera/internal/yaml_object.h"
|
||||
|
||||
#include "controller.h"
|
||||
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
#include <string>
|
||||
|
||||
#include <libcamera/base/utils.h>
|
||||
#include "libcamera/internal/yaml_parser.h"
|
||||
#include "libcamera/internal/yaml_object.h"
|
||||
|
||||
#include "camera_mode.h"
|
||||
#include "device_status.h"
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
|
||||
#include <libcamera/base/log.h>
|
||||
|
||||
#include "libcamera/internal/yaml_parser.h"
|
||||
#include "libcamera/internal/yaml_object.h"
|
||||
|
||||
/**
|
||||
* \file geometry.h
|
||||
|
||||
@@ -58,6 +58,7 @@ libcamera_internal_sources = files([
|
||||
'v4l2_subdevice.cpp',
|
||||
'v4l2_videodevice.cpp',
|
||||
'vector.cpp',
|
||||
'yaml_object.cpp',
|
||||
'yaml_parser.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;
|
||||
|
||||
|
||||
@@ -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 <libcamera/ipa/raspberrypi_ipa_interface.h>
|
||||
#include <libcamera/ipa/raspberrypi_ipa_proxy.h>
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
#include <libcamera/base/file.h>
|
||||
|
||||
#include "libcamera/internal/pipeline_handler.h"
|
||||
#include "libcamera/internal/yaml_parser.h"
|
||||
#include "libcamera/internal/yaml_object.h"
|
||||
|
||||
#include "virtual.h"
|
||||
|
||||
|
||||
@@ -37,7 +37,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"
|
||||
|
||||
|
||||
@@ -0,0 +1,469 @@
|
||||
/* 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 <charconv>
|
||||
#include <errno.h>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include <libcamera/base/utils.h>
|
||||
|
||||
/**
|
||||
* \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<typename T> YamlObject::get<T>() 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<typename T, typename U> YamlObject::get<T>(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<typename T> YamlObject::set<T>(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<T>() will return the same value.
|
||||
*
|
||||
* \todo Implement the conversion guarantee for floating point types
|
||||
*
|
||||
* 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<bool>
|
||||
YamlObject::Accessor<bool>::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<bool>::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<typename T>
|
||||
struct YamlObject::Accessor<T, std::enable_if_t<
|
||||
std::is_same_v<int8_t, T> ||
|
||||
std::is_same_v<uint8_t, T> ||
|
||||
std::is_same_v<int16_t, T> ||
|
||||
std::is_same_v<uint16_t, T> ||
|
||||
std::is_same_v<int32_t, T> ||
|
||||
std::is_same_v<uint32_t, T>>>
|
||||
{
|
||||
std::optional<T> 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<int8_t>;
|
||||
template struct YamlObject::Accessor<uint8_t>;
|
||||
template struct YamlObject::Accessor<int16_t>;
|
||||
template struct YamlObject::Accessor<uint16_t>;
|
||||
template struct YamlObject::Accessor<int32_t>;
|
||||
template struct YamlObject::Accessor<uint32_t>;
|
||||
|
||||
template<>
|
||||
std::optional<float>
|
||||
YamlObject::Accessor<float>::get(const YamlObject &obj) const
|
||||
{
|
||||
return obj.get<double>();
|
||||
}
|
||||
|
||||
template<>
|
||||
void YamlObject::Accessor<float>::set(YamlObject &obj, float value)
|
||||
{
|
||||
obj.set<double>(value);
|
||||
}
|
||||
|
||||
template<>
|
||||
std::optional<double>
|
||||
YamlObject::Accessor<double>::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<double>::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<std::string>
|
||||
YamlObject::Accessor<std::string>::get(const YamlObject &obj) const
|
||||
{
|
||||
if (obj.type_ != Type::Value)
|
||||
return std::nullopt;
|
||||
|
||||
return obj.value_;
|
||||
}
|
||||
|
||||
template<>
|
||||
void YamlObject::Accessor<std::string>::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<typename T>
|
||||
struct YamlObject::Accessor<std::vector<T>> {
|
||||
std::optional<std::vector<T>> get(const YamlObject &obj) const
|
||||
{
|
||||
if (obj.type_ != Type::List)
|
||||
return std::nullopt;
|
||||
|
||||
std::vector<T> values;
|
||||
values.reserve(obj.list_.size());
|
||||
|
||||
for (const YamlObject &entry : obj.asList()) {
|
||||
auto value = entry.get<T>();
|
||||
if (!value)
|
||||
return std::nullopt;
|
||||
values.emplace_back(std::move(*value));
|
||||
}
|
||||
|
||||
return values;
|
||||
}
|
||||
};
|
||||
|
||||
template struct YamlObject::Accessor<std::vector<bool>>;
|
||||
template struct YamlObject::Accessor<std::vector<float>>;
|
||||
template struct YamlObject::Accessor<std::vector<double>>;
|
||||
template struct YamlObject::Accessor<std::vector<int8_t>>;
|
||||
template struct YamlObject::Accessor<std::vector<uint8_t>>;
|
||||
template struct YamlObject::Accessor<std::vector<int16_t>>;
|
||||
template struct YamlObject::Accessor<std::vector<uint16_t>>;
|
||||
template struct YamlObject::Accessor<std::vector<int32_t>>;
|
||||
template struct YamlObject::Accessor<std::vector<uint32_t>>;
|
||||
template struct YamlObject::Accessor<std::vector<std::string>>;
|
||||
#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
|
||||
* <em>std::pair<const std::string &, const \ref YamlObject &></em>.
|
||||
*
|
||||
* 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 <em>const YamlObject &</em>.
|
||||
*
|
||||
* 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 object as the last element of this object's children
|
||||
* list. This object must be empty, in which case it is converted to the
|
||||
* Type::List type, or be a list. Otherwise, the function returns a nullptr and
|
||||
* the \a child is not modified.
|
||||
*
|
||||
* \return A pointer to the child object if successfully added, nullptr
|
||||
* otherwise
|
||||
*/
|
||||
YamlObject *YamlObject::add(std::unique_ptr<YamlObject> &&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 object with the given \a key to this object's children. This
|
||||
* object must be empty, in which case it is converted to the Type::Dictionary
|
||||
* type, or be a dictionary. Otherwise, the function returns a nullptr and the
|
||||
* \a child is not modified.
|
||||
*
|
||||
* Keys are unique. If a child with the same \a key already exists, the function
|
||||
* returns a nullptr and the \a child is not modified.
|
||||
*
|
||||
* \return A pointer to the child object if successfully added, nullptr
|
||||
* otherwise
|
||||
*/
|
||||
YamlObject *YamlObject::add(std::string key, std::unique_ptr<YamlObject> &&child)
|
||||
{
|
||||
if (type_ == Type::Empty)
|
||||
type_ = Type::Dictionary;
|
||||
|
||||
if (type_ != Type::Dictionary)
|
||||
return nullptr;
|
||||
|
||||
auto [it, inserted] = dictionary_.try_emplace(std::move(key), child.get());
|
||||
if (!inserted)
|
||||
return nullptr;
|
||||
|
||||
return list_.emplace_back(it->first, std::move(child)).value.get();
|
||||
}
|
||||
|
||||
} /* namespace libcamera */
|
||||
@@ -7,11 +7,10 @@
|
||||
|
||||
#include "libcamera/internal/yaml_parser.h"
|
||||
|
||||
#include <charconv>
|
||||
#include <errno.h>
|
||||
#include <functional>
|
||||
#include <limits>
|
||||
#include <stdlib.h>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
#include <libcamera/base/file.h>
|
||||
#include <libcamera/base/log.h>
|
||||
@@ -27,449 +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<typename T> YamlObject::get<T>() 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<typename T, typename U> YamlObject::get<T>(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<typename T> YamlObject::set<T>(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<T>() will return the same value.
|
||||
*
|
||||
* \todo Implement the conversion guarantee for floating point types
|
||||
*
|
||||
* 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<bool>
|
||||
YamlObject::Accessor<bool>::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<bool>::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<typename T>
|
||||
struct YamlObject::Accessor<T, std::enable_if_t<
|
||||
std::is_same_v<int8_t, T> ||
|
||||
std::is_same_v<uint8_t, T> ||
|
||||
std::is_same_v<int16_t, T> ||
|
||||
std::is_same_v<uint16_t, T> ||
|
||||
std::is_same_v<int32_t, T> ||
|
||||
std::is_same_v<uint32_t, T>>>
|
||||
{
|
||||
std::optional<T> 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<int8_t>;
|
||||
template struct YamlObject::Accessor<uint8_t>;
|
||||
template struct YamlObject::Accessor<int16_t>;
|
||||
template struct YamlObject::Accessor<uint16_t>;
|
||||
template struct YamlObject::Accessor<int32_t>;
|
||||
template struct YamlObject::Accessor<uint32_t>;
|
||||
|
||||
template<>
|
||||
std::optional<float>
|
||||
YamlObject::Accessor<float>::get(const YamlObject &obj) const
|
||||
{
|
||||
return obj.get<double>();
|
||||
}
|
||||
|
||||
template<>
|
||||
void YamlObject::Accessor<float>::set(YamlObject &obj, float value)
|
||||
{
|
||||
obj.set<double>(value);
|
||||
}
|
||||
|
||||
template<>
|
||||
std::optional<double>
|
||||
YamlObject::Accessor<double>::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<double>::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<std::string>
|
||||
YamlObject::Accessor<std::string>::get(const YamlObject &obj) const
|
||||
{
|
||||
if (obj.type_ != Type::Value)
|
||||
return std::nullopt;
|
||||
|
||||
return obj.value_;
|
||||
}
|
||||
|
||||
template<>
|
||||
void YamlObject::Accessor<std::string>::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<typename T>
|
||||
struct YamlObject::Accessor<std::vector<T>> {
|
||||
std::optional<std::vector<T>> get(const YamlObject &obj) const
|
||||
{
|
||||
if (obj.type_ != Type::List)
|
||||
return std::nullopt;
|
||||
|
||||
std::vector<T> values;
|
||||
values.reserve(obj.list_.size());
|
||||
|
||||
for (const YamlObject &entry : obj.asList()) {
|
||||
auto value = entry.get<T>();
|
||||
if (!value)
|
||||
return std::nullopt;
|
||||
values.emplace_back(std::move(*value));
|
||||
}
|
||||
|
||||
return values;
|
||||
}
|
||||
};
|
||||
|
||||
template struct YamlObject::Accessor<std::vector<bool>>;
|
||||
template struct YamlObject::Accessor<std::vector<float>>;
|
||||
template struct YamlObject::Accessor<std::vector<double>>;
|
||||
template struct YamlObject::Accessor<std::vector<int8_t>>;
|
||||
template struct YamlObject::Accessor<std::vector<uint8_t>>;
|
||||
template struct YamlObject::Accessor<std::vector<int16_t>>;
|
||||
template struct YamlObject::Accessor<std::vector<uint16_t>>;
|
||||
template struct YamlObject::Accessor<std::vector<int32_t>>;
|
||||
template struct YamlObject::Accessor<std::vector<uint32_t>>;
|
||||
template struct YamlObject::Accessor<std::vector<std::string>>;
|
||||
#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
|
||||
* <em>std::pair<const std::string &, const \ref YamlObject &></em>.
|
||||
*
|
||||
* 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 <em>const YamlObject &</em>.
|
||||
*
|
||||
* 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 object as the last element of this object's children
|
||||
* list. This object must be empty, in which case it is converted to the
|
||||
* Type::List type, or be a list. Otherwise, the function returns a nullptr and
|
||||
* the \a child is not modified.
|
||||
*
|
||||
* \return A pointer to the child object if successfully added, nullptr
|
||||
* otherwise
|
||||
*/
|
||||
YamlObject *YamlObject::add(std::unique_ptr<YamlObject> &&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 object with the given \a key to this object's children. This
|
||||
* object must be empty, in which case it is converted to the Type::Dictionary
|
||||
* type, or be a dictionary. Otherwise, the function returns a nullptr and the
|
||||
* \a child is not modified.
|
||||
*
|
||||
* Keys are unique. If a child with the same \a key already exists, the function
|
||||
* returns a nullptr and the \a child is not modified.
|
||||
*
|
||||
* \return A pointer to the child object if successfully added, nullptr
|
||||
* otherwise
|
||||
*/
|
||||
YamlObject *YamlObject::add(std::string key, std::unique_ptr<YamlObject> &&child)
|
||||
{
|
||||
if (type_ == Type::Empty)
|
||||
type_ = Type::Dictionary;
|
||||
|
||||
if (type_ != Type::Dictionary)
|
||||
return nullptr;
|
||||
|
||||
auto [it, inserted] = dictionary_.try_emplace(std::move(key), child.get());
|
||||
if (!inserted)
|
||||
return nullptr;
|
||||
|
||||
return list_.emplace_back(it->first, std::move(child)).value.get();
|
||||
}
|
||||
|
||||
#ifndef __DOXYGEN__
|
||||
|
||||
class YamlParserContext
|
||||
|
||||
Reference in New Issue
Block a user