Skip to content

Commit

Permalink
Support parsing elements that are not part of the schema (#638)
Browse files Browse the repository at this point in the history
* support parsing inf

Signed-off-by: Jenn Nguyen <jenn@openrobotics.org>

* made ValueFromStringImpl visible

Signed-off-by: Jenn Nguyen <jenn@openrobotics.org>

* type to string mapping

Signed-off-by: Jenn Nguyen <jenn@openrobotics.org>

* added test

Signed-off-by: Jenn Nguyen <jenn@openrobotics.org>

* readded bool test case

Signed-off-by: Jenn Nguyen <jenn@openrobotics.org>

* added comment

Signed-off-by: Jenn Nguyen <jenn@openrobotics.org>
  • Loading branch information
jennuine authored Aug 5, 2021
1 parent 89be29b commit 42f8fad
Show file tree
Hide file tree
Showing 4 changed files with 190 additions and 86 deletions.
122 changes: 88 additions & 34 deletions include/sdf/Param.hh
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,7 @@ namespace sdf

/// \brief Private method to set the Element from a passed-in string.
/// \param[in] _value Value to set the parameter to.
/// \return True if the parameter was successfully set, false otherwise.
private: bool ValueFromString(const std::string &_value);

/// \brief Private data
Expand Down Expand Up @@ -258,8 +259,63 @@ namespace sdf

/// \brief This parameter's default value
public: ParamVariant defaultValue;

/// \brief Method used to set the Param from a passed-in string
/// \param[in] _typeName The data type of the value to set
/// \param[in] _valueStr The value as a string
/// \param[out] _valueToSet The value to set
/// \return True if the value was successfully set, false otherwise
public: bool SDFORMAT_VISIBLE ValueFromStringImpl(
const std::string &_typeName,
const std::string &_valueStr,
ParamVariant &_valueToSet) const;

/// \brief Data type to string mapping
/// \return The type as a string, empty string if unknown type
public: template<typename T>
std::string TypeToString() const;
};

///////////////////////////////////////////////
template<typename T>
std::string ParamPrivate::TypeToString() const
{
if constexpr (std::is_same_v<T, bool>)
return "bool";
else if constexpr (std::is_same_v<T, char>)
return "char";
else if constexpr (std::is_same_v<T, std::string>)
return "string";
else if constexpr (std::is_same_v<T, int>)
return "int";
else if constexpr (std::is_same_v<T, std::uint64_t>)
return "uint64_t";
else if constexpr (std::is_same_v<T, unsigned int>)
return "unsigned int";
else if constexpr (std::is_same_v<T, double>)
return "double";
else if constexpr (std::is_same_v<T, float>)
return "float";
else if constexpr (std::is_same_v<T, sdf::Time>)
return "time";
else if constexpr (std::is_same_v<T, ignition::math::Angle>)
return "angle";
else if constexpr (std::is_same_v<T, ignition::math::Color>)
return "color";
else if constexpr (std::is_same_v<T, ignition::math::Vector2i>)
return "vector2i";
else if constexpr (std::is_same_v<T, ignition::math::Vector2d>)
return "vector2d";
else if constexpr (std::is_same_v<T, ignition::math::Vector3d>)
return "vector3";
else if constexpr (std::is_same_v<T, ignition::math::Quaterniond>)
return "quaternion";
else if constexpr (std::is_same_v<T, ignition::math::Pose3d>)
return "pose";
else
return "";
}

///////////////////////////////////////////////
template<typename T>
void Param::SetUpdateFunc(T _updateFunc)
Expand Down Expand Up @@ -291,50 +347,48 @@ namespace sdf
template<typename T>
bool Param::Get(T &_value) const
{
try
T *value = std::get_if<T>(&this->dataPtr->value);
if (value)
{
if (typeid(T) == typeid(bool) && this->dataPtr->typeName == "string")
_value = *value;
}
else
{
std::string typeStr = this->dataPtr->TypeToString<T>();
if (typeStr.empty())
{
sdferr << "Unknown parameter type[" << typeid(T).name() << "]\n";
return false;
}

std::string valueStr = this->GetAsString();
ParamPrivate::ParamVariant pv;
bool success = this->dataPtr->ValueFromStringImpl(typeStr, valueStr, pv);

if (success)
{
_value = std::get<T>(pv);
}
else if (typeStr == "bool" && this->dataPtr->typeName == "string")
{
std::string strValue = std::get<std::string>(this->dataPtr->value);
std::transform(strValue.begin(), strValue.end(), strValue.begin(),
[](unsigned char c)
{
return static_cast<unsigned char>(std::tolower(c));
});
// this section for handling bool types is to keep backward behavior
// TODO(anyone) remove for Fortress. For more details:
// https://github.com/ignitionrobotics/sdformat/pull/638
valueStr = lowercase(valueStr);

std::stringstream tmp;
if (strValue == "true" || strValue == "1")
{
if (valueStr == "true" || valueStr == "1")
tmp << "1";
}
else
{
tmp << "0";
}

tmp >> _value;
return true;
}
else
{
T *value = std::get_if<T>(&this->dataPtr->value);
if (value)
_value = *value;
else
{
std::stringstream ss;
ss << ParamStreamer{this->dataPtr->value};
ss >> _value;
}
}
}
catch(...)
{
sdferr << "Unable to convert parameter["
<< this->dataPtr->key << "] "
<< "whose type is["
<< this->dataPtr->typeName << "], to "
<< "type[" << typeid(T).name() << "]\n";
return false;

return success;
}

return true;
}

Expand Down
113 changes: 66 additions & 47 deletions src/Param.cc
Original file line number Diff line number Diff line change
Expand Up @@ -273,14 +273,24 @@ std::string Param::GetDefaultAsString() const

//////////////////////////////////////////////////
bool Param::ValueFromString(const std::string &_value)
{
return this->dataPtr->ValueFromStringImpl(this->dataPtr->typeName,
_value,
this->dataPtr->value);
}

//////////////////////////////////////////////////
bool ParamPrivate::ValueFromStringImpl(const std::string &_typeName,
const std::string &_valueStr,
ParamVariant &_valueToSet) const
{
// Under some circumstances, latin locales (es_ES or pt_BR) will return a
// comma for decimal position instead of a dot, making the conversion
// to fail. See bug #60 for more information. Force to use always C
setlocale(LC_NUMERIC, "C");

std::string tmp(_value);
std::string lowerTmp = lowercase(_value);
std::string tmp(_valueStr);
std::string lowerTmp = lowercase(_valueStr);

// "true" and "false" doesn't work properly
if (lowerTmp == "true")
Expand All @@ -304,140 +314,149 @@ bool Param::ValueFromString(const std::string &_value)
numericBase = 16;
}

if (this->dataPtr->typeName == "bool")
if (_typeName == "bool")
{
if (lowerTmp == "true" || lowerTmp == "1")
{
this->dataPtr->value = true;
_valueToSet = true;
}
else if (lowerTmp == "false" || lowerTmp == "0")
{
this->dataPtr->value = false;
_valueToSet = false;
}
else
{
sdferr << "Invalid boolean value\n";
return false;
}
}
else if (this->dataPtr->typeName == "char")
else if (_typeName == "char")
{
this->dataPtr->value = tmp[0];
_valueToSet = tmp[0];
}
else if (this->dataPtr->typeName == "std::string" ||
this->dataPtr->typeName == "string")
else if (_typeName == "std::string" ||
_typeName == "string")
{
this->dataPtr->value = tmp;
_valueToSet = tmp;
}
else if (this->dataPtr->typeName == "int")
else if (_typeName == "int")
{
this->dataPtr->value = std::stoi(tmp, nullptr, numericBase);
_valueToSet = std::stoi(tmp, nullptr, numericBase);
}
else if (this->dataPtr->typeName == "uint64_t")
else if (_typeName == "uint64_t")
{
StringStreamClassicLocale ss(tmp);
std::uint64_t u64tmp;

ss >> u64tmp;
this->dataPtr->value = u64tmp;
_valueToSet = u64tmp;
}
else if (this->dataPtr->typeName == "unsigned int")
else if (_typeName == "unsigned int")
{
this->dataPtr->value = static_cast<unsigned int>(
_valueToSet = static_cast<unsigned int>(
std::stoul(tmp, nullptr, numericBase));
}
else if (this->dataPtr->typeName == "double")
else if (_typeName == "double")
{
this->dataPtr->value = std::stod(tmp);
_valueToSet = std::stod(tmp);
}
else if (this->dataPtr->typeName == "float")
else if (_typeName == "float")
{
this->dataPtr->value = std::stof(tmp);
_valueToSet = std::stof(tmp);
}
else if (this->dataPtr->typeName == "sdf::Time" ||
this->dataPtr->typeName == "time")
else if (_typeName == "sdf::Time" ||
_typeName == "time")
{
StringStreamClassicLocale ss(tmp);
sdf::Time timetmp;

ss >> timetmp;
this->dataPtr->value = timetmp;
_valueToSet = timetmp;
}
else if (_typeName == "ignition::math::Angle" ||
_typeName == "angle")
{
StringStreamClassicLocale ss(tmp);
ignition::math::Angle angletmp;

ss >> angletmp;
_valueToSet = angletmp;
}
else if (this->dataPtr->typeName == "ignition::math::Color" ||
this->dataPtr->typeName == "color")
else if (_typeName == "ignition::math::Color" ||
_typeName == "color")
{
StringStreamClassicLocale ss(tmp);
ignition::math::Color colortmp;

ss >> colortmp;
this->dataPtr->value = colortmp;
_valueToSet = colortmp;
}
else if (this->dataPtr->typeName == "ignition::math::Vector2i" ||
this->dataPtr->typeName == "vector2i")
else if (_typeName == "ignition::math::Vector2i" ||
_typeName == "vector2i")
{
StringStreamClassicLocale ss(tmp);
ignition::math::Vector2i vectmp;

ss >> vectmp;
this->dataPtr->value = vectmp;
_valueToSet = vectmp;
}
else if (this->dataPtr->typeName == "ignition::math::Vector2d" ||
this->dataPtr->typeName == "vector2d")
else if (_typeName == "ignition::math::Vector2d" ||
_typeName == "vector2d")
{
StringStreamClassicLocale ss(tmp);
ignition::math::Vector2d vectmp;

ss >> vectmp;
this->dataPtr->value = vectmp;
_valueToSet = vectmp;
}
else if (this->dataPtr->typeName == "ignition::math::Vector3d" ||
this->dataPtr->typeName == "vector3")
else if (_typeName == "ignition::math::Vector3d" ||
_typeName == "vector3")
{
StringStreamClassicLocale ss(tmp);
ignition::math::Vector3d vectmp;

ss >> vectmp;
this->dataPtr->value = vectmp;
_valueToSet = vectmp;
}
else if (this->dataPtr->typeName == "ignition::math::Pose3d" ||
this->dataPtr->typeName == "pose" ||
this->dataPtr->typeName == "Pose")
else if (_typeName == "ignition::math::Pose3d" ||
_typeName == "pose" ||
_typeName == "Pose")
{
StringStreamClassicLocale ss(tmp);
ignition::math::Pose3d posetmp;

ss >> posetmp;
this->dataPtr->value = posetmp;
_valueToSet = posetmp;
}
else if (this->dataPtr->typeName == "ignition::math::Quaterniond" ||
this->dataPtr->typeName == "quaternion")
else if (_typeName == "ignition::math::Quaterniond" ||
_typeName == "quaternion")
{
StringStreamClassicLocale ss(tmp);
ignition::math::Quaterniond quattmp;

ss >> quattmp;
this->dataPtr->value = quattmp;
_valueToSet = quattmp;
}
else
{
sdferr << "Unknown parameter type[" << this->dataPtr->typeName << "]\n";
sdferr << "Unknown parameter type[" << _typeName << "]\n";
return false;
}
}
// Catch invalid argument exception from std::stoi/stoul/stod/stof
catch(std::invalid_argument &)
{
sdferr << "Invalid argument. Unable to set value ["
<< _value << " ] for key["
<< this->dataPtr->key << "].\n";
<< _valueStr << " ] for key["
<< this->key << "].\n";
return false;
}
// Catch out of range exception from std::stoi/stoul/stod/stof
catch(std::out_of_range &)
{
sdferr << "Out of range. Unable to set value ["
<< _value << " ] for key["
<< this->dataPtr->key << "].\n";
<< _valueStr << " ] for key["
<< this->key << "].\n";
return false;
}

Expand Down
Loading

0 comments on commit 42f8fad

Please sign in to comment.