Browse Source

string to int: Allow specifying string size

testing/bash_completion_debugging
Martchus 5 years ago
parent
commit
28f37bbbcd
  1. 4
      CMakeLists.txt
  2. 75
      conversion/stringconversion.h
  3. 25
      tests/conversiontests.cpp

4
CMakeLists.txt

@ -121,8 +121,8 @@ set(META_APP_AUTHOR "Martchus")
set(META_APP_URL "https://github.com/${META_APP_AUTHOR}/${META_PROJECT_NAME}")
set(META_APP_DESCRIPTION "Common C++ classes and routines used by my applications such as argument parser, IO and conversion utilities")
set(META_VERSION_MAJOR 4)
set(META_VERSION_MINOR 8)
set(META_VERSION_PATCH 1)
set(META_VERSION_MINOR 9)
set(META_VERSION_PATCH 0)
# find required 3rd party libraries
include(3rdParty)

75
conversion/stringconversion.h

@ -301,7 +301,7 @@ StringType numberToString(IntegralType number, typename StringType::value_type b
* \tparam StringType The string type (should be an instantiation of the basic_string class template).
* \remarks This function is using std::basic_stringstream interanlly and hence also has its limitations (eg. regarding
* \a base and types).
* \sa stringToNumber()
* \sa stringToNumber(), bufferToNumber()
*/
template <typename FloatingType, class StringType = std::string, Traits::EnableIf<std::is_floating_point<FloatingType>>...>
StringType numberToString(FloatingType number, typename StringType::value_type base = 10)
@ -334,11 +334,11 @@ template <typename CharType> CharType charToDigit(CharType character, CharType b
}
/*!
* \brief Converts the given \a string to a number assuming \a string uses the specified \a base.
* \brief Converts the given \a string to an unsigned number assuming \a string uses the specified \a base.
* \tparam NumberType 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()
* \sa numberToString(), bufferToNumber()
*/
template <typename IntegralType, class StringType, Traits::EnableIf<std::is_integral<IntegralType>, Traits::Not<std::is_signed<IntegralType>>>...>
IntegralType stringToNumber(const StringType &string, typename StringType::value_type base = 10)
@ -355,11 +355,11 @@ IntegralType stringToNumber(const StringType &string, typename StringType::value
}
/*!
* \brief Converts the given \a string to a number assuming \a string uses the specified \a base.
* \brief Converts the given \a string to a signed number assuming \a string uses the specified \a base.
* \tparam NumberType 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()
* \sa numberToString(), bufferToNumber()
*/
template <typename IntegralType, class StringType, Traits::EnableIf<std::is_integral<IntegralType>, std::is_signed<IntegralType>>...>
IntegralType stringToNumber(const StringType &string, typename StringType::value_type base = 10)
@ -393,7 +393,7 @@ IntegralType stringToNumber(const StringType &string, typename StringType::value
* \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()
* \sa numberToString(), bufferToNumber()
*/
template <typename FloatingType, class StringType, Traits::EnableIf<std::is_floating_point<FloatingType>>...>
FloatingType stringToNumber(const StringType &string, typename StringType::value_type base = 10)
@ -409,11 +409,11 @@ FloatingType stringToNumber(const StringType &string, typename StringType::value
}
/*!
* \brief Converts the given null-terminated \a string to a numeric value using the specified \a base.
* \brief Converts the given null-terminated \a string to an unsigned numeric value using the specified \a base.
* \tparam NumberType 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()
* \sa numberToString(), bufferToNumber()
*/
template <typename IntegralType, class CharType, Traits::EnableIf<std::is_integral<IntegralType>, Traits::Not<std::is_signed<IntegralType>>>...>
IntegralType stringToNumber(const CharType *string, unsigned char base = 10)
@ -430,11 +430,32 @@ IntegralType stringToNumber(const CharType *string, unsigned char base = 10)
}
/*!
* \brief Converts the given null-terminated \a string to a numeric value using the specified \a base.
* \brief Converts the given \a string of \a size characters to an unsigned numeric value using the specified \a base.
* \tparam NumberType 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()
* \sa numberToString(), stringToNumber()
*/
template <typename IntegralType, class CharType, Traits::EnableIf<std::is_integral<IntegralType>, Traits::Not<std::is_signed<IntegralType>>>...>
IntegralType bufferToNumber(const CharType *string, std::size_t size, unsigned char base = 10)
{
IntegralType result = 0;
for (const CharType *end = string + size; string != end; ++string) {
if (*string == ' ') {
continue;
}
result *= base;
result += charToDigit<CharType>(*string, base);
}
return result;
}
/*!
* \brief Converts the given null-terminated \a string to a signed numeric value using the specified \a base.
* \tparam NumberType 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 <typename IntegralType, class CharType, Traits::EnableIf<std::is_integral<IntegralType>, std::is_signed<IntegralType>>...>
IntegralType stringToNumber(const CharType *string, unsigned char base = 10)
@ -462,6 +483,40 @@ IntegralType stringToNumber(const CharType *string, unsigned char base = 10)
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 NumberType 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(), stringToNumber()
*/
template <typename IntegralType, class CharType, Traits::EnableIf<std::is_integral<IntegralType>, std::is_signed<IntegralType>>...>
IntegralType bufferToNumber(const CharType *string, std::size_t size, unsigned char base = 10)
{
if (!size) {
return 0;
}
const CharType *end = string + size;
for (; string != end && *string == ' '; ++string)
;
if (string == end) {
return 0;
}
const bool negative = (*string == '-');
if (negative) {
++string;
}
IntegralType result = 0;
for (; string != end; ++string) {
if (*string == ' ') {
continue;
}
result *= base;
result += charToDigit<CharType>(*string, base);
}
return negative ? -result : result;
}
/*!
* \brief Interprets the given \a integer at the specified position as std::string using the specified byte order.
*

25
tests/conversiontests.cpp

@ -228,24 +228,27 @@ void ConversionTests::testStringEncodingConversions()
void ConversionTests::testStringConversions()
{
// stringToNumber() / numberToString() with zero and random numbers
CPPUNIT_ASSERT_EQUAL(string("0"), numberToString<unsigned int>(0));
CPPUNIT_ASSERT_EQUAL(string("0"), numberToString<signed int>(0));
CPPUNIT_ASSERT_EQUAL("0"s, numberToString<unsigned int>(0));
CPPUNIT_ASSERT_EQUAL("0"s, numberToString<signed int>(0));
uniform_int_distribution<int64> randomDistSigned(numeric_limits<int64>::min());
uniform_int_distribution<uint64> randomDistUnsigned(0);
const string stringMsg("string"), wideStringMsg("wide string"), bufferMsg("buffer");
for (byte b = 1; b < 100; ++b) {
auto signedRandom = randomDistSigned(m_randomEngine);
auto unsignedRandom = randomDistUnsigned(m_randomEngine);
for (const auto base : initializer_list<byte>{ 2, 8, 10, 16 }) {
auto resultString = stringToNumber<uint64, string>(numberToString<uint64, string>(unsignedRandom, base), base);
auto resultWideString = stringToNumber<uint64, wstring>(numberToString<uint64, wstring>(unsignedRandom, base), base);
CPPUNIT_ASSERT_EQUAL(unsignedRandom, resultString);
CPPUNIT_ASSERT_EQUAL(unsignedRandom, resultWideString);
const auto asString = numberToString<uint64, string>(unsignedRandom, static_cast<string::value_type>(base));
const auto asWideString = numberToString<uint64, wstring>(unsignedRandom, base);
CPPUNIT_ASSERT_EQUAL_MESSAGE(stringMsg, unsignedRandom, stringToNumber<uint64>(asString, static_cast<string::value_type>(base)));
CPPUNIT_ASSERT_EQUAL_MESSAGE(wideStringMsg, unsignedRandom, stringToNumber<uint64>(asWideString, base));
CPPUNIT_ASSERT_EQUAL_MESSAGE(bufferMsg, unsignedRandom, bufferToNumber<uint64>(asString.data(), asString.size(), base));
}
for (const auto base : initializer_list<byte>{ 10 }) {
auto resultString = stringToNumber<int64, string>(numberToString<int64, string>(signedRandom, base), base);
auto resultWideString = stringToNumber<int64, wstring>(numberToString<int64, wstring>(signedRandom, base), base);
CPPUNIT_ASSERT_EQUAL(signedRandom, resultString);
CPPUNIT_ASSERT_EQUAL(signedRandom, resultWideString);
const auto asString = numberToString<int64, string>(signedRandom, static_cast<string::value_type>(base));
const auto asWideString = numberToString<int64, wstring>(signedRandom, base);
CPPUNIT_ASSERT_EQUAL_MESSAGE(stringMsg, signedRandom, stringToNumber<int64>(asString, static_cast<string::value_type>(base)));
CPPUNIT_ASSERT_EQUAL_MESSAGE(wideStringMsg, signedRandom, stringToNumber<int64>(asWideString, base));
CPPUNIT_ASSERT_EQUAL_MESSAGE(bufferMsg, signedRandom, bufferToNumber<int64>(asString.data(), asString.size(), base));
}
}
@ -254,10 +257,12 @@ void ConversionTests::testStringConversions()
CPPUNIT_ASSERT_EQUAL(1, stringToNumber<int32>(L"01"s));
CPPUNIT_ASSERT_EQUAL(1, stringToNumber<int32>(u"01"s));
CPPUNIT_ASSERT_EQUAL(-23, stringToNumber<int32>(" - 023"s));
CPPUNIT_ASSERT_EQUAL(-23, bufferToNumber<int32>(" - 023", 6));
CPPUNIT_ASSERT_EQUAL(1u, stringToNumber<uint32>("01"));
CPPUNIT_ASSERT_EQUAL(1u, stringToNumber<uint32>(L"01"s));
CPPUNIT_ASSERT_EQUAL(1u, stringToNumber<uint32>(u"01"s));
CPPUNIT_ASSERT_EQUAL(23u, stringToNumber<uint32>(" 023"s));
CPPUNIT_ASSERT_EQUAL(23u, bufferToNumber<uint32>(" 023", 5));
// interpretIntegerAsString()
CPPUNIT_ASSERT_EQUAL("TEST"s, interpretIntegerAsString<uint32>(0x54455354));

Loading…
Cancel
Save