From ae75d05c2c8a75638e12eefb2b4922c73008d8e6 Mon Sep 17 00:00:00 2001 From: Adam Wulkiewicz Date: Wed, 18 Apr 2018 00:33:47 +0200 Subject: [PATCH] [srs] Implement str_cast and use it instead of lexical_cast. --- .../srs/projections/impl/dms_parser.hpp | 18 +- .../geometry/srs/projections/impl/pj_init.hpp | 13 +- .../srs/projections/impl/pj_param.hpp | 4 +- .../geometry/srs/projections/str_cast.hpp | 158 ++++++++++++++++++ 4 files changed, 170 insertions(+), 23 deletions(-) create mode 100644 include/boost/geometry/srs/projections/str_cast.hpp diff --git a/include/boost/geometry/srs/projections/impl/dms_parser.hpp b/include/boost/geometry/srs/projections/impl/dms_parser.hpp index bbecc9b1a..15e4e57ad 100644 --- a/include/boost/geometry/srs/projections/impl/dms_parser.hpp +++ b/include/boost/geometry/srs/projections/impl/dms_parser.hpp @@ -41,18 +41,12 @@ #include +#include +#include #include -#if !defined(BOOST_GEOMETRY_NO_LEXICAL_CAST) -#include -#endif // !defined(BOOST_GEOMETRY_NO_LEXICAL_CAST) - -#include - -#include - #include - +#include #include namespace boost { namespace geometry { namespace projections @@ -145,11 +139,7 @@ struct dms_parser template static inline void assign_dms(dms_value& dms, std::string& value, bool& has_value) { -#if !defined(BOOST_GEOMETRY_NO_LEXICAL_CAST) - dms.dms[I] = boost::lexical_cast(value.c_str()); -#else // !defined(BOOST_GEOMETRY_NO_LEXICAL_CAST) - dms.dms[I] = std::atof(value.c_str()); -#endif // !defined(BOOST_GEOMETRY_NO_LEXICAL_CAST) + dms.dms[I] = geometry::str_cast(value); dms.has_dms[I] = true; has_value = false; value.clear(); diff --git a/include/boost/geometry/srs/projections/impl/pj_init.hpp b/include/boost/geometry/srs/projections/impl/pj_init.hpp index 2ca9b1805..1d2db1af2 100644 --- a/include/boost/geometry/srs/projections/impl/pj_init.hpp +++ b/include/boost/geometry/srs/projections/impl/pj_init.hpp @@ -44,7 +44,6 @@ #include #include -#include #include #include @@ -157,12 +156,12 @@ inline void pj_init_units(std::vector > const& params, std::size_t const pos = s.find('/'); if (pos == std::string::npos) { - to_meter = lexical_cast(s); + to_meter = geometry::str_cast(s); } else { - T const numerator = lexical_cast(s.substr(0, pos)); - T const denominator = lexical_cast(s.substr(pos + 1)); + T const numerator = geometry::str_cast(s.substr(0, pos)); + T const denominator = geometry::str_cast(s.substr(pos + 1)); if (numerator == 0.0 || denominator == 0.0) { BOOST_THROW_EXCEPTION( projection_exception(error_unit_factor_less_than_0) ); @@ -316,8 +315,8 @@ inline parameters pj_init(BGParams const& bg_params, R const& arguments, bool dms_parser parser; - // TODO: Handle case when lexical_cast is not used consistently. - // This should probably be done in dms_parser. + // TODO: Is this try-catch needed? + // In other cases the bad_str_cast exception is simply thrown BOOST_TRY { if (value.empty()) { @@ -326,7 +325,7 @@ inline parameters pj_init(BGParams const& bg_params, R const& arguments, bool pin.from_greenwich = parser.apply(value).angle(); } } - BOOST_CATCH(boost::bad_lexical_cast const&) + BOOST_CATCH(geometry::bad_str_cast const&) { BOOST_THROW_EXCEPTION( projection_exception(error_unknown_prime_meridian) ); } diff --git a/include/boost/geometry/srs/projections/impl/pj_param.hpp b/include/boost/geometry/srs/projections/impl/pj_param.hpp index 751693f76..764805541 100644 --- a/include/boost/geometry/srs/projections/impl/pj_param.hpp +++ b/include/boost/geometry/srs/projections/impl/pj_param.hpp @@ -122,7 +122,7 @@ inline bool pj_param_i(std::vector > const& pl, std::string const& nam typename std::vector >::const_iterator it = pj_param_find(pl, name); if (it != pl.end()) { - par = atoi(it->s.c_str()); + par = geometry::str_cast(it->s); return true; } return false; @@ -135,7 +135,7 @@ inline bool pj_param_f(std::vector > const& pl, std::string const& nam typename std::vector >::const_iterator it = pj_param_find(pl, name); if (it != pl.end()) { - par = atof(it->s.c_str()); + par = geometry::str_cast(it->s); return true; } return false; diff --git a/include/boost/geometry/srs/projections/str_cast.hpp b/include/boost/geometry/srs/projections/str_cast.hpp new file mode 100644 index 000000000..ff49dbf03 --- /dev/null +++ b/include/boost/geometry/srs/projections/str_cast.hpp @@ -0,0 +1,158 @@ +// Boost.Geometry + +// Copyright (c) 2018, Oracle and/or its affiliates. +// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle + +// Use, modification and distribution is subject to the Boost Software License, +// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_GEOMETRY_SRS_PROJECTIONS_STR_CAST_HPP +#define BOOST_GEOMETRY_SRS_PROJECTIONS_STR_CAST_HPP + +#include +#include +#include +#include +#include + +#include +#include + +namespace boost { namespace geometry +{ + +class bad_str_cast : public geometry::exception +{ + virtual char const* what() const throw() + { + return "Unable to convert from string."; + } +}; + +#ifndef DOXYGEN_NO_DETAIL +namespace detail +{ + +template +< + typename T, + bool IsIntegral = boost::is_integral::value, + bool IsSigned = boost::is_signed::value +> +struct str_cast_traits_strtox +{ + static inline T apply(const char *str, char **str_end) + { + return strtod(str, str_end); + } +}; + +template +struct str_cast_traits_strtox +{ + static inline T apply(const char *str, char **str_end) + { + return strtol(str, str_end, 0); + } +}; + +template +struct str_cast_traits_strtox +{ + static inline T apply(const char *str, char **str_end) + { + return strtoul(str, str_end, 0); + } +}; + +template +struct str_cast_traits_strtox +{ + static inline T apply(const char *str, char **str_end) + { + return strtod(str, str_end); + } +}; + +// Assuming a compiler supporting r-value references +// supports long long and strtoll, strtoull, strtof, strtold +#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES +template <> +struct str_cast_traits_strtox +{ + static inline long long apply(const char *str, char **str_end) + { + return strtoll(str, str_end, 0); + } +}; + +template <> +struct str_cast_traits_strtox +{ + static inline unsigned long long apply(const char *str, char **str_end) + { + return strtoull(str, str_end, 0); + } +}; + +template <> +struct str_cast_traits_strtox +{ + static inline float apply(const char *str, char **str_end) + { + return strtof(str, str_end); + } +}; + +template <> +struct str_cast_traits_strtox +{ + static inline long double apply(const char *str, char **str_end) + { + return strtold(str, str_end); + } +}; +#endif // C++11 strtox supported + +template +struct str_cast_traits_generic +{ + static inline T apply(const char *str) + { + char * str_end = (char*)(void*)str; + T res = str_cast_traits_strtox + < + typename boost::remove_cv::type + >::apply(str, &str_end); + if (str_end == str) + { + BOOST_THROW_EXCEPTION( bad_str_cast() ); + } + return res; + } +}; + +} // namespace detail +#endif // DOXYGEN_NO_DETAIL + +template +struct str_cast_traits +{ + template + static inline T apply(String const& str) + { + return detail::str_cast_traits_generic::apply(str.c_str()); + } +}; + +template +inline T str_cast(String const& str) +{ + return str_cast_traits::apply(str); +} + + +}} // namespace boost::geometry + +#endif // BOOST_GEOMETRY_SRS_PROJECTIONS_STR_CAST_HPP