From 2e93882882df098da84f00c87b10b6c373be6e5c Mon Sep 17 00:00:00 2001 From: Martchus Date: Mon, 24 May 2021 19:28:39 +0200 Subject: [PATCH] Reduce redundant code in stringconversion.h --- conversion/stringconversion.h | 271 +++++++++++++++------------------- tests/conversiontests.cpp | 5 + 2 files changed, 127 insertions(+), 149 deletions(-) diff --git a/conversion/stringconversion.h b/conversion/stringconversion.h index d50feec..37a11ff 100644 --- a/conversion/stringconversion.h +++ b/conversion/stringconversion.h @@ -526,125 +526,6 @@ void raiseAndAdd(IntegralType &result, BaseType base, CharType character) } // namespace Detail /// \endcond -/*! - * \brief Converts the given \a string to an unsigned number assuming \a string uses the specified \a base. - * \tparam IntegralType The data type used to store the converted value. - * \tparam StringType The string type (should be an instantiation of the basic_string class template). - * \throws A ConversionException will be thrown if the provided \a string is not a valid number. - * \sa numberToString(), bufferToNumber() - */ -template , std::is_unsigned, Traits::Not>>> - * = nullptr> -IntegralType stringToNumber(const StringType &string, BaseType base = 10) -{ - IntegralType result = 0; - for (const auto &c : string) { - Detail::raiseAndAdd(result, base, c); - } - return result; -} - -/*! - * \brief Converts the given \a string to a signed number assuming \a string uses the specified \a base. - * \tparam IntegralType The data type used to store the converted value. - * \tparam StringType The string type (should be an instantiation of the basic_string class template). - * \throws A ConversionException will be thrown if the provided \a string is not a valid number. - * \sa numberToString(), bufferToNumber() - */ -template , std::is_signed, Traits::Not>>> * = nullptr> -IntegralType stringToNumber(const StringType &string, BaseType base = 10) -{ - auto i = string.begin(); - auto end = string.end(); - for (; i != end && *i == ' '; ++i) - ; - if (i == end) { - return 0; - } - const bool negative = (*i == '-'); - if (negative) { - ++i; - } - IntegralType result = 0; - for (; i != end; ++i) { - Detail::raiseAndAdd(result, base, *i); - } - return negative ? -result : result; -} - -/*! - * \brief Converts the given \a string to a number assuming \a string uses the specified \a base. - * \tparam FloatingType The data type used to store the converted value. - * \tparam StringType The string type (should be an instantiation of the basic_string class template). - * \throws A ConversionException will be thrown if the provided \a string is not a valid number. - * \remarks This function is using std::basic_stringstream interanlly and hence also has its limitations (eg. regarding - * \a base and types). - * \sa numberToString(), bufferToNumber() - */ -template , Traits::Not>>> * = nullptr> -FloatingType stringToNumber(const StringType &string, int base = 10) -{ - std::basic_stringstream ss; - ss << std::setbase(base) << string; - FloatingType result; - if ((ss >> result) && ss.eof()) { - return result; - } - std::string errorMsg; - errorMsg.reserve(48 + string.size()); - errorMsg += "The string \""; - errorMsg += string; - errorMsg += "\" is no valid floating point number."; - throw ConversionException(errorMsg); -} - -/*! - * \brief Converts the given null-terminated \a string to an unsigned numeric value using the specified \a base. - * \tparam IntegralType The data type used to store the converted value. - * \tparam CharType The character type. - * \throws A ConversionException will be thrown if the provided \a string is not a valid number. - * \sa numberToString(), bufferToNumber() - */ -template , std::is_unsigned> * = nullptr> -IntegralType stringToNumber(const CharType *string, BaseType base = 10) -{ - IntegralType result = 0; - for (; *string; ++string) { - Detail::raiseAndAdd(result, base, *string); - } - return result; -} - -/*! - * \brief Converts the given null-terminated \a string to a number assuming \a string uses the specified \a base. - * \tparam FloatingType The data type used to store the converted value. - * \tparam CharType The character type. - * \throws A ConversionException will be thrown if the provided \a string is not a valid number. - * \remarks This function is using std::basic_stringstream interanlly and hence also has its limitations (eg. regarding - * \a base and types). - * \sa numberToString(), bufferToNumber() - */ -template > * = nullptr> -FloatingType stringToNumber(const CharType *string, int base = 10) -{ - std::basic_stringstream ss; - ss << std::setbase(base) << string; - FloatingType result; - if ((ss >> result) && ss.eof()) { - return result; - } - std::string errorMsg; - errorMsg.reserve(42 + std::char_traits::length(string)); - errorMsg += "The string \""; - errorMsg += string; - errorMsg += "\" is no valid floating number."; - throw ConversionException(errorMsg); -} - /*! * \brief Converts the given \a string of \a size characters to an unsigned numeric value using the specified \a base. * \tparam IntegralType The data type used to store the converted value. @@ -663,36 +544,6 @@ IntegralType bufferToNumber(const CharType *string, std::size_t size, BaseType b return result; } -/*! - * \brief Converts the given null-terminated \a string to a signed numeric value using the specified \a base. - * \tparam IntegralType The data type used to store the converted value. - * \tparam CharType The character type. - * \throws A ConversionException will be thrown if the provided \a string is not a valid number. - * \sa numberToString(), bufferToNumber() - */ -template , std::is_signed> * = nullptr> -IntegralType stringToNumber(const CharType *string, IntegralType base = 10) -{ - if (!*string) { - return 0; - } - for (; *string && *string == ' '; ++string) - ; - if (!*string) { - return 0; - } - const bool negative = (*string == '-'); - if (negative) { - ++string; - } - IntegralType result = 0; - for (; *string; ++string) { - Detail::raiseAndAdd(result, base, *string); - } - return negative ? -result : result; -} - /*! * \brief Converts the given \a string of \a size characters to a signed numeric value using the specified \a base. * \tparam IntegralType The data type used to store the converted value. @@ -724,6 +575,128 @@ IntegralType bufferToNumber(const CharType *string, std::size_t size, BaseType b return negative ? -result : result; } +/*! + * \brief Converts the given \a string to an unsigned/signed number assuming \a string uses the specified \a base. + * \tparam IntegralType The data type used to store the converted value. + * \tparam StringType The string type (should be an instantiation of the basic_string class template). + * \throws A ConversionException will be thrown if the provided \a string is not a valid number. + * \sa numberToString(), bufferToNumber() + */ +template , Traits::Not>>> * = nullptr> +IntegralType stringToNumber(const StringType &string, BaseType base = 10) +{ + return bufferToNumber(string.data(), string.size(), base); +} + +/*! + * \brief Converts the given \a stringView to a number assuming \a stringView uses the specified \a base. + * \tparam FloatingType The data type used to store the converted value. + * \tparam StringViewType The string view type (must be an instantiation of the basic_string_view class template). + * \throws A ConversionException will be thrown if the provided \a string is not a valid number. + * \remarks This function is using std::basic_stringstream interanlly and hence also has its limitations (eg. regarding + * \a base and types). + * \sa numberToString(), bufferToNumber() + */ +template , Traits::IsSpecializationOf> * = nullptr> +FloatingType stringToNumber(StringViewType stringView, int base = 10) +{ + std::basic_stringstream ss; + ss << std::setbase(base) << stringView; + FloatingType result; + if ((ss >> result) && ss.eof()) { + return result; + } + std::string errorMsg; + errorMsg.reserve(48 + stringView.size()); + errorMsg += "The string \""; + errorMsg += stringView; + errorMsg += "\" is no valid floating point number."; + throw ConversionException(errorMsg); +} + +/*! + * \brief Converts the given \a string to a number assuming \a string uses the specified \a base. + * \tparam FloatingType The data type used to store the converted value. + * \tparam StringType The string type (should be an instantiation of the basic_string class template). + * \throws A ConversionException will be thrown if the provided \a string is not a valid number. + * \remarks This function is using std::basic_stringstream interanlly and hence also has its limitations (eg. regarding + * \a base and types). + * \sa numberToString(), bufferToNumber() + */ +template , Traits::Not>>, + Traits::Not>> * = nullptr> +FloatingType stringToNumber(const StringType &string, int base = 10) +{ + using StringViewType = std::basic_string_view; + return stringToNumber(StringViewType(string.data(), string.size()), base); +} + +/*! + * \brief Converts the given null-terminated \a string to an unsigned numeric value using the specified \a base. + * \tparam IntegralType The data type used to store the converted value. + * \tparam CharType The character type. + * \throws A ConversionException will be thrown if the provided \a string is not a valid number. + * \sa numberToString(), bufferToNumber() + */ +template , std::is_unsigned> * = nullptr> +IntegralType stringToNumber(const CharType *string, BaseType base = 10) +{ + IntegralType result = 0; + for (; *string; ++string) { + Detail::raiseAndAdd(result, base, *string); + } + return result; +} + +/*! + * \brief Converts the given null-terminated \a string to a number assuming \a string uses the specified \a base. + * \tparam FloatingType The data type used to store the converted value. + * \tparam CharType The character type. + * \throws A ConversionException will be thrown if the provided \a string is not a valid number. + * \remarks This function is using std::basic_stringstream interanlly and hence also has its limitations (eg. regarding + * \a base and types). + * \sa numberToString(), bufferToNumber() + */ +template > * = nullptr> +FloatingType stringToNumber(const CharType *string, int base = 10) +{ + return stringToNumber>(string, base); +} + +/*! + * \brief Converts the given null-terminated \a string to a signed numeric value using the specified \a base. + * \tparam IntegralType The data type used to store the converted value. + * \tparam CharType The character type. + * \throws A ConversionException will be thrown if the provided \a string is not a valid number. + * \sa numberToString(), bufferToNumber() + */ +template , std::is_signed> * = nullptr> +IntegralType stringToNumber(const CharType *string, IntegralType base = 10) +{ + if (!*string) { + return 0; + } + for (; *string && *string == ' '; ++string) + ; + if (!*string) { + return 0; + } + const bool negative = (*string == '-'); + if (negative) { + ++string; + } + IntegralType result = 0; + for (; *string; ++string) { + Detail::raiseAndAdd(result, base, *string); + } + return negative ? -result : result; +} + /*! * \brief Interprets the given \a integer at the specified position as std::string using the specified byte order. * diff --git a/tests/conversiontests.cpp b/tests/conversiontests.cpp index 6c7cde2..7534d6f 100644 --- a/tests/conversiontests.cpp +++ b/tests/conversiontests.cpp @@ -292,6 +292,11 @@ void ConversionTests::testStringConversions() CPPUNIT_ASSERT_EQUAL_MESSAGE("negative limit", -2147483647, stringToNumber("-2147483647", 10)); #endif + // stringToNumber() / numberToString() with floating point numbers + CPPUNIT_ASSERT_EQUAL(1.5f, stringToNumber(numberToString(1.5f))); + CPPUNIT_ASSERT_EQUAL(1.5, stringToNumber(numberToString(1.5))); + CPPUNIT_ASSERT_EQUAL(-10.25, stringToNumber("-10.25")); + // interpretIntegerAsString() CPPUNIT_ASSERT_EQUAL("TEST"s, interpretIntegerAsString(0x54455354));