diff --git a/libs/containers/include/mrpt/containers/Parameters.h b/libs/containers/include/mrpt/containers/yaml.h similarity index 74% rename from libs/containers/include/mrpt/containers/Parameters.h rename to libs/containers/include/mrpt/containers/yaml.h index 0067a2d8f7..9f651c9505 100644 --- a/libs/containers/include/mrpt/containers/Parameters.h +++ b/libs/containers/include/mrpt/containers/yaml.h @@ -27,89 +27,108 @@ // forward declarations // clang-format off +// For YAMLCPP import: namespace YAML { class Node; } -namespace mrpt::containers { class Parameters; +// For auxiliary proxies: +namespace mrpt::containers { class yaml; namespace internal { enum tag_as_proxy_t {}; enum tag_as_const_proxy_t {}; - template T implAsGetter(const Parameters& p); + template T implAsGetter(const yaml& p); } // clang-format on -/** Powerful YAML-like container for possibly-nested blocks of parameters. +/** Powerful YAML-like container for possibly-nested blocks of parameters or any + * arbitrary structured data contents. * - * The class Parameters acts as a "node" in a YAML structure, and can be of one - *of these types: + * The class yaml holds the root "node" in a YAML-like structure. + * Each node can be of one of these types: * - Leaf nodes ("scalar values"): Any type, stored as a C++17 std::any. * - Sequential container. * - Map ("dictionary"): pairs of `name: value`. + * - Empty. * - * Elements contained in either sequenties or dictionaries can be either plain - *leaf types, or another container. + * Elements contained in sequences or dictionaries can be, in turn, of any of + *the four types above, leading to arbitrarialy-complex nested structures. * * This class was designed as a lightweight, while structured, way to pass - *arbitrarialy-complex parameter blocks. + *arbitrarialy-complex parameter blocks but can be used to load and save YAML + *files or as a database. * - * See example in \ref containers_parameters_example/test.cpp - * \snippet containers_parameters_example/test.cpp example-parameters + * See example in \ref containers_yaml_example/test.cpp + * \snippet containers_yaml_example/test.cpp example-yaml * * \ingroup mrpt_containers_grp * \note [new in MRPT 2.0.5] */ -class Parameters +class yaml { public: + /** @name Types + * @{ */ + using scalar_t = std::any; using parameter_name_t = std::string; - using sequence_t = std::vector; - using map_t = std::map; + struct node_t; + + using sequence_t = std::vector; + using map_t = std::map; + + struct node_t + { + node_t() = default; + node_t(const scalar_t& s) : d(s) {} + std::variant d; + }; + + /** @} */ - using data_t = std::variant; + /** @name Constructors and initializers + * @{ */ - Parameters() = default; - ~Parameters() = default; + yaml() = default; + ~yaml() = default; /** Constructor for maps, from list of pairs of values. See examples in - * Parameters above. */ - Parameters(std::initializer_list init) : data_(init) {} + * yaml above. */ + yaml(std::initializer_list init) : root_(init) {} /** Constructor for sequences, from list of values. See examples in - * Parameters above. */ - Parameters(std::initializer_list init) : data_(init) - { - } - Parameters(const Parameters& v); + * yaml above. */ + yaml(std::initializer_list init) : root_(init) {} + yaml(const yaml& v); - static Parameters Sequence( - std::initializer_list init) + static yaml Sequence(std::initializer_list init) { - return Parameters(init); + return yaml(init); } - static Parameters Sequence() + static yaml Sequence() { - Parameters p; - p.data_.emplace(); + yaml p; + p.root_.d.emplace(); return p; } - static Parameters Map(std::initializer_list init) + static yaml Map(std::initializer_list init) { - return Parameters(init); + return yaml(init); } - static Parameters Map() + static yaml Map() { - Parameters p; - p.data_.emplace(); + yaml p; + p.root_.d.emplace(); return p; } /** Builds an object copying the structure and contents from an existing * YAML Node. Requires mrpt built against yamlcpp. */ - static Parameters FromYAML(const YAML::Node& n); + static yaml FromYAML(const YAML::Node& n); - /** Parses the text as a YAML document, then converts it into a Parameters + /** Parses the text as a YAML document, then converts it into a yaml * object */ - static Parameters FromYAMLText(const std::string& yamlTextBlock); + static yaml FromYAMLText(const std::string& yamlTextBlock); + + /** @} */ /** For map nodes, checks if the given key name exists */ bool has(const std::string& key) const; @@ -141,36 +160,38 @@ class Parameters const std::type_info& type() const; /** Write access for maps */ - Parameters operator[](const char* key); + yaml operator[](const char* key); /// \overload - inline Parameters operator[](const std::string& key) + inline yaml operator[](const std::string& key) { return operator[](key.c_str()); } /** Read access for maps * \throw std::runtime_error if key does not exist. */ - const Parameters operator[](const char* key) const; + const yaml operator[](const char* key) const; /// \overload - inline const Parameters operator[](const std::string& key) const + inline const yaml operator[](const std::string& key) const { return operator[](key.c_str()); } - /** Read access for maps, with default value if key does not exist. */ + /** Scalar read access for maps, with default value if key does not exist. + */ template const T getOrDefault(const std::string& key, const T& defaultValue) const { - const Parameters* p = internalMeOrValue(); + const yaml* p = dereferenceProxy(); if (p->empty()) return defaultValue; if (!p->isMap()) throw std::logic_error("getOrDefault() is only for map nodes."); - const map_t& m = std::get(p->data_); + const map_t& m = std::get(p->root_.d); auto it = m.find(key); if (m.end() == it) return defaultValue; + it->second.d try { - return Parameters(internal::tag_as_const_proxy_t(), it->second, "") + return yaml(internal::tag_as_const_proxy_t(), it->second, "") .as(); } catch (const std::bad_any_cast& e) @@ -178,16 +199,16 @@ class Parameters throw std::logic_error(mrpt::format( "getOrDefault(): Trying to access key `%s` holding type `%s` " "as the wrong type: `%s`", - key.c_str(), it->second.type().name(), e.what())); + key.c_str(), it->second.d.type().name(), e.what())); } } /** Write into an existing index of a sequence. * \throw std::out_of_range if index is out of range. */ - Parameters operator()(int index); + yaml operator()(int index); /** Read from an existing index of a sequence. * \throw std::out_of_range if index is out of range. */ - const Parameters operator()(int index) const; + const yaml operator()(int index) const; /** Append a new value to a sequence. * \throw std::exception If this is not a sequence */ @@ -199,27 +220,29 @@ class Parameters /// \overload void push_back(const bool v) { internalPushBack(bool(v)); } /// \overload - void push_back(const Parameters& v) { internalPushBack(v); } + void push_back(const yaml& v) { internalPushBack(v); } /** Copies the structure and contents from an existing * YAML Node. Requires mrpt built against yamlcpp. */ void loadFromYAML(const YAML::Node& n); private: - data_t data_; + node_t root_; bool isProxy_ = false; bool isConstProxy_ = false; /** @name Internal proxy * @{ */ private: - explicit Parameters( - internal::tag_as_proxy_t, scalar_t& val, const char* name) - : isProxy_(true), isConstProxy_(false), name_(name), valuenc_(&val) + explicit yaml(internal::tag_as_proxy_t, node_t& val, const char* name) + : isProxy_(true), + isConstProxy_(false), + name_(name), + proxiedNodenc_(&val) { } - explicit Parameters( - internal::tag_as_const_proxy_t, const scalar_t& val, const char* name) + explicit yaml( + internal::tag_as_const_proxy_t, const node_t& val, const char* name) : isProxy_(true), isConstProxy_(true), name_(name), value_(&val) { } @@ -270,7 +293,7 @@ class Parameters { operator=(std::string(v)); } - Parameters& operator=(const Parameters& v); + yaml& operator=(const yaml& v); inline operator bool() const { return as(); } @@ -289,25 +312,26 @@ class Parameters inline operator std::string() const { return as(); } private: + // Proxy members: const char* name_ = nullptr; - const scalar_t* value_ = nullptr; - scalar_t* valuenc_ = nullptr; + const node_t* value_ = nullptr; + node_t* proxiedNodenc_ = nullptr; /** Returns the pointer to the referenced object, if a proxy, or nullptr * otherwise */ - const Parameters* internalValueAsSelf() const; - Parameters* internalValueAsSelf(); + const yaml* dereferenceProxy() const; + yaml* dereferenceProxy(); /** Returns me or the pointer to the referenced object, if a proxy */ - const Parameters* internalMeOrValue() const; - Parameters* internalMeOrValue(); + const yaml* dereferenceProxy() const; + yaml* dereferenceProxy(); template - friend T internal::implAsGetter(const Parameters& p); + friend T internal::implAsGetter(const yaml& p); // Return: true if the last printed char is a newline char static bool internalPrintAsYAML( - const Parameters& p, std::ostream& o, int indent, bool first); + const yaml& p, std::ostream& o, int indent, bool first); template void internalPushBack(const T& v); @@ -331,27 +355,28 @@ class Parameters throw std::logic_error( "Trying to write into a Parameter block. Use " "`p[\"name\"]=value;` instead"); - if (!valuenc_) throw std::logic_error("valuenc_ is nullptr"); - valuenc_->emplace(v); + if (!proxiedNodenc_) + throw std::logic_error("proxiedNodenc_ is nullptr"); + proxiedNodenc_->emplace(v); } /** @} */ }; -/** Prints a scalar, a part of a Parameters tree, or the entire structure, +/** Prints a scalar, a part of a yaml tree, or the entire structure, * in YAML-like format */ -inline std::ostream& operator<<(std::ostream& o, const Parameters& p) +inline std::ostream& operator<<(std::ostream& o, const yaml& p) { p.printAsYAML(o); return o; } -/** Macro to load a variable from a mrpt::containers::Parameters (initials MCP) +/** Macro to load a variable from a mrpt::containers::yaml (initials MCP) * dictionary, throwing an std::invalid_argument exception if the value is not * found (REQuired). * * Usage: * \code - * mrpt::containers::Parameters p; + * mrpt::containers::yaml p; * double K; * * MCP_LOAD_REQ(p, K); @@ -364,12 +389,12 @@ inline std::ostream& operator<<(std::ostream& o, const Parameters& p) #keyName__)); \ keyName__ = paramsVariable__[#keyName__].as() -/** Macro to load a variable from a mrpt::containers::Parameters (initials MCP) +/** Macro to load a variable from a mrpt::containers::yaml (initials MCP) * dictionary, leaving it with its former value if not found (OPTional). * * Usage: * \code - * mrpt::containers::Parameters p; + * mrpt::containers::yaml p; * double K; * * MCP_LOAD_OPT(p, K); @@ -391,12 +416,12 @@ inline std::ostream& operator<<(std::ostream& o, const Parameters& p) MCP_LOAD_OPT(paramsVariable__, keyName__); \ keyName__ = mrpt::DEG2RAD(keyName__) -/** Macro to store a variable into a mrpt::containers::Parameters (initials MCP) +/** Macro to store a variable into a mrpt::containers::yaml (initials MCP) * dictionary, using as "key" the name of the variable. * * Usage: * \code - * mrpt::containers::Parameters p; + * mrpt::containers::yaml p; * double K = ...; * * MCP_SAVE(p, K); @@ -417,7 +442,7 @@ inline std::ostream& operator<<(std::ostream& o, const Parameters& p) namespace mrpt::containers { template -T& Parameters::asRef() +T& yaml::asRef() { if (isConstProxy_) throw std::logic_error("Trying to write into read-only proxy"); @@ -426,27 +451,28 @@ T& Parameters::asRef() "Trying to read from a non-scalar. Use `p[\"name\"].as();` " "instead"); - if (!valuenc_) throw std::logic_error("valuenc_ is nullptr"); + if (!proxiedNodenc_) throw std::logic_error("proxiedNodenc_ is nullptr"); try { - std::any_cast(*valuenc_); + std::any_cast(*proxiedNodenc_); } catch (const std::bad_any_cast&) { - valuenc_->emplace(); + proxiedNodenc_->emplace(); } - return *std::any_cast(valuenc_); + return *std::any_cast(proxiedNodenc_); } template -const T& Parameters::asRef() const +const T& yaml::asRef() const { if (!isProxy_) throw std::logic_error( "Trying to read from a non-scalar. Use `p[\"name\"].as();` " "instead"); const auto& expectedType = typeid(T); - const auto& storedType = isConstProxy_ ? value_->type() : valuenc_->type(); + const auto& storedType = + isConstProxy_ ? value_->type() : proxiedNodenc_->type(); if (storedType != expectedType) THROW_EXCEPTION_FMT( @@ -458,17 +484,17 @@ const T& Parameters::asRef() const if (isConstProxy_) return *std::any_cast(value_); else - return *std::any_cast(valuenc_); + return *std::any_cast(proxiedNodenc_); } template -void Parameters::internalPushBack(const T& v) +void yaml::internalPushBack(const T& v) { - Parameters* p = internalMeOrValue(); + yaml* p = dereferenceProxy(); if (!p->isSequence()) throw std::logic_error( "push_back() only available for sequence nodes."); - sequence_t& seq = std::get(p->data_); + sequence_t& seq = std::get(p->root_.d); seq.emplace_back(v); } @@ -477,12 +503,12 @@ void Parameters::internalPushBack(const T& v) namespace mrpt::containers::internal { template -T implAsGetter(const Parameters& p) +T implAsGetter(const yaml& p) { ASSERT_(p.isProxy_); const auto& expectedType = typeid(T); const auto& storedType = - p.isConstProxy_ ? p.value_->type() : p.valuenc_->type(); + p.isConstProxy_ ? p.value_->type() : p.proxiedNodenc_->type(); if (storedType != expectedType) { @@ -532,7 +558,7 @@ T implAsGetter(const Parameters& p) if (p.isConstProxy_) return *std::any_cast(p.value_); else - return *std::any_cast(p.valuenc_); + return *std::any_cast(p.proxiedNodenc_); } } // namespace mrpt::containers::internal diff --git a/libs/containers/src/Parameters.cpp b/libs/containers/src/yaml.cpp similarity index 51% rename from libs/containers/src/Parameters.cpp rename to libs/containers/src/yaml.cpp index 2940194798..2222088d1c 100644 --- a/libs/containers/src/Parameters.cpp +++ b/libs/containers/src/yaml.cpp @@ -10,7 +10,7 @@ #include "containers-precomp.h" // Precompiled headers // #include -#include +#include #include #if MRPT_HAS_YAMLCPP @@ -19,266 +19,265 @@ using namespace mrpt::containers; -Parameters::Parameters(const Parameters& v) { *this = v; } +yaml::yaml(const yaml& v) { *this = v; } -bool Parameters::isSequence() const +bool yaml::isSequence() const { - auto p = internalMeOrValue(); - return std::holds_alternative(p->data_); + auto p = dereferenceProxy(); + return std::holds_alternative(p->root_); } -Parameters::sequence_t& Parameters::asSequence() +yaml::sequence_t& yaml::asSequence() { if (isProxy_) { - auto p = internalValueAsSelf(); + auto p = dereferenceProxy(); ASSERTMSG_(p, "Cannot call asSequence() on a scalar"); return p->asSequence(); } - return std::get(data_); + return std::get(root_); } -const Parameters::sequence_t& Parameters::asSequence() const +const yaml::sequence_t& yaml::asSequence() const { if (isProxy_) { - auto p = internalValueAsSelf(); + auto p = dereferenceProxy(); ASSERTMSG_(p, "Cannot call asSequence() on a scalar"); return p->asSequence(); } - return std::get(data_); + return std::get(root_); } -bool Parameters::isScalar() const +bool yaml::isScalar() const { - auto p = internalMeOrValue(); + auto p = dereferenceProxy(); return (p->isProxy_ || p->isConstProxy_); } -bool Parameters::isEmptyNode() const +bool yaml::isEmptyNode() const { - auto p = internalMeOrValue(); + auto p = dereferenceProxy(); if (p->isConstProxy_) { - ASSERT_(p->value_); - return !p->value_->has_value(); + ASSERT_(p->proxiedNode_); + return !p->proxiedNode_->has_value(); } if (p->isProxy_) { - ASSERT_(p->valuenc_); - return !p->valuenc_->has_value(); + ASSERT_(p->proxiedNodenc_); + return !p->proxiedNodenc_->has_value(); } return false; } -bool Parameters::isMap() const +bool yaml::isMap() const { - auto p = internalMeOrValue(); - return std::holds_alternative(p->data_); + auto p = dereferenceProxy(); + return std::holds_alternative(p->root_); } -Parameters::map_t& Parameters::asMap() +yaml::map_t& yaml::asMap() { if (isProxy_) { - auto p = internalValueAsSelf(); + auto p = dereferenceProxy(); ASSERTMSG_(p, "Cannot call asMap() on a scalar"); return p->asMap(); } - return std::get(data_); + return std::get(root_); } -const Parameters::map_t& Parameters::asMap() const +const yaml::map_t& yaml::asMap() const { if (isProxy_) { - auto p = internalValueAsSelf(); + auto p = dereferenceProxy(); ASSERTMSG_(p, "Cannot call asMap() on a scalar"); return p->asMap(); } - return std::get(data_); + return std::get(root_); } -bool Parameters::has(const std::string& key) const +bool yaml::has(const std::string& key) const { if (isProxy_) { - auto p = internalValueAsSelf(); + auto p = dereferenceProxy(); ASSERTMSG_(p, "Cannot call has() on a scalar"); return p->has(key); } - if (!std::holds_alternative(data_)) + if (!std::holds_alternative(root_)) THROW_EXCEPTION("has() not applicable to non-map nodes."); - const map_t& m = std::get(data_); + const map_t& m = std::get(root_); return m.end() != m.find(key); } -const std::type_info& Parameters::typeOfChild(const std::string& name) const +const std::type_info& yaml::typeOfChild(const std::string& name) const { if (isProxy_) { - auto p = internalValueAsSelf(); + auto p = dereferenceProxy(); ASSERTMSG_(p, "Cannot call typeOf() on a scalar."); return p->typeOfChild(name); } - if (!std::holds_alternative(data_)) + if (!std::holds_alternative(root_)) THROW_EXCEPTION("typeOfChild() not applicable to non-map nodes."); - const map_t& m = std::get(data_); + const map_t& m = std::get(root_); auto it = m.find(name); if (m.end() == it) return typeid(void); return it->second.type(); } -const std::type_info& Parameters::type() const +const std::type_info& yaml::type() const { - auto p = internalMeOrValue(); + auto p = dereferenceProxy(); if (p->isConstProxy_) { - ASSERT_(p->value_); - return p->value_->type(); + ASSERT_(p->proxiedNode_); + return p->proxiedNode_->type(); } if (p->isProxy_) { - ASSERT_(p->valuenc_); - return p->valuenc_->type(); + ASSERT_(p->proxiedNodenc_); + return p->proxiedNodenc_->type(); } THROW_EXCEPTION("type() only applicable to scalar nodes"); } -const Parameters* Parameters::internalValueAsSelf() const +const yaml* yaml::dereferenceProxy() const { - const Parameters* p = nullptr; - if (valuenc_ && valuenc_->type() == typeid(Parameters)) - p = std::any_cast(valuenc_); - if (value_ && value_->type() == typeid(Parameters)) - p = std::any_cast(value_); + const yaml* p = nullptr; + if (proxiedNodenc_ && proxiedNodenc_->type() == typeid(yaml)) + p = std::any_cast(proxiedNodenc_); + if (proxiedNode_ && proxiedNode_->type() == typeid(yaml)) + p = std::any_cast(proxiedNode_); return p; } -Parameters* Parameters::internalValueAsSelf() +yaml* yaml::dereferenceProxy() { - Parameters* p = nullptr; - if (valuenc_ && valuenc_->type() == typeid(Parameters)) - p = std::any_cast(valuenc_); + yaml* p = nullptr; + if (proxiedNodenc_ && proxiedNodenc_->type() == typeid(yaml)) + p = std::any_cast(proxiedNodenc_); return p; } -const Parameters* Parameters::internalMeOrValue() const +const yaml* yaml::dereferenceProxy() const { - const Parameters* p = internalValueAsSelf(); + const yaml* p = dereferenceProxy(); return p != nullptr ? p : this; } -Parameters* Parameters::internalMeOrValue() +yaml* yaml::dereferenceProxy() { - Parameters* p = internalValueAsSelf(); + yaml* p = dereferenceProxy(); return p != nullptr ? p : this; } -bool Parameters::empty() const +bool yaml::empty() const { if (isProxy_) { - auto p = internalValueAsSelf(); + auto p = dereferenceProxy(); ASSERTMSG_(p, "Cannot call empty() on a scalar"); return p->empty(); } - if (std::holds_alternative(data_)) - return std::get(data_).empty(); - if (std::holds_alternative(data_)) - return std::get(data_).empty(); + if (std::holds_alternative(root_)) + return std::get(root_).empty(); + if (std::holds_alternative(root_)) + return std::get(root_).empty(); return true; } -void Parameters::clear() +void yaml::clear() { if (isProxy_) { - auto p = internalValueAsSelf(); + auto p = dereferenceProxy(); ASSERTMSG_(p, "Cannot call clear() on a scalar"); p->clear(); } - if (std::holds_alternative(data_)) + if (std::holds_alternative(root_)) { - std::get(data_).clear(); + std::get(root_).clear(); return; } - if (std::holds_alternative(data_)) + if (std::holds_alternative(root_)) { - std::get(data_).clear(); + std::get(root_).clear(); return; } } -void Parameters::operator=(bool v) { implOpAssign(v); } +void yaml::operator=(bool v) { implOpAssign(v); } -void Parameters::operator=(double v) { implOpAssign(v); } -void Parameters::operator=(float v) { implOpAssign(v); } +void yaml::operator=(double v) { implOpAssign(v); } +void yaml::operator=(float v) { implOpAssign(v); } -void Parameters::operator=(int8_t v) { implOpAssign(v); } -void Parameters::operator=(uint8_t v) { implOpAssign(v); } +void yaml::operator=(int8_t v) { implOpAssign(v); } +void yaml::operator=(uint8_t v) { implOpAssign(v); } -void Parameters::operator=(int16_t v) { implOpAssign(v); } -void Parameters::operator=(uint16_t v) { implOpAssign(v); } +void yaml::operator=(int16_t v) { implOpAssign(v); } +void yaml::operator=(uint16_t v) { implOpAssign(v); } -void Parameters::operator=(int32_t v) { implOpAssign(v); } -void Parameters::operator=(uint32_t v) { implOpAssign(v); } +void yaml::operator=(int32_t v) { implOpAssign(v); } +void yaml::operator=(uint32_t v) { implOpAssign(v); } -void Parameters::operator=(int64_t v) { implOpAssign(v); } -void Parameters::operator=(uint64_t v) { implOpAssign(v); } +void yaml::operator=(int64_t v) { implOpAssign(v); } +void yaml::operator=(uint64_t v) { implOpAssign(v); } -void Parameters::operator=(const std::string& v) { implOpAssign(v); } -Parameters& Parameters::operator=(const Parameters& v) +void yaml::operator=(const std::string& v) { implOpAssign(v); } +yaml& yaml::operator=(const yaml& v) { if (isConstProxy_) THROW_EXCEPTION("Trying to write into read-only proxy"); if (isProxy_) { - if (!valuenc_) THROW_EXCEPTION("valuenc_ is nullptr"); - valuenc_->emplace(v); - return *std::any_cast(valuenc_); + if (!proxiedNodenc_) THROW_EXCEPTION("proxiedNodenc_ is nullptr"); + proxiedNodenc_->emplace(v); + return *std::any_cast(proxiedNodenc_); } else { - data_ = v.internalMeOrValue()->data_; + root_ = v.dereferenceProxy()->root_; isProxy_ = false; isConstProxy_ = false; return *this; } } -Parameters Parameters::operator[](const char* s) +yaml yaml::operator[](const char* s) { ASSERT_(s != nullptr); - Parameters* p = internalMeOrValue(); + yaml* p = dereferenceProxy(); // Init as map on first use: - if (std::holds_alternative(p->data_)) - p->data_.emplace(); + if (std::holds_alternative(p->root_)) + p->root_.emplace(); if (!p->isMap()) THROW_EXCEPTION("write operator[] not applicable to non-map nodes."); - return Parameters( - internal::tag_as_proxy_t(), std::get(p->data_)[s], s); + return yaml(internal::tag_as_proxy_t(), std::get(p->root_)[s], s); } -const Parameters Parameters::operator[](const char* s) const +const yaml yaml::operator[](const char* s) const { ASSERT_(s != nullptr); - const Parameters* p = internalMeOrValue(); + const yaml* p = dereferenceProxy(); if (p->empty()) THROW_EXCEPTION("read operator[] not applicable to empty nodes."); if (!p->isMap()) THROW_EXCEPTION("read operator[] only available for map nodes."); - const map_t& m = std::get(p->data_); + const map_t& m = std::get(p->root_); auto it = m.find(s); if (m.end() == it) THROW_EXCEPTION_FMT("Access non-existing map key `%s`", s); - return Parameters(internal::tag_as_const_proxy_t(), it->second, s); + return yaml(internal::tag_as_const_proxy_t(), it->second, s); } -Parameters Parameters::operator()(int index) +yaml yaml::operator()(int index) { - Parameters* p = internalMeOrValue(); + yaml* p = dereferenceProxy(); if (p->empty()) THROW_EXCEPTION( "write operator() not applicable to empty nodes or sequences."); @@ -286,65 +285,65 @@ Parameters Parameters::operator()(int index) if (!p->isSequence()) THROW_EXCEPTION("write operator() only available for sequence nodes."); - sequence_t& seq = std::get(p->data_); + sequence_t& seq = std::get(p->root_); if (index < 0 || index >= static_cast(seq.size())) THROW_TYPED_EXCEPTION( - "Parameters::operator() out of range", std::out_of_range); + "yaml::operator() out of range", std::out_of_range); - return Parameters(internal::tag_as_proxy_t(), seq.at(index), ""); + return yaml(internal::tag_as_proxy_t(), seq.at(index), ""); } -const Parameters Parameters::operator()(int index) const +const yaml yaml::operator()(int index) const { - const Parameters* p = internalMeOrValue(); + const yaml* p = dereferenceProxy(); if (p->empty()) THROW_EXCEPTION("read operator[] not applicable to empty nodes."); if (!p->isSequence()) THROW_EXCEPTION("read operator() only available for sequence nodes."); - const sequence_t& seq = std::get(p->data_); + const sequence_t& seq = std::get(p->root_); if (index < 0 || index >= static_cast(seq.size())) THROW_TYPED_EXCEPTION( - "Parameters::operator() out of range", std::out_of_range); + "yaml::operator() out of range", std::out_of_range); - return Parameters(internal::tag_as_const_proxy_t(), seq.at(index), ""); + return yaml(internal::tag_as_const_proxy_t(), seq.at(index), ""); } -void Parameters::printAsYAML() const { printAsYAML(std::cout); } +void yaml::printAsYAML() const { printAsYAML(std::cout); } -void Parameters::printAsYAML(std::ostream& o) const +void yaml::printAsYAML(std::ostream& o) const { - const Parameters* p = internalMeOrValue(); + const yaml* p = dereferenceProxy(); internalPrintAsYAML(*p, o, 0, true); } -bool Parameters::internalPrintAsYAML( - const Parameters& p, std::ostream& o, int indent, bool first) +bool yaml::internalPrintAsYAML( + const yaml& p, std::ostream& o, int indent, bool first) { - if (p.isProxy_ && p.valuenc_) - return internalPrintAsYAML(*p.valuenc_, o, indent, first); - if (p.isConstProxy_ && p.value_) - return internalPrintAsYAML(*p.value_, o, indent, first); - - if (std::holds_alternative(p.data_)) - return internalPrintAsYAML(std::get(p.data_), o, indent, first); - if (std::holds_alternative(p.data_)) + if (p.isProxy_ && p.proxiedNodenc_) + return internalPrintAsYAML(*p.proxiedNodenc_, o, indent, first); + if (p.isConstProxy_ && p.proxiedNode_) + return internalPrintAsYAML(*p.proxiedNode_, o, indent, first); + + if (std::holds_alternative(p.root_)) + return internalPrintAsYAML(std::get(p.root_), o, indent, first); + if (std::holds_alternative(p.root_)) return internalPrintAsYAML( - std::get(p.data_), o, indent, first); - if (std::holds_alternative(p.data_)) + std::get(p.root_), o, indent, first); + if (std::holds_alternative(p.root_)) return internalPrintAsYAML(std::monostate(), o, indent, first); THROW_EXCEPTION("Trying to print a node of unknown type (!)"); } -bool Parameters::internalPrintAsYAML( +bool yaml::internalPrintAsYAML( const std::monostate&, std::ostream& o, [[maybe_unused]] int indent, [[maybe_unused]] bool first) { o << "~"; return false; } -bool Parameters::internalPrintAsYAML( - const Parameters::sequence_t& v, std::ostream& o, int indent, bool first) +bool yaml::internalPrintAsYAML( + const yaml::sequence_t& v, std::ostream& o, int indent, bool first) { if (!first) { @@ -359,8 +358,8 @@ bool Parameters::internalPrintAsYAML( } return true; } -bool Parameters::internalPrintAsYAML( - const Parameters::map_t& m, std::ostream& o, int indent, bool first) +bool yaml::internalPrintAsYAML( + const yaml::map_t& m, std::ostream& o, int indent, bool first) { if (!first) { @@ -377,8 +376,8 @@ bool Parameters::internalPrintAsYAML( return true; } -bool Parameters::internalPrintAsYAML( - const Parameters::scalar_t& v, std::ostream& o, int indent, bool first) +bool yaml::internalPrintAsYAML( + const yaml::scalar_t& v, std::ostream& o, int indent, bool first) { if (!v.has_value()) { @@ -386,9 +385,8 @@ bool Parameters::internalPrintAsYAML( return false; } - if (v.type() == typeid(Parameters)) - return internalPrintAsYAML( - std::any_cast(v), o, indent, first); + if (v.type() == typeid(yaml)) + return internalPrintAsYAML(std::any_cast(v), o, indent, first); else if (v.type() == typeid(bool)) o << (std::any_cast(v) ? "true" : "false"); else if (v.type() == typeid(uint64_t)) @@ -426,30 +424,30 @@ bool Parameters::internalPrintAsYAML( return false; } -Parameters Parameters::FromYAMLText(const std::string& yamlTextBlock) +yaml yaml::FromYAMLText(const std::string& yamlTextBlock) { #if MRPT_HAS_YAMLCPP YAML::Node n = YAML::Load(yamlTextBlock); - return Parameters::FromYAML(n); + return yaml::FromYAML(n); #else THROW_EXCEPTION("MRPT was built without yaml-cpp"); #endif } -Parameters Parameters::FromYAML(const YAML::Node& n) +yaml yaml::FromYAML(const YAML::Node& n) { #if MRPT_HAS_YAMLCPP const auto invalidDbl = std::numeric_limits::max(); if (n.IsSequence()) { - auto ret = Parameters::Sequence(); + auto ret = yaml::Sequence(); for (const auto& e : n) { if (e.IsNull()) { - sequence_t& seq = std::get(ret.data_); + sequence_t& seq = std::get(ret.root_); seq.emplace_back(); } else if (e.IsScalar()) @@ -462,14 +460,14 @@ Parameters Parameters::FromYAML(const YAML::Node& n) else { // Recursive: - ret.push_back(Parameters::FromYAML(e)); + ret.push_back(yaml::FromYAML(e)); } } return ret; } else if (n.IsMap()) { - auto ret = Parameters::Map(); + auto ret = yaml::Map(); for (const auto& kv : n) { @@ -478,7 +476,7 @@ Parameters Parameters::FromYAML(const YAML::Node& n) if (val.IsNull()) { - map_t& m = std::get(ret.data_); + map_t& m = std::get(ret.root_); m[key]; } else if (val.IsScalar()) @@ -491,7 +489,7 @@ Parameters Parameters::FromYAML(const YAML::Node& n) else { // Recursive: - ret[key] = Parameters::FromYAML(val); + ret[key] = yaml::FromYAML(val); } } return ret; @@ -506,7 +504,4 @@ Parameters Parameters::FromYAML(const YAML::Node& n) #endif } -void Parameters::loadFromYAML(const YAML::Node& n) -{ - *this = Parameters::FromYAML(n); -} +void yaml::loadFromYAML(const YAML::Node& n) { *this = yaml::FromYAML(n); } diff --git a/libs/containers/src/Parameters_unittest.cpp b/libs/containers/src/yaml_unittest.cpp similarity index 83% rename from libs/containers/src/Parameters_unittest.cpp rename to libs/containers/src/yaml_unittest.cpp index f27cce6a0c..a0eb76a032 100644 --- a/libs/containers/src/Parameters_unittest.cpp +++ b/libs/containers/src/yaml_unittest.cpp @@ -16,14 +16,14 @@ TEST(Parameters, emptyCtor) { { - mrpt::containers::Parameters p; + mrpt::containers::yaml p; EXPECT_TRUE(p.empty()); } } TEST(Parameters, assignments) { - mrpt::containers::Parameters p; + mrpt::containers::yaml p; p["K"] = 2.0; p["N"] = uint64_t(10); p["name"] = "Pepico"; @@ -55,7 +55,7 @@ TEST(Parameters, assignments) EXPECT_EQ(p.typeOfChild("enabled"), typeid(bool)); { - mrpt::containers::Parameters p2; + mrpt::containers::yaml p2; EXPECT_TRUE(p2.empty()); p2 = p; @@ -77,20 +77,20 @@ TEST(Parameters, assignments) TEST(Parameters, initializers) { { - auto p = mrpt::containers::Parameters({"K", 1.0}); + auto p = mrpt::containers::yaml({"K", 1.0}); EXPECT_TRUE(p.isSequence()); } { - auto p = mrpt::containers::Parameters({{"K", 1.0}}); + auto p = mrpt::containers::yaml({{"K", 1.0}}); EXPECT_TRUE(p.isMap()); } { - auto p = mrpt::containers::Parameters({"K", 1.0, 10.0}); + auto p = mrpt::containers::yaml({"K", 1.0, 10.0}); EXPECT_TRUE(p.isSequence()); } { - auto p = mrpt::containers::Parameters( + auto p = mrpt::containers::yaml( {{"K", 1.0}, {"T", 10.0}, {"Name", "bar"}}); EXPECT_TRUE(p.isMap()); } @@ -98,7 +98,7 @@ TEST(Parameters, initializers) TEST(Parameters, initializerMap) { - const auto p = mrpt::containers::Parameters( + const auto p = mrpt::containers::yaml( {{"K", 2.0}, {"book", std::string("silmarillion")}}); EXPECT_FALSE(p.isSequence()); @@ -124,7 +124,7 @@ TEST(Parameters, initializerMap) TEST(Parameters, initializerSequence) { - const auto seq1 = mrpt::containers::Parameters({1.0, 2.0, 3.0}); + const auto seq1 = mrpt::containers::yaml({1.0, 2.0, 3.0}); EXPECT_FALSE(seq1.empty()); EXPECT_TRUE(seq1.isSequence()); @@ -141,7 +141,7 @@ TEST(Parameters, initializerSequence) EXPECT_THROW(seq1(3), std::out_of_range); EXPECT_THROW(seq1(-1), std::out_of_range); - auto seq2 = mrpt::containers::Parameters({1.0, 2.0, 3.0}); + auto seq2 = mrpt::containers::yaml({1.0, 2.0, 3.0}); EXPECT_EQ(seq2(1).as(), 2.0); seq2(1) = 42.0; @@ -150,7 +150,7 @@ TEST(Parameters, initializerSequence) seq2(1) = "foo"; EXPECT_EQ(seq2(1).as(), std::string("foo")); - seq2(1) = mrpt::containers::Parameters({{"K", 1.0}}); + seq2(1) = mrpt::containers::yaml({{"K", 1.0}}); EXPECT_EQ(seq2(1)["K"].as(), 1.0); seq2.push_back(std::string("foo2")); @@ -162,8 +162,8 @@ TEST(Parameters, initializerSequence) TEST(Parameters, nested) { - auto p = mrpt::containers::Parameters({{"K", 2.0}}); - p["PID"] = mrpt::containers::Parameters({{"Kp", 10.0}, {"Ti", 10.0}}); + auto p = mrpt::containers::yaml({{"K", 2.0}}); + p["PID"] = mrpt::containers::yaml({{"Kp", 10.0}, {"Ti", 10.0}}); EXPECT_FALSE(p.empty()); EXPECT_FALSE(p["PID"].empty()); @@ -188,9 +188,9 @@ TEST(Parameters, nested) TEST(Parameters, nested2) { - mrpt::containers::Parameters p; + mrpt::containers::yaml p; p["N"] = 10; - auto& pid = p["PID"] = mrpt::containers::Parameters(); + auto& pid = p["PID"] = mrpt::containers::yaml(); pid["Kp"] = 0.5; p["PID"]["Ti"] = 2.0; p["PID"]["N"] = 1000; @@ -202,20 +202,20 @@ TEST(Parameters, nested2) EXPECT_EQ(p["PID"]["name"].as(), std::string("foo")); } -const auto testMap = mrpt::containers::Parameters( +const auto testMap = mrpt::containers::yaml( {{"K", 2.0}, {"book", "silmarillion"}, {"mySequence", - mrpt::containers::Parameters::Sequence( + mrpt::containers::yaml::Sequence( {1.0, 2.0, - mrpt::containers::Parameters::Map({{"P", 1.0}, {"Q", 2.0}})})}, - {"myEmptyVal", mrpt::containers::Parameters()}, + mrpt::containers::yaml::Map({{"P", 1.0}, {"Q", 2.0}})})}, + {"myEmptyVal", mrpt::containers::yaml()}, {"myDict", - mrpt::containers::Parameters({{"A", 1.0}, {"B", 2.0}, {"C", 3.0}})}}); + mrpt::containers::yaml({{"A", 1.0}, {"B", 2.0}, {"C", 3.0}})}}); TEST(Parameters, printYAML) { - // testMap.printAsYAML(); + testMap.printAsYAML(); std::stringstream ss; testMap.printAsYAML(ss); const auto s = ss.str(); @@ -227,8 +227,11 @@ TEST(Parameters, iterate) std::set foundKeys; for (const auto& kv : testMap.asMap()) { - // std::cout << kv.first << ":" << kv.second.index() << "\n"; - foundKeys.insert(kv.first); + std::cout << kv.first << ":" << kv.second.type().name() << "\n"; + + if (std::any_cast(kv.second)) + + foundKeys.insert(kv.first); } EXPECT_EQ(foundKeys.size(), 5U); @@ -245,12 +248,12 @@ TEST(Parameters, iterate) TEST(Parameters, macros) { - mrpt::containers::Parameters p; + mrpt::containers::yaml p; p["K"] = 2.0; p["Ang"] = 90.0; p["N"].asRef() = 10; p["name"] = "Pepico"; - p["PID"] = mrpt::containers::Parameters({{"Kp", 1.0}, {"Td", 0.8}}); + p["PID"] = mrpt::containers::yaml({{"Kp", 1.0}, {"Td", 0.8}}); double K, Td, Foo = 9.0, Bar, Ang, Ang2 = M_PI; std::string name; @@ -275,7 +278,7 @@ TEST(Parameters, macros) EXPECT_THROW(MCP_LOAD_REQ(p, Bar), std::exception); } -void foo(mrpt::containers::Parameters& p) +void foo(mrpt::containers::yaml& p) { p["K"] = 2.0; p["N"] = 2; @@ -283,9 +286,9 @@ void foo(mrpt::containers::Parameters& p) TEST(Parameters, assignmentsInCallee) { - mrpt::containers::Parameters p; + mrpt::containers::yaml p; - auto& pp = p["params"] = mrpt::containers::Parameters::Map(); + auto& pp = p["params"] = mrpt::containers::yaml::Map(); foo(pp); EXPECT_FALSE(p.empty()); @@ -312,13 +315,17 @@ const auto sampleYamlBlock = std::string(R"xxx( K: 10.0 P: -5.0 Q: ~ + nestedMap: + a: 1 + b: 2 + c: 3 )xxx"); // clang-format on #if MRPT_HAS_YAMLCPP TEST(Parameters, fromYAML) { - auto p = mrpt::containers::Parameters::FromYAMLText(sampleYamlBlock); + auto p = mrpt::containers::yaml::FromYAMLText(sampleYamlBlock); EXPECT_EQ(p["mySeq"](0).as(), "first"); EXPECT_EQ(p["myMap"]["P"].as(), -5.0); EXPECT_EQ(p["myMap"]["K"].as(), 10.0); diff --git a/libs/system/include/mrpt/system/TParameters.h b/libs/system/include/mrpt/system/TParameters.h index 870b99b1ea..2866369c9e 100644 --- a/libs/system/include/mrpt/system/TParameters.h +++ b/libs/system/include/mrpt/system/TParameters.h @@ -49,7 +49,7 @@ namespace mrpt::system * "10.0". * \ingroup mrpt_system_grp * \sa the example in MRPT/samples/params-by-name - * \deprecated (Since mrpt 2.0.5) Prefer mrpt::containers::Parameters. + * \deprecated (Since mrpt 2.0.5) Prefer mrpt::containers::yaml. */ template struct TParameters @@ -60,14 +60,14 @@ struct TParameters using const_iterator = typename BASE::const_iterator; /** Default constructor (initializes empty) */ - [[deprecated("Prefer mrpt::containers::Parameters [Since mrpt 2.0.5]")]] // + [[deprecated("Prefer mrpt::containers::yaml [Since mrpt 2.0.5]")]] // TParameters() { } /** Constructor with a list of initial values (see the description and use * example in mrpt::system::TParameters) */ - [[deprecated("Prefer mrpt::containers::Parameters [Since mrpt 2.0.5]")]] // + [[deprecated("Prefer mrpt::containers::yaml [Since mrpt 2.0.5]")]] // TParameters(std::initializer_list init) : base(init) { diff --git a/samples/CMakeLists.txt b/samples/CMakeLists.txt index 66c4c3f0cf..3a5fc8426e 100644 --- a/samples/CMakeLists.txt +++ b/samples/CMakeLists.txt @@ -71,7 +71,7 @@ if(BUILD_EXAMPLES) # === Depending on: containers, systems === set(LIST_EXAMPLES_IN_THIS_DIR - containers_parameters_example + containers_yaml_example ) set(CMAKE_EXAMPLE_DEPS mrpt::containers mrpt::system) GENERATE_CMAKE_FILES_SAMPLES_DIRECTORY() diff --git a/samples/containers_parameters_example/CMakeLists.txt b/samples/containers_yaml_example/CMakeLists.txt similarity index 94% rename from samples/containers_parameters_example/CMakeLists.txt rename to samples/containers_yaml_example/CMakeLists.txt index 05b476533c..125a440ccf 100644 --- a/samples/containers_parameters_example/CMakeLists.txt +++ b/samples/containers_yaml_example/CMakeLists.txt @@ -1,10 +1,10 @@ #----------------------------------------------------------------------------------------------- -# CMake file for the MRPT example: /containers_parameters_example +# CMake file for the MRPT example: /containers_yaml_example # # Run with "ccmake ." at the root directory, or use it as a template for # starting your own programs #----------------------------------------------------------------------------------------------- -set(sampleName containers_parameters_example) +set(sampleName containers_yaml_example) project(EXAMPLE_${sampleName}) cmake_minimum_required(VERSION 3.1) diff --git a/samples/containers_parameters_example/test.cpp b/samples/containers_yaml_example/test.cpp similarity index 100% rename from samples/containers_parameters_example/test.cpp rename to samples/containers_yaml_example/test.cpp