From 988ef8a651e07b7e2d3ba698990bf53c4bfa3912 Mon Sep 17 00:00:00 2001 From: "Marco A. Gutierrez" Date: Thu, 15 Sep 2022 08:14:48 +0000 Subject: [PATCH 1/4] updating Element calls to use Errors Signed-off-by: Marco A. Gutierrez --- include/sdf/Element.hh | 249 +++++++++++++++++++++++++++++++++++++++-- src/Element.cc | 240 +++++++++++++++++++++++++++++++-------- 2 files changed, 435 insertions(+), 54 deletions(-) diff --git a/include/sdf/Element.hh b/include/sdf/Element.hh index 1afc35799..36b704c43 100644 --- a/include/sdf/Element.hh +++ b/include/sdf/Element.hh @@ -161,12 +161,26 @@ namespace sdf /// \param[in] _prefix String value to prefix to the output. public: void PrintDescription(const std::string &_prefix) const; + /// \brief Output Element's description to stdout. + /// \param[in] _prefix String value to prefix to the output. + /// \param[out] _errors Vector of errors. + public: void PrintDescription(const std::string &_prefix, + sdf::Errors &_errors) const; + /// \brief Output Element's values to stdout. /// \param[in] _prefix String value to prefix to the output. /// \param[in] _config Configuration for printing the values. public: void PrintValues(std::string _prefix, const PrintConfig &_config = PrintConfig()) const; + /// \brief Output Element's values to stdout. + /// \param[out] _errors Vector of errors. + /// \param[in] _prefix String value to prefix to the output. + /// \param[in] _config Configuration for printing the values. + public: void PrintValues(sdf::Errors &_errors, + std::string _prefix, + const PrintConfig &_config = PrintConfig()) const; + /// \brief Output Element's values to stdout. /// \param[in] _prefix String value to prefix to the output. /// \param[in] _includeDefaultElements flag to print default elements. @@ -177,6 +191,18 @@ namespace sdf bool _includeDefaultAttributes, const PrintConfig &_config = PrintConfig()) const; + /// \brief Output Element's values to stdout. + /// \param[out] _errors Vector of errors. + /// \param[in] _prefix String value to prefix to the output. + /// \param[in] _includeDefaultElements flag to print default elements. + /// \param[in] _includeDefaultAttributes flag to print default attributes. + /// \param[in] _config Configuration for printing the values. + public: void PrintValues(sdf::Errors &_errors, + const std::string &_prefix, + bool _includeDefaultElements, + bool _includeDefaultAttributes, + const PrintConfig &_config = PrintConfig()) const; + /// \brief Helper function for SDF::PrintDoc /// /// This generates the SDF html documentation. @@ -194,24 +220,60 @@ namespace sdf public: void PrintDocRightPane(std::string &_html, int _spacing, int &_index) const; + /// \brief Helper function for SDF::PrintDoc + /// + /// This generates the SDF html documentation. + /// \param[out] _html Accumulated HTML for output. + /// \param[in] _spacing Amount of spacing for this element. + /// \param[out] _errors Vector of errors. + public: void PrintDocRightPane(std::string &_html, int _spacing, + int &_index, sdf::Errors &_errors) const; + + /// \brief Convert the element values to a string representation. + /// \param[in] _prefix String value to prefix to the output. + /// \param[in] _config Configuration for printing the values. + /// \return The string representation. + public: std::string ToString( + const std::string &_prefix, + const PrintConfig &_config = PrintConfig()) const; + /// \brief Convert the element values to a string representation. + /// \param[out] _errors Vector of errors. /// \param[in] _prefix String value to prefix to the output. /// \param[in] _config Configuration for printing the values. /// \return The string representation. + public: std::string ToString( + sdf::Errors &_errors, + const std::string &_prefix, + const PrintConfig &_config = PrintConfig()) const; + + /// \brief Convert the element values to a string representation. + /// Current behavior of ToString(const std::string &_prefix) can be + /// achieved by calling this function with _includeDefaultElements=true + /// and _includeDefaultAttributes=false + /// \param[in] _prefix String value to prefix to the output. + /// \param[in] _includeDefaultElements flag to include default elements. + /// \param[in] _includeDefaultAttributes flag to include default attributes. + /// \param[in] _config Configuration for converting to string. + /// \return The string representation. public: std::string ToString( const std::string &_prefix, + bool _includeDefaultElements, + bool _includeDefaultAttributes, const PrintConfig &_config = PrintConfig()) const; /// \brief Convert the element values to a string representation. /// Current behavior of ToString(const std::string &_prefix) can be /// achieved by calling this function with _includeDefaultElements=true /// and _includeDefaultAttributes=false + /// \param[out] _errors Vector of errors. /// \param[in] _prefix String value to prefix to the output. /// \param[in] _includeDefaultElements flag to include default elements. /// \param[in] _includeDefaultAttributes flag to include default attributes. /// \param[in] _config Configuration for converting to string. /// \return The string representation. public: std::string ToString( + sdf::Errors &_errors, const std::string &_prefix, bool _includeDefaultElements, bool _includeDefaultAttributes, @@ -371,6 +433,17 @@ namespace sdf public: std::any GetAny(sdf::Errors &_errors, const std::string &_key = "") const; + /// \brief Get the value of a key. This function assumes the _key + /// exists. + /// \param[out] _errors Vector of errors. + /// \param[in] _key the name of a child attribute or element. + /// \return The value of the _key. + /// \sa std::pair Get(const std::string &_key, + /// const T &_defaultValue) + public: template + T Get(sdf::Errors &_errors, + const std::string &_key = "") const; + /// \brief Get the value of a key. This function assumes the _key /// exists. /// \param[in] _key the name of a child attribute or element. @@ -381,6 +454,17 @@ namespace sdf T Get(const std::string &_key = "") const; /// \brief Get the value of a key. + /// \param[out] _errors Vector of errors. + /// \param[in] _key the name of a child attribute or element. + /// \param[in] _defaultValue a default value to use if _key is not + /// found. + /// \return A pair where the first element is the value of _key, and the + /// second element is true when the _key was found and false otherwise. + public: template + std::pair Get(sdf::Errors &_errors, + const std::string &_key, + const T &_defaultValue) const; + /// \brief Get the value of a key. /// \param[in] _key the name of a child attribute or element. /// \param[in] _defaultValue a default value to use if _key is not /// found. @@ -401,12 +485,32 @@ namespace sdf T &_param, const T &_defaultValue) const; + /// \brief Get the value of a key. + /// \param[out] _errors Vector of errors. + /// \param[in] _key the name of a child attribute or element. + /// \param[out] _param the parameter output + /// \param[in] _defaultValue a default value to use if _key is not + /// found. + /// \return True when the _key was found and false otherwise. + public: template + bool Get(sdf::Errors &_errors, + const std::string &_key, + T &_param, + const T &_defaultValue) const; + /// \brief Set the value of this element. /// \param[in] _value the value to set. /// \return True if the value was successfully set, false otherwise. public: template bool Set(const T &_value); + /// \brief Set the value of this element. + /// \param[in] _value the value to set. + /// \param[out] _errors Vector of errors. + /// \return True if the value was successfully set, false otherwise. + public: template + bool Set(const T &_value, sdf::Errors &_errors); + /// \brief Return true if the named element exists. /// \param[in] _name the name of the element to look for. /// \return True if the named element was found, false otherwise. @@ -443,9 +547,35 @@ namespace sdf /// names. Also return true if no elements of the specified type are found. public: bool HasUniqueChildNames(const std::string &_type = "") const; + /// \brief Checks whether any child elements of the specified element type + /// have identical name attribute values and returns false if so. + /// \param[out] _errors Vector of errors. + /// \param[in] _type The type of Element to check. If empty, check names + /// of all child elements. + /// \return True if all child elements with name attributes of the + /// specified type have unique names, return false if there are duplicated + /// names. Also return true if no elements of the specified type are found. + public: bool HasUniqueChildNames(sdf::Errors &_errors, + const std::string &_type = "") const; + + /// \brief Checks whether any child elements of the specified element type, + /// except those listed in \p _ignoreElements, have identical name attribute + /// values and returns false if so. + /// \param[in] _type The type of Element to check. If empty, check names + /// of all child elements. + /// \param[in] _ignoreElements A list of child element types to ignore when + /// checking for uniqueness. + /// \return True if all child elements with name attributes of the + /// specified type have unique names, return false if there are duplicated + /// names. Also return true if no elements of the specified type are found. + public: bool HasUniqueChildNames( + const std::string &_type, + const std::vector &_ignoreElements) const; + /// \brief Checks whether any child elements of the specified element type, /// except those listed in \p _ignoreElements, have identical name attribute /// values and returns false if so. + /// \param[out] _errors Vector of errors. /// \param[in] _type The type of Element to check. If empty, check names /// of all child elements. /// \param[in] _ignoreElements A list of child element types to ignore when @@ -454,6 +584,7 @@ namespace sdf /// specified type have unique names, return false if there are duplicated /// names. Also return true if no elements of the specified type are found. public: bool HasUniqueChildNames( + sdf::Errors &_errors, const std::string &_type, const std::vector &_ignoreElements) const; @@ -467,6 +598,18 @@ namespace sdf public: std::map CountNamedElements(const std::string &_type = "") const; + /// \brief Count the number of child elements of the specified element type + /// that have the same name attribute value. + /// \param[out] _errors Vector of errors. + /// \param[in] _type The type of Element to check. If empty, count names + /// of all child elements. + /// \return Map from Element names to a count of how many times the name + /// occurs. The count should never be 0. If all 2nd values are 1, then + /// there are exclusively unique names. + public: std::map + CountNamedElements(sdf::Errors &_errors, + const std::string &_type = "") const; + /// \brief Count the number of child elements of the specified element type /// that have the same name attribute value with the exception of elements /// listed in \p _ignoreElements. @@ -481,6 +624,22 @@ namespace sdf const std::string &_type, const std::vector &_ignoreElements) const; + /// \brief Count the number of child elements of the specified element type + /// that have the same name attribute value with the exception of elements + /// listed in \p _ignoreElements. + /// \param[out] _errors Vector of errors. + /// \param[in] _type The type of Element to check. If empty, count names + /// of all child elements. + /// \param[in] _ignoreElements A list of child element types to ignore when + /// checking for uniqueness. + /// \return Map from Element names to a count of how many times the name + /// occurs. The count should never be 0. If all 2nd values are 1, then + /// there are exclusively unique names. + public: std::map CountNamedElements( + sdf::Errors &_errors, + const std::string &_type, + const std::vector &_ignoreElements) const; + /// \brief Return a pointer to the child element with the provided name. /// /// A new child element, with the provided name, is added to this element @@ -575,6 +734,11 @@ namespace sdf /// the embedded Param. public: void Update(); + /// \brief Call the Update() callback on each element, as well as + /// the embedded Param. + /// \param[out] _errors Vector of errors. + public: void Update(sdf::Errors &_errors); + /// \brief Call reset on each element and element description /// before deleting all of them. Also clear out the /// embedded Param. @@ -661,16 +825,18 @@ namespace sdf public: static std::vector NameUniquenessExceptions(); /// \brief Generate a string (XML) representation of this object. + /// \param[out] _out the std::ostreamstream to write output to. + /// \param[out] _errors Vector of errors. /// \param[in] _prefix arbitrary prefix to put on the string. /// \param[in] _includeDefaultElements flag to include default elements. /// \param[in] _includeDefaultAttributes flag to include default attributes. /// \param[in] _config Configuration for converting to string. - /// \param[out] _out the std::ostreamstream to write output to. - private: void ToString(const std::string &_prefix, + private: void ToString(std::ostringstream &_out, + sdf::Errors &_errors, + const std::string &_prefix, bool _includeDefaultElements, bool _includeDefaultAttributes, - const PrintConfig &_config, - std::ostringstream &_out) const; + const PrintConfig &_config) const; /// \brief Generate a string (XML) representation of this object. /// \param[in] _prefix arbitrary prefix to put on the string. @@ -678,11 +844,13 @@ namespace sdf /// \param[in] _includeDefaultAttributes flag to include default attributes. /// \param[in] _config Configuration for printing values. /// \param[out] _out the std::ostringstream to write output to. + /// \param[out] _errors Vector of errors. private: void PrintValuesImpl(const std::string &_prefix, bool _includeDefaultElements, bool _includeDefaultAttributes, const PrintConfig &_config, - std::ostringstream &_out) const; + std::ostringstream &_out, + sdf::Errors &_errors) const; /// \brief Create a new Param object and return it. /// \param[in] _key Key for the parameter. @@ -782,8 +950,29 @@ namespace sdf public: void PrintAttributes(bool _includeDefaultAttributes, const PrintConfig &_config, std::ostringstream &_out) const; + + /// \brief Generate the string (XML) for the attributes. + /// \param[in] _includeDefaultAttributes flag to include default attributes. + /// \param[in] _config Configuration for printing attributes. + /// \param[out] _out the std::ostringstream to write output to. + /// \param[out] _errors Vector of errors. + public: void PrintAttributes(bool _includeDefaultAttributes, + const PrintConfig &_config, + std::ostringstream &_out, + sdf::Errors &_errors) const; }; + /////////////////////////////////////////////// + template + T Element::Get(sdf::Errors &_errors, const std::string &_key) const + { + T result = T(); + + std::pair ret = this->Get(_errors, _key, result); + + return ret.first; + } + /////////////////////////////////////////////// template T Element::Get(const std::string &_key) const @@ -795,6 +984,18 @@ namespace sdf return ret.first; } + /////////////////////////////////////////////// + template + bool Element::Get(sdf::Errors &_errors, + const std::string &_key, + T &_param, + const T &_defaultValue) const + { + std::pair ret = this->Get(_errors, _key, _defaultValue); + _param = ret.first; + return ret.second; + } + /////////////////////////////////////////////// template bool Element::Get(const std::string &_key, @@ -810,27 +1011,42 @@ namespace sdf template std::pair Element::Get(const std::string &_key, const T &_defaultValue) const + { + sdf::Errors errors; + std::pair result = this->Get(errors, _key, _defaultValue); + for(auto& error : errors) + { + sdferr << error.Message(); + } + return result; + } + + /////////////////////////////////////////////// + template + std::pair Element::Get(sdf::Errors &_errors, + const std::string &_key, + const T &_defaultValue) const { std::pair result(_defaultValue, true); if (_key.empty() && this->dataPtr->value) { - this->dataPtr->value->Get(result.first); + this->dataPtr->value->Get(result.first, _errors); } else if (!_key.empty()) { ParamPtr param = this->GetAttribute(_key); if (param) { - param->Get(result.first); + param->Get(result.first, _errors); } else if (this->HasElement(_key)) { - result.first = this->GetElementImpl(_key)->Get(); + result.first = this->GetElementImpl(_key)->Get(_errors); } else if (this->HasElementDescription(_key)) { - result.first = this->GetElementDescription(_key)->Get(); + result.first = this->GetElementDescription(_key)->Get(_errors); } else { @@ -848,10 +1064,23 @@ namespace sdf /////////////////////////////////////////////// template bool Element::Set(const T &_value) + { + sdf::Errors errors; + bool result = this->Set(_value, errors); + for(auto& error : errors) + { + sdferr << error.Message(); + } + return result; + } + + /////////////////////////////////////////////// + template + bool Element::Set(const T &_value, sdf::Errors &_errors) { if (this->dataPtr->value) { - this->dataPtr->value->Set(_value); + this->dataPtr->value->Set(_value, _errors); return true; } return false; diff --git a/src/Element.cc b/src/Element.cc index 5dfc243c6..2bc5452f5 100644 --- a/src/Element.cc +++ b/src/Element.cc @@ -141,7 +141,7 @@ void Element::AddValue(const std::string &_type, sdf::Errors errors; this->dataPtr->value = this->CreateParam(this->dataPtr->name, _type, _defaultValue, _required, errors, _description); - throwOrPrintErrors(errors); + sdf::throwOrPrintErrors(errors); } ///////////////////////////////////////////////// @@ -166,7 +166,7 @@ void Element::AddValue(const std::string &_type, sdf::Errors errors; this->AddValue(_type, _defaultValue, _required, _minValue, _maxValue, errors, _description); - throwOrPrintErrors(errors); + sdf::throwOrPrintErrors(errors); } ///////////////////////////////////////////////// @@ -218,7 +218,7 @@ void Element::AddAttribute(const std::string &_key, sdf::Errors errors; this->AddAttribute(_key, _type, _defaultValue, _required, errors, _description); - throwOrPrintErrors(errors); + sdf::throwOrPrintErrors(errors); } ///////////////////////////////////////////////// @@ -239,7 +239,7 @@ ElementPtr Element::Clone() const { sdf::Errors errors; ElementPtr elem = this->Clone(errors); - throwOrPrintErrors(errors); + sdf::throwOrPrintErrors(errors); return elem; } @@ -277,13 +277,13 @@ ElementPtr Element::Clone(sdf::Errors &_errors) const for (eiter = this->dataPtr->elementDescriptions.begin(); eiter != this->dataPtr->elementDescriptions.end(); ++eiter) { - clone->dataPtr->elementDescriptions.push_back((*eiter)->Clone()); + clone->dataPtr->elementDescriptions.push_back((*eiter)->Clone(_errors)); } for (eiter = this->dataPtr->elements.begin(); eiter != this->dataPtr->elements.end(); ++eiter) { - clone->dataPtr->elements.push_back((*eiter)->Clone()); + clone->dataPtr->elements.push_back((*eiter)->Clone(_errors)); clone->dataPtr->elements.back()->SetParent(clone); } @@ -314,7 +314,7 @@ void Element::Copy(const ElementPtr _elem) { sdf::Errors errors; this->Copy(_elem, errors); - throwOrPrintErrors(errors); + sdf::throwOrPrintErrors(errors); } ///////////////////////////////////////////////// @@ -404,6 +404,15 @@ void Element::Copy(const ElementPtr _elem, sdf::Errors &_errors) ///////////////////////////////////////////////// void Element::PrintDescription(const std::string &_prefix) const +{ + sdf::Errors errors; + this->PrintDescription(_prefix, errors); + sdf::throwOrPrintErrors(errors); +} + +///////////////////////////////////////////////// +void Element::PrintDescription(const std::string &_prefix, + sdf::Errors &_errors) const { std::cout << _prefix << "dataPtr->value->GetDefaultAsString(_errors) << "'"; - auto minValue = this->dataPtr->value->GetMinValueAsString(); + auto minValue = this->dataPtr->value->GetMinValueAsString(_errors); if (minValue.has_value()) { std::cout << " min ='" << *minValue << "'"; } - auto maxValue = this->dataPtr->value->GetMaxValueAsString(); + auto maxValue = this->dataPtr->value->GetMaxValueAsString(_errors); if (maxValue.has_value()) { std::cout << " max ='" << *maxValue << "'"; @@ -439,7 +449,7 @@ void Element::PrintDescription(const std::string &_prefix) const { std::cout << _prefix << " \n"; std::cout << _prefix << " GetDescription() @@ -464,7 +474,7 @@ void Element::PrintDescription(const std::string &_prefix) const for (eiter = this->dataPtr->elementDescriptions.begin(); eiter != this->dataPtr->elementDescriptions.end(); ++eiter) { - (*eiter)->PrintDescription(_prefix + " "); + (*eiter)->PrintDescription(_prefix + " ", _errors); } std::cout << _prefix << "\n"; @@ -473,6 +483,15 @@ void Element::PrintDescription(const std::string &_prefix) const ///////////////////////////////////////////////// void Element::PrintDocRightPane(std::string &_html, int _spacing, int &_index) const +{ + sdf::Errors errors; + this->PrintDocRightPane(_html, _spacing, _index, errors); + sdf::throwOrPrintErrors(errors); +} + +///////////////////////////////////////////////// +void Element::PrintDocRightPane(std::string &_html, int _spacing, + int &_index, sdf::Errors &_errors) const { std::ostringstream stream; ElementPtr_V::iterator eiter; @@ -483,7 +502,7 @@ void Element::PrintDocRightPane(std::string &_html, int _spacing, for (eiter = this->dataPtr->elementDescriptions.begin(); eiter != this->dataPtr->elementDescriptions.end(); ++eiter) { - (*eiter)->PrintDocRightPane(childHTML, _spacing + 4, _index); + (*eiter)->PrintDocRightPane(childHTML, _spacing + 4, _index, _errors); } stream << "dataPtr->name << start @@ -512,7 +531,7 @@ void Element::PrintDocRightPane(std::string &_html, int _spacing, stream << this->dataPtr->value->GetTypeName() << "   \n" << "Default: " - << this->dataPtr->value->GetDefaultAsString() << '\n'; + << this->dataPtr->value->GetDefaultAsString(_errors) << '\n'; } else { @@ -552,7 +571,7 @@ void Element::PrintDocRightPane(std::string &_html, int _spacing, stream << "Type: " << (*aiter)->GetTypeName() << "   " << "Default: " - << (*aiter)->GetDefaultAsString() << "
"; + << (*aiter)->GetDefaultAsString(_errors) << "
"; stream << "\n"; stream << "\n"; @@ -598,17 +617,19 @@ void Element::PrintValuesImpl(const std::string &_prefix, bool _includeDefaultElements, bool _includeDefaultAttributes, const PrintConfig &_config, - std::ostringstream &_out) const + std::ostringstream &_out, + sdf::Errors &_errors) const { if (_config.PreserveIncludes() && this->GetIncludeElement() != nullptr) { - _out << this->GetIncludeElement()->ToString(_prefix, _config); + _out << this->GetIncludeElement()->ToString(_errors, _prefix, _config); } else if (this->GetExplicitlySetInFile() || _includeDefaultElements) { _out << _prefix << "<" << this->dataPtr->name; - this->dataPtr->PrintAttributes(_includeDefaultAttributes, _config, _out); + this->dataPtr->PrintAttributes( + _includeDefaultAttributes, _config, _out, _errors); if (this->dataPtr->elements.size() > 0) { @@ -617,11 +638,12 @@ void Element::PrintValuesImpl(const std::string &_prefix, for (eiter = this->dataPtr->elements.begin(); eiter != this->dataPtr->elements.end(); ++eiter) { - (*eiter)->ToString(_prefix + " ", + (*eiter)->ToString(_out, + _errors, + _prefix + " ", _includeDefaultElements, _includeDefaultAttributes, - _config, - _out); + _config); } _out << _prefix << "dataPtr->name << ">\n"; } @@ -629,7 +651,7 @@ void Element::PrintValuesImpl(const std::string &_prefix, { if (this->dataPtr->value) { - _out << ">" << this->dataPtr->value->GetAsString(_config) + _out << ">" << this->dataPtr->value->GetAsString(_errors, _config) << "dataPtr->name << ">\n"; } else @@ -644,6 +666,18 @@ void Element::PrintValuesImpl(const std::string &_prefix, void ElementPrivate::PrintAttributes(bool _includeDefaultAttributes, const PrintConfig &_config, std::ostringstream &_out) const +{ + sdf::Errors errors; + this->PrintAttributes(_includeDefaultAttributes, _config, + _out, errors); + sdf::throwOrPrintErrors(errors); +} + +///////////////////////////////////////////////// +void ElementPrivate::PrintAttributes(bool _includeDefaultAttributes, + const PrintConfig &_config, + std::ostringstream &_out, + sdf::Errors &_errors) const { // Attribute exceptions are used in the event of a non-default PrintConfig // which modifies the Attributes of this Element that are printed out. The @@ -678,17 +712,30 @@ void ElementPrivate::PrintAttributes(bool _includeDefaultAttributes, const auto it = attributeExceptions.find(key); if (it == attributeExceptions.end()) { - _out << " " << key << "='" << (*aiter)->GetAsString(_config) << "'"; + _out << " " << key << "='" + << (*aiter)->GetAsString(_errors, _config) << "'"; } } } } ///////////////////////////////////////////////// -void Element::PrintValues(std::string _prefix, const PrintConfig &_config) const +void Element::PrintValues(std::string _prefix, + const PrintConfig &_config) const { std::ostringstream ss; - PrintValuesImpl(_prefix, true, false, _config, ss); + sdf::Errors errors; + PrintValuesImpl(_prefix, true, false, _config, ss, errors); + sdf::throwOrPrintErrors(errors); + std::cout << ss.str(); +} + +///////////////////////////////////////////////// +void Element::PrintValues(sdf::Errors &_errors, std::string _prefix, + const PrintConfig &_config) const +{ + std::ostringstream ss; + PrintValuesImpl(_prefix, true, false, _config, ss, _errors); std::cout << ss.str(); } @@ -697,22 +744,54 @@ void Element::PrintValues(const std::string &_prefix, bool _includeDefaultElements, bool _includeDefaultAttributes, const PrintConfig &_config) const +{ + std::ostringstream ss; + sdf::Errors errors; + PrintValuesImpl(_prefix, + _includeDefaultElements, + _includeDefaultAttributes, + _config, + ss, + errors); + sdf::throwOrPrintErrors(errors); + std::cout << ss.str(); +} + +///////////////////////////////////////////////// +void Element::PrintValues(sdf::Errors &_errors, + const std::string &_prefix, + bool _includeDefaultElements, + bool _includeDefaultAttributes, + const PrintConfig &_config) const { std::ostringstream ss; PrintValuesImpl(_prefix, _includeDefaultElements, _includeDefaultAttributes, _config, - ss); + ss, + _errors); std::cout << ss.str(); } ///////////////////////////////////////////////// std::string Element::ToString(const std::string &_prefix, const PrintConfig &_config) const +{ + sdf::Errors errors; + std::ostringstream out; + this->ToString(out, errors, _prefix, true, false, _config); + sdf::throwOrPrintErrors(errors); + return out.str(); +} + +///////////////////////////////////////////////// +std::string Element::ToString(sdf::Errors &_errors, + const std::string &_prefix, + const PrintConfig &_config) const { std::ostringstream out; - this->ToString(_prefix, true, false, _config, out); + this->ToString(out, _errors, _prefix, true, false, _config); return out.str(); } @@ -722,27 +801,49 @@ std::string Element::ToString(const std::string &_prefix, bool _includeDefaultAttributes, const PrintConfig &_config) const { + sdf::Errors errors; std::ostringstream out; - this->ToString(_prefix, + this->ToString(out, + errors, + _prefix, _includeDefaultElements, _includeDefaultAttributes, - _config, - out); + _config); + sdf::throwOrPrintErrors(errors); return out.str(); } ///////////////////////////////////////////////// -void Element::ToString(const std::string &_prefix, +std::string Element::ToString(sdf::Errors &_errors, + const std::string &_prefix, + bool _includeDefaultElements, + bool _includeDefaultAttributes, + const PrintConfig &_config) const +{ + std::ostringstream out; + this->ToString(out, + _errors, + _prefix, + _includeDefaultElements, + _includeDefaultAttributes, + _config); + return out.str(); +} + +///////////////////////////////////////////////// +void Element::ToString(std::ostringstream &_out, + sdf::Errors &_errors, + const std::string &_prefix, bool _includeDefaultElements, bool _includeDefaultAttributes, - const PrintConfig &_config, - std::ostringstream &_out) const + const PrintConfig &_config) const { PrintValuesImpl(_prefix, _includeDefaultElements, _includeDefaultAttributes, _config, - _out); + _out, + _errors); } ///////////////////////////////////////////////// @@ -957,12 +1058,33 @@ bool Element::HasUniqueChildNames(const std::string &_type) const return this->HasUniqueChildNames(_type, {}); } +///////////////////////////////////////////////// +bool Element::HasUniqueChildNames( + sdf::Errors &_errors, + const std::string &_type) const +{ + return this->HasUniqueChildNames(_errors, _type, {}); +} + ///////////////////////////////////////////////// bool Element::HasUniqueChildNames( const std::string &_type, const std::vector &_ignoreElements) const { - auto namedElementsCount = this->CountNamedElements(_type, _ignoreElements); + sdf::Errors errors; + bool result = this->HasUniqueChildNames(errors, _type, _ignoreElements); + sdf::throwOrPrintErrors(errors); + return result; +} + +///////////////////////////////////////////////// +bool Element::HasUniqueChildNames( + sdf::Errors &_errors, + const std::string &_type, + const std::vector &_ignoreElements) const +{ + auto namedElementsCount = this->CountNamedElements( + _errors, _type, _ignoreElements); for (auto &iter : namedElementsCount) { if (iter.second > 1) @@ -982,6 +1104,26 @@ std::map Element::CountNamedElements( ///////////////////////////////////////////////// std::map Element::CountNamedElements( + sdf::Errors &_errors, + const std::string &_type) const +{ + return this->CountNamedElements(_errors, _type, {}); +} + +///////////////////////////////////////////////// +std::map Element::CountNamedElements( + const std::string &_type, + const std::vector &_ignoreElements) const +{ + sdf::Errors errors; + auto result = this->CountNamedElements(errors, _type, _ignoreElements); + sdf::throwOrPrintErrors(errors); + return result; +} + +///////////////////////////////////////////////// +std::map Element::CountNamedElements( + sdf::Errors &_errors, const std::string &_type, const std::vector &_ignoreElements) const { @@ -1006,7 +1148,8 @@ std::map Element::CountNamedElements( // Get("name") returns attribute value if it exists before checking // for the value of a child element , so it's safe to use // here since we've checked HasAttribute("name"). - std::string childNameAttributeValue = elem->Get("name"); + std::string childNameAttributeValue = elem->Get( + _errors, "name"); if (result.find(childNameAttributeValue) == result.end()) { result[childNameAttributeValue] = 1; @@ -1028,7 +1171,7 @@ ElementPtr Element::GetElement(const std::string &_name) { sdf::Errors errors; ElementPtr result = this->GetElement(_name, errors); - throwOrPrintErrors(errors); + sdf::throwOrPrintErrors(errors); return result; } @@ -1081,7 +1224,7 @@ ElementPtr Element::AddElement(const std::string &_name) { sdf::Errors errors; ElementPtr elem = this->AddElement(_name, errors); - throwOrPrintErrors(errors); + sdf::throwOrPrintErrors(errors); return elem; } @@ -1153,24 +1296,33 @@ void Element::ClearElements() this->dataPtr->elements.clear(); } + ///////////////////////////////////////////////// void Element::Update() +{ + sdf::Errors errors; + this->Update(errors); + sdf::throwOrPrintErrors(errors); +} + +///////////////////////////////////////////////// +void Element::Update(sdf::Errors &_errors) { for (sdf::Param_V::iterator iter = this->dataPtr->attributes.begin(); iter != this->dataPtr->attributes.end(); ++iter) { - (*iter)->Update(); + (*iter)->Update(_errors); } for (sdf::ElementPtr_V::iterator iter = this->dataPtr->elements.begin(); iter != this->dataPtr->elements.end(); ++iter) { - (*iter)->Update(); + (*iter)->Update(_errors); } if (this->dataPtr->value) { - this->dataPtr->value->Update(); + this->dataPtr->value->Update(_errors); } } @@ -1305,7 +1457,7 @@ void Element::RemoveChild(ElementPtr _child) { sdf::Errors errors; RemoveChild(_child, errors); - throwOrPrintErrors(errors); + sdf::throwOrPrintErrors(errors); } ///////////////////////////////////////////////// @@ -1334,7 +1486,7 @@ std::any Element::GetAny(const std::string &_key) const { sdf::Errors errors; std::any result = this->GetAny(errors, _key); - throwOrPrintErrors(errors); + sdf::throwOrPrintErrors(errors); return result; } @@ -1344,7 +1496,7 @@ std::any Element::GetAny(sdf::Errors &_errors, const std::string &_key) const std::any result; if (_key.empty() && this->dataPtr->value) { - if (!this->dataPtr->value->GetAny(result)) + if (!this->dataPtr->value->GetAny(result, _errors)) { _errors.push_back({ErrorCode::ELEMENT_ERROR, "Couldn't get element [" + this->GetName() + "] as std::any\n"}); From 84ea3fd4acf52016cca7616879718092ec6d632b Mon Sep 17 00:00:00 2001 From: "Marco A. Gutierrez" Date: Mon, 19 Sep 2022 05:04:22 +0000 Subject: [PATCH 2/4] adding errors parameter to function calls Signed-off-by: Marco A. Gutierrez --- include/sdf/Noise.hh | 8 +++++++ src/Noise.cc | 52 ++++++++++++++++++++++++++++---------------- 2 files changed, 41 insertions(+), 19 deletions(-) diff --git a/include/sdf/Noise.hh b/include/sdf/Noise.hh index 0d99c4dcf..361e12f7e 100644 --- a/include/sdf/Noise.hh +++ b/include/sdf/Noise.hh @@ -169,6 +169,14 @@ namespace sdf /// \return SDF element pointer with updated noise values. public: sdf::ElementPtr ToElement() const; + /// \brief Create and return an SDF element filled with data from this + /// noise. + /// Note that parameter passing functionality is not captured with this + /// function. + /// \param[out] _errors Vector of errors. + /// \return SDF element pointer with updated noise values. + public: sdf::ElementPtr ToElement(sdf::Errors &_errors) const; + /// \brief Private data pointer. GZ_UTILS_IMPL_PTR(dataPtr) }; diff --git a/src/Noise.cc b/src/Noise.cc index e286ed51a..450723b3d 100644 --- a/src/Noise.cc +++ b/src/Noise.cc @@ -19,6 +19,7 @@ #include "sdf/Noise.hh" #include "sdf/parser.hh" #include "sdf/Types.hh" +#include "Utils.hh" using namespace sdf; @@ -78,7 +79,8 @@ Errors Noise::Load(ElementPtr _sdf) return errors; } - std::pair type = _sdf->Get("type", "none"); + std::pair type = + _sdf->Get(errors, "type", "none"); if (!type.second) { errors.push_back({ErrorCode::ELEMENT_MISSING, @@ -102,26 +104,26 @@ Errors Noise::Load(ElementPtr _sdf) this->dataPtr->type = NoiseType::NONE; } - this->dataPtr->mean = _sdf->Get("mean", + this->dataPtr->mean = _sdf->Get(errors, "mean", this->dataPtr->mean).first; - this->dataPtr->stdDev = _sdf->Get("stddev", + this->dataPtr->stdDev = _sdf->Get(errors, "stddev", this->dataPtr->stdDev).first; - this->dataPtr->biasMean = _sdf->Get("bias_mean", + this->dataPtr->biasMean = _sdf->Get(errors, "bias_mean", this->dataPtr->biasMean).first; - this->dataPtr->biasStdDev = _sdf->Get("bias_stddev", + this->dataPtr->biasStdDev = _sdf->Get(errors, "bias_stddev", this->dataPtr->biasStdDev).first; - this->dataPtr->precision = _sdf->Get("precision", + this->dataPtr->precision = _sdf->Get(errors, "precision", this->dataPtr->precision).first; - this->dataPtr->dynamicBiasStdDev = _sdf->Get("dynamic_bias_stddev", - this->dataPtr->dynamicBiasStdDev).first; + this->dataPtr->dynamicBiasStdDev = _sdf->Get( + errors, "dynamic_bias_stddev", this->dataPtr->dynamicBiasStdDev).first; this->dataPtr->dynamicBiasCorrelationTime = _sdf->Get( - "dynamic_bias_correlation_time", + errors, "dynamic_bias_correlation_time", this->dataPtr->dynamicBiasCorrelationTime).first; return errors; @@ -252,6 +254,15 @@ bool Noise::operator==(const Noise &_noise) const ///////////////////////////////////////////////// sdf::ElementPtr Noise::ToElement() const +{ + sdf::Errors errors; + auto result = this->ToElement(errors); + sdf::throwOrPrintErrors(errors); + return result; +} + +///////////////////////////////////////////////// +sdf::ElementPtr Noise::ToElement(sdf::Errors &_errors) const { sdf::ElementPtr elem(new sdf::Element); sdf::initFile("noise.sdf", elem); @@ -271,18 +282,21 @@ sdf::ElementPtr Noise::ToElement() const default: noiseType = "none"; } - elem->GetAttribute("type")->Set(noiseType); - elem->GetElement("mean")->Set(this->Mean()); - elem->GetElement("stddev")->Set(this->StdDev()); + elem->GetAttribute("type")->Set(noiseType, _errors); + elem->GetElement("mean", _errors)->Set(this->Mean(), _errors); + elem->GetElement("stddev", _errors)->Set(this->StdDev(), _errors); // camera and lidar does not have the sdf params below - elem->GetElement("bias_mean")->Set(this->BiasMean()); - elem->GetElement("bias_stddev")->Set(this->BiasStdDev()); - elem->GetElement("dynamic_bias_stddev")->Set( - this->DynamicBiasStdDev()); - elem->GetElement("dynamic_bias_correlation_time")->Set( - this->DynamicBiasCorrelationTime()); - elem->GetElement("precision")->Set(this->Precision()); + elem->GetElement("bias_mean", _errors)->Set( + this->BiasMean(), _errors); + elem->GetElement("bias_stddev", _errors)->Set( + this->BiasStdDev(), _errors); + elem->GetElement("dynamic_bias_stddev", _errors)->Set( + this->DynamicBiasStdDev(), _errors); + elem->GetElement("dynamic_bias_correlation_time", _errors)->Set( + this->DynamicBiasCorrelationTime(), _errors); + elem->GetElement("precision", _errors)->Set( + this->Precision(), _errors); return elem; } From f6ee3b0cfb5373bb5f09d7700bf70c8fc5a63b68 Mon Sep 17 00:00:00 2001 From: "Marco A. Gutierrez" Date: Tue, 20 Sep 2022 05:33:51 +0000 Subject: [PATCH 3/4] adding errors to AirPressure function calls Signed-off-by: Marco A. Gutierrez --- include/sdf/AirPressure.hh | 8 ++++++++ src/AirPressure.cc | 28 +++++++++++++++++++--------- 2 files changed, 27 insertions(+), 9 deletions(-) diff --git a/include/sdf/AirPressure.hh b/include/sdf/AirPressure.hh index 5117a6e1a..798474dd5 100644 --- a/include/sdf/AirPressure.hh +++ b/include/sdf/AirPressure.hh @@ -91,6 +91,14 @@ namespace sdf /// \return SDF element pointer with updated sensor values. public: sdf::ElementPtr ToElement() const; + /// \brief Create and return an SDF element filled with data from this + /// air pressure sensor. + /// Note that parameter passing functionality is not captured with this + /// function. + /// \param[out] _errors Vector of errors. + /// \return SDF element pointer with updated sensor values. + public: sdf::ElementPtr ToElement(sdf::Errors &_errors) const; + /// \brief Private data pointer. GZ_UTILS_IMPL_PTR(dataPtr) }; diff --git a/src/AirPressure.cc b/src/AirPressure.cc index 26c4b7c8e..44175eece 100644 --- a/src/AirPressure.cc +++ b/src/AirPressure.cc @@ -18,6 +18,7 @@ #include #include "sdf/AirPressure.hh" #include "sdf/parser.hh" +#include "Utils.hh" using namespace sdf; @@ -60,13 +61,13 @@ Errors AirPressure::Load(ElementPtr _sdf) // Load the noise values. if (_sdf->HasElement("pressure")) { - sdf::ElementPtr elem = _sdf->GetElement("pressure"); + sdf::ElementPtr elem = _sdf->GetElement("pressure", errors); if (elem->HasElement("noise")) - this->dataPtr->noise.Load(elem->GetElement("noise")); + this->dataPtr->noise.Load(elem->GetElement("noise", errors)); } - this->dataPtr->referenceAltitude = _sdf->Get("reference_altitude", - this->dataPtr->referenceAltitude).first; + this->dataPtr->referenceAltitude = _sdf->Get( + errors, "reference_altitude", this->dataPtr->referenceAltitude).first; return errors; } @@ -117,15 +118,24 @@ void AirPressure::SetPressureNoise(const Noise &_noise) ///////////////////////////////////////////////// sdf::ElementPtr AirPressure::ToElement() const +{ + sdf::Errors errors; + auto result = this->ToElement(errors); + sdf::throwOrPrintErrors(errors); + return result; +} + +///////////////////////////////////////////////// +sdf::ElementPtr AirPressure::ToElement(sdf::Errors &_errors) const { sdf::ElementPtr elem(new sdf::Element); sdf::initFile("air_pressure.sdf", elem); - elem->GetElement("reference_altitude")->Set( - this->ReferenceAltitude()); - sdf::ElementPtr pressureElem = elem->GetElement("pressure"); - sdf::ElementPtr noiseElem = pressureElem->GetElement("noise"); - noiseElem->Copy(this->dataPtr->noise.ToElement()); + elem->GetElement("reference_altitude", _errors)->Set( + this->ReferenceAltitude(), _errors); + sdf::ElementPtr pressureElem = elem->GetElement("pressure", _errors); + sdf::ElementPtr noiseElem = pressureElem->GetElement("noise", _errors); + noiseElem->Copy(this->dataPtr->noise.ToElement(_errors), _errors); return elem; } From bfaefea362ba54cdc6ff2b0450688c0e389695c7 Mon Sep 17 00:00:00 2001 From: "Marco A. Gutierrez" Date: Tue, 28 Mar 2023 03:31:04 +0000 Subject: [PATCH 4/4] Add ToElement error test Signed-off-by: Marco A. Gutierrez --- src/AirPressure_TEST.cc | 59 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 59 insertions(+) diff --git a/src/AirPressure_TEST.cc b/src/AirPressure_TEST.cc index fff895faf..076d6c7fc 100644 --- a/src/AirPressure_TEST.cc +++ b/src/AirPressure_TEST.cc @@ -17,6 +17,7 @@ #include #include "sdf/AirPressure.hh" +#include "test_utils.hh" ///////////////////////////////////////////////// TEST(DOMAirPressure, Construction) @@ -131,3 +132,61 @@ TEST(DOMAirPressure, ToElement) air3.Load(air2Elem); EXPECT_DOUBLE_EQ(111.0, air3.ReferenceAltitude()); } + +///////////////////////////////////////////////// +TEST(DOMAirPressure, ToElementErrorOutput) +{ + std::stringstream buffer; + sdf::testing::RedirectConsoleStream redir( + sdf::Console::Instance()->GetMsgStream(), &buffer); + + #ifdef _WIN32 + sdf::Console::Instance()->SetQuiet(false); + sdf::testing::ScopeExit revertSetQuiet( + [] + { + sdf::Console::Instance()->SetQuiet(true); + }); + #endif + + // test calling ToElement on a DOM object constructed without calling Load + sdf::AirPressure air; + sdf::Noise noise; + sdf::Errors errors; + air.SetReferenceAltitude(10.2); + noise.SetType(sdf::NoiseType::GAUSSIAN); + noise.SetMean(1.2); + noise.SetStdDev(2.3); + noise.SetBiasMean(4.5); + noise.SetBiasStdDev(6.7); + noise.SetPrecision(8.9); + air.SetPressureNoise(noise); + + sdf::ElementPtr airElem = air.ToElement(errors); + EXPECT_TRUE(errors.empty()); + EXPECT_NE(nullptr, airElem); + EXPECT_EQ(nullptr, air.Element()); + + // verify values after loading the element back + sdf::AirPressure air2; + errors = air2.Load(airElem); + EXPECT_TRUE(errors.empty()); + + EXPECT_DOUBLE_EQ(noise.Mean(), air2.PressureNoise().Mean()); + EXPECT_DOUBLE_EQ(noise.StdDev(), air2.PressureNoise().StdDev()); + EXPECT_DOUBLE_EQ(noise.BiasMean(), air2.PressureNoise().BiasMean()); + EXPECT_DOUBLE_EQ(noise.BiasStdDev(), air2.PressureNoise().BiasStdDev()); + EXPECT_DOUBLE_EQ(noise.Precision(), air2.PressureNoise().Precision()); + EXPECT_DOUBLE_EQ(10.2, air2.ReferenceAltitude()); + + // make changes to DOM and verify ToElement produces updated values + air2.SetReferenceAltitude(111); + sdf::ElementPtr air2Elem = air2.ToElement(); + EXPECT_NE(nullptr, air2Elem); + sdf::AirPressure air3; + air3.Load(air2Elem); + EXPECT_DOUBLE_EQ(111.0, air3.ReferenceAltitude()); + + // Check nothing has been printed + EXPECT_TRUE(buffer.str().empty()) << buffer.str(); +}