Use locale independent conversion from double to string#1099
Use locale independent conversion from double to string#1099davetcoleman merged 13 commits intomoveit:kinetic-develfrom
Conversation
boost::lexical_cast<std::string>(0.1) returns "0,1" on Dutch, German and probably some other locales which boost::lexical_cast<double> fails to parse even on Dutch, German etc locales so this commit uses std::ostringstream which seems to be the only sane way to ignore locale
rhaschke
left a comment
There was a problem hiding this comment.
I agree to the need of this fix. However, instead of repeating the same code snippet over and over, we should aim for a generic solution at a central place. We already have macros and exceptions. However, both folders have only a single header / source file. I suggest a more generic utils folder:
- utils/CMakeLists.txt (building
libmoveit_utils) - utils/include/moveit/utils/conversions.h
- utils/src/conversions.cpp
There we could implement a moveit::lexical_cast.
| { | ||
| // convert to string using no locale | ||
| std::ostringstream oss; | ||
| oss.imbue(std::locale()); |
There was a problem hiding this comment.
I'm not sure that's really neccessary at all.
If so, I guess you need to use std::locale::classic()
There was a problem hiding this comment.
Yes, using std::locale::classic() is indeed better. Omitting it would probably/usually/maybe also be right unless somebody somewhere set the global locale to something else.
As a side note, using std::stod for the inverse operation does not work as this uses the c locale internally which does seem to get set automatically from the system.
std::locale() copies the global locale, which is already used at construction time of std::stringstream. So this was a noop. The global locale defaults to std::locale::classic() but it might have been set somewhere else before, so explicitly setting std::locale::classic() makes this code independent of locale settings elsewhere.
|
@simonschmeisser Please factor out this conversion code into its own library. |
|
sure, @rhaschke , one thing at its time ;) would you prefer
|
|
github sometimes forgets about my further commits, I'm confused |
|
rhaschke
left a comment
There was a problem hiding this comment.
Thanks for adapting this. Some minor comments inline.
- Did you checked for all occurences of
boost::lexical_castin the source? Are there any other locations that need an updated? - What about conversion fromString to a value? Shouldn't we have appropriate C-locale functions for that too?
| { | ||
| /** \brief Convert a double to std::string without using the system locale | ||
|
|
||
| Depending on the system locale, a different decimal seperator might be used |
There was a problem hiding this comment.
I suggest to move this comment to the top as a general comment for this file.
| { | ||
| namespace utils | ||
| { | ||
| std::string toString(double d) |
There was a problem hiding this comment.
The implementation using function overloading is somewhat redundant.
Why didn't you choose templates as discussed?
There was a problem hiding this comment.
There are only two variable types (float and double) where these functions are required. For other variable types (integer types) std::to_string would be a more obvious solution? This can of course be handled using template specialization if requested but imho just adds compile time and unneeded abstractions.
There was a problem hiding this comment.
@simonschmeisser I always try to prevent code duplication as much as possible - even in this simple case. In this particular case, I would suggest to use a template defined in .cpp only, providing the common implementation for both overloaded functions. This doesn't add compile time or any other complexity to the API.
Please, use github's Reply button to answer such remarks. This way, the thread is kept together.
Co-Authored-By: simonschmeisser <s.schmeisser@gmx.net>
|
about string->float/double: from a bug fixing point of view it's not necessary since boost::lexical_cast(string) expects "." independent of locale (there is not a single line about locales in the documentation of boost::lexical_cast so ...) from a maintenance point of view (as boost::lexical_cast people do not seem to know what a locale is ...) it might be better to indeed add this inverse function |
|
There is only one more places where the conversion double -> string is done incorrectly: should I include it in this PR? |
Yes, please. |
now throws a std::runtime_exception if errors occur. For planners this gets caught in planning_pipeline::PlanningPipeline::generatePlan and there are no further users of toDouble/toFloat currently
rhaschke
left a comment
There was a problem hiding this comment.
Thanks a lot for those fixes. One more nit-pick.
| moveit_distance_field | ||
| moveit_kinematics_metrics | ||
| moveit_dynamics_solver | ||
| moveit_utils |
There was a problem hiding this comment.
this is not a package, remove
There was a problem hiding this comment.
this section is about what libraries are exported by the moveit_core package, you get linker errors in dependent packages if moveit_utils is not added here
There was a problem hiding this comment.
oops sorry. the github code folding hid the relevant section and i made a wrong assumption
| /* Author: Simon Schmeisser */ | ||
|
|
||
| #ifndef MOVEIT_UTILS_ | ||
| #define MOVEIT_UTILS_ |
| #include <string> | ||
| namespace moveit | ||
| { | ||
| namespace utils |
There was a problem hiding this comment.
this should have namespace core also, or instead of utils, as used in all the other subfolders of moveit_core
| std::string toString(double d); | ||
|
|
||
| /** \brief Convert a float to std::string using the classic C locale */ | ||
| std::string toString(float d); |
There was a problem hiding this comment.
| std::string toString(float d); | |
| std::string toString(float f); |
var name makes more sense
| // convert from string using no locale | ||
| std::istringstream iss(s); | ||
| iss.imbue(std::locale::classic()); | ||
| T d; |
There was a problem hiding this comment.
there are too many one character variable names here, hard to read. add longer variable names
| return toStringImpl(d); | ||
| } | ||
|
|
||
| template <class T> |
There was a problem hiding this comment.
I think T would be clearer if called something like OutputDataType
There was a problem hiding this comment.
This is nit-picking. T is the standard for a template type. Only if more than one type is involved, there is a need in more verbose type names.
There was a problem hiding this comment.
fair. just pulling in recent experiences in google-style projects, but ignore my comment
|
LGTM |
| moveit_distance_field | ||
| moveit_kinematics_metrics | ||
| moveit_dynamics_solver | ||
| moveit_utils |
There was a problem hiding this comment.
oops sorry. the github code folding hid the relevant section and i made a wrong assumption
* Use locale independent conversion from double to string boost::lexical_cast<std::string>(0.1) returns "0,1" on Dutch, German and probably some other locales which boost::lexical_cast<double> fails to parse even on Dutch, German etc locales so this commit uses std::ostringstream which seems to be the only sane way to ignore locale * clang format * use std::locale::classic() instead of std::locale() std::locale() copies the global locale, which is already used at construction time of std::stringstream. So this was a noop. The global locale defaults to std::locale::classic() but it might have been set somewhere else before, so explicitly setting std::locale::classic() makes this code independent of locale settings elsewhere. * factor out conversion from double/float to string into moveit_utils * clang format * more explicit description Co-Authored-By: simonschmeisser <s.schmeisser@gmx.net> * adress documentation comments * add and use conversion functions from string to double * Don't write localized doubles to benchmark results * use template internally to avoid code duplication * Add error handling for std::string->float/double now throws a std::runtime_exception if errors occur. For planners this gets caught in planning_pipeline::PlanningPipeline::generatePlan and there are no further users of toDouble/toFloat currently * remove extra parantheses again * Code review comments by Dave
|
Melodic: #1155 |
* Use locale independent conversion from double to string boost::lexical_cast<std::string>(0.1) returns "0,1" on Dutch, German and probably some other locales which boost::lexical_cast<double> fails to parse even on Dutch, German etc locales so this commit uses std::ostringstream which seems to be the only sane way to ignore locale * clang format * use std::locale::classic() instead of std::locale() std::locale() copies the global locale, which is already used at construction time of std::stringstream. So this was a noop. The global locale defaults to std::locale::classic() but it might have been set somewhere else before, so explicitly setting std::locale::classic() makes this code independent of locale settings elsewhere. * factor out conversion from double/float to string into moveit_utils * clang format * more explicit description Co-Authored-By: simonschmeisser <s.schmeisser@gmx.net> * adress documentation comments * add and use conversion functions from string to double * Don't write localized doubles to benchmark results * use template internally to avoid code duplication * Add error handling for std::string->float/double now throws a std::runtime_exception if errors occur. For planners this gets caught in planning_pipeline::PlanningPipeline::generatePlan and there are no further users of toDouble/toFloat currently * remove extra parantheses again * Code review comments by Dave
* Use locale independent conversion from double to string boost::lexical_cast<std::string>(0.1) returns "0,1" on Dutch, German and probably some other locales which boost::lexical_cast<double> fails to parse even on Dutch, German etc locales so this commit uses std::ostringstream which seems to be the only sane way to ignore locale * clang format * use std::locale::classic() instead of std::locale() std::locale() copies the global locale, which is already used at construction time of std::stringstream. So this was a noop. The global locale defaults to std::locale::classic() but it might have been set somewhere else before, so explicitly setting std::locale::classic() makes this code independent of locale settings elsewhere. * factor out conversion from double/float to string into moveit_utils * clang format * more explicit description Co-Authored-By: simonschmeisser <s.schmeisser@gmx.net> * adress documentation comments * add and use conversion functions from string to double * Don't write localized doubles to benchmark results * use template internally to avoid code duplication * Add error handling for std::string->float/double now throws a std::runtime_exception if errors occur. For planners this gets caught in planning_pipeline::PlanningPipeline::generatePlan and there are no further users of toDouble/toFloat currently * remove extra parantheses again * Code review comments by Dave
* Remove OgrePrerequisites include * octomap_render.h includes itself * Include OgrePrerequisites.h
boost::lexical_caststd::string(0.1) returns "0,1" on Dutch, German and probably some other locales
which boost::lexical_cast fails to parse even on Dutch, German etc locales
so this PR uses std::ostringstream which seems to be the only sane way to ignore locale
(this is no new problem, it somehow seemed to "sometimes" work to put strings (ie '0.1') instead off the raw numbers (ie 0.1) in ompl_planning.yaml but not always ...)