From 6746c4244f034f07fef87c986a19584a3ddc3fb9 Mon Sep 17 00:00:00 2001 From: John Wellbelove Date: Sat, 24 Sep 2022 13:13:06 +0100 Subject: [PATCH] Work-In-Progress Function parameter radix implementation --- include/etl/to_arithmetic.h | 485 ++++++++++++++++++++++------- test/test_string_to_arithmetic.cpp | 264 ++++++++++------ 2 files changed, 535 insertions(+), 214 deletions(-) diff --git a/include/etl/to_arithmetic.h b/include/etl/to_arithmetic.h index 4c9a75bc..97fb6e2a 100644 --- a/include/etl/to_arithmetic.h +++ b/include/etl/to_arithmetic.h @@ -1,6 +1,7 @@ #include "platform.h" #include "type_traits.h" +#include "integral_limits.h" #include "string_view.h" #include "basic_string.h" #include "format_spec.h" @@ -8,7 +9,6 @@ #include "optional.h" #include "string_utilities.h" #include "iterator.h" -#include "largest.h" #include "exception.h" #include "error_handler.h" @@ -56,11 +56,11 @@ namespace etl //*************************************************************************** /// //*************************************************************************** - class to_arithmetic_radix_not_supported : public to_arithmetic_exception + class to_arithmetic_invalid_radix : public to_arithmetic_exception { public: - to_arithmetic_radix_not_supported(string_type file_name_, numeric_type line_number_) + to_arithmetic_invalid_radix(string_type file_name_, numeric_type line_number_) : to_arithmetic_exception(ETL_ERROR_TEXT("to arithmetic:radix not supported", ETL_TO_ARITHMETIC_FILE_ID"C"), file_name_, line_number_) { } @@ -68,6 +68,9 @@ namespace etl namespace private_to_arithmetic { + //*********************************************************************** + /// + //*********************************************************************** template struct character_set; @@ -79,6 +82,8 @@ namespace etl static ETL_CONSTANT string_type numeric_chars = "0123456789abcdefABCDEF"; static ETL_CONSTANT value_type positive_char = '+'; static ETL_CONSTANT value_type negative_char = '-'; + static ETL_CONSTANT string_type radix_point = ".,"; + static ETL_CONSTANT string_type exponential = "eE"; }; template <> @@ -89,6 +94,8 @@ namespace etl static ETL_CONSTANT string_type numeric_chars = L"0123456789abcdefABCDEF"; static ETL_CONSTANT value_type positive_char = L'+'; static ETL_CONSTANT value_type negative_char = L'-'; + static ETL_CONSTANT string_type radix_point = L".,"; + static ETL_CONSTANT string_type exponential = L"eE"; }; template <> @@ -99,6 +106,8 @@ namespace etl static ETL_CONSTANT string_type numeric_chars = u"0123456789abcdefABCDEF"; static ETL_CONSTANT value_type positive_char = u'+'; static ETL_CONSTANT value_type negative_char = u'-'; + static ETL_CONSTANT string_type radix_point = u".,"; + static ETL_CONSTANT string_type exponential = u"eE"; }; template <> @@ -109,6 +118,8 @@ namespace etl static ETL_CONSTANT string_type numeric_chars = U"0123456789abcdefABCDEF"; static ETL_CONSTANT value_type positive_char = U'+'; static ETL_CONSTANT value_type negative_char = U'-'; + static ETL_CONSTANT string_type radix_point = U".,"; + static ETL_CONSTANT string_type exponential = U"eE"; }; static ETL_CONSTANT char binary_length = 2; @@ -116,8 +127,12 @@ namespace etl static ETL_CONSTANT char decimal_length = 10; static ETL_CONSTANT char hex_length = 16 + 6; - //******************************* + //*************************************************************************** + /// + //*************************************************************************** template + ETL_NODISCARD + ETL_CONSTEXPR14 char get_digit_value(TChar c) { size_t length = etl::strlen(character_set::numeric_chars); @@ -137,112 +152,236 @@ namespace etl /// //*************************************************************************** template - ETL_CONSTEXPR14 bool is_valid_numeric_character(const TChar c, - const etl::basic_string_view& valid_characters) + ETL_NODISCARD + ETL_CONSTEXPR14 + etl::basic_string_view get_character_set(const etl::radix::value_type radix) { - using namespace etl::private_to_arithmetic; + switch (radix) + { + case etl::radix::binary: { return etl::basic_string_view(character_set::numeric_chars, binary_length); break; } + case etl::radix::octal: { return etl::basic_string_view(character_set::numeric_chars, octal_length); break; } + case etl::radix::decimal: { return etl::basic_string_view(character_set::numeric_chars, decimal_length); break; } + case etl::radix::hex: { return etl::basic_string_view(character_set::numeric_chars, hex_length); break; } + default: { ETL_ASSERT_FAIL(ETL_ERROR(etl::to_arithmetic_invalid_radix)); return etl::basic_string_view(); break; } + } + } + //*************************************************************************** + /// + //*************************************************************************** + template + ETL_NODISCARD + ETL_CONSTEXPR14 + bool is_valid_numeric_character(const TChar c, + const etl::basic_string_view& valid_characters) + { etl::basic_string_view itr = etl::find(valid_characters.begin(), valid_characters.end(), c); return (itr != valid_characters.end()); } //*************************************************************************** -/// -//*************************************************************************** - template - ETL_CONSTEXPR14 T accumulate_value(T value, const char digit, const bool is_negative, int shift, const etl::radix::value_type radix) + /// + //*************************************************************************** + template + ETL_NODISCARD + ETL_CONSTEXPR14 + bool is_valid_decimal_character(const TChar c) { - switch (radix) - { - case etl::radix::decimal: - { - value *= radix; - is_negative ? value -= digit : value += digit; - break; - } + return (c >= character_set::numeric_chars[0]) && (c <= character_set::numeric_chars[9]); + } - default: // Binary, octal or hex. + //*************************************************************************** + /// + //*************************************************************************** + template + struct view_information + { + ETL_CONSTEXPR14 + view_information() + : valid_characters() + { + } + + etl::basic_string_view valid_characters; + }; + + //********************************* + struct numeric_information + { + ETL_CONSTEXPR14 + numeric_information() + : digit(0) + , is_negative(false) + , radix(0) + , radix_point_position(etl::npos) + , exponential_position(etl::npos) + { + } + + char digit; + bool is_negative; + etl::radix::value_type radix; + size_t radix_point_position; + size_t exponential_position; + }; + + //*************************************************************************** + /// + //*************************************************************************** + template + ETL_NODISCARD + ETL_CONSTEXPR14 + bool validate_information_from_view(etl::basic_string_view& view, etl::radix::value_type radix, view_information& view_info, numeric_information& numeric_info) + { + numeric_info.radix = radix; + view_info.valid_characters = get_character_set(numeric_info.radix); + + bool is_valid = !view_info.valid_characters.empty(); + + if (is_valid) + { + // Look for a prefix. + const bool has_positive_prefix = (view[0] == character_set::positive_char); + numeric_info.is_negative = (view[0] == character_set::negative_char); + + if (has_positive_prefix || numeric_info.is_negative) { - value <<= shift; - value = value | digit; - break; + view.remove_prefix(1U); + is_valid = (view.begin() != view.end()); } } + if (is_valid) + { + // Look for a radix point. + numeric_info.radix_point_position = view.find_first_of(character_set::radix_point); + + // Look for an exponential. + numeric_info.exponential_position = view.find_first_of(character_set::exponential); + } + + ETL_ASSERT(is_valid, ETL_ERROR(etl::to_arithmetic_invalid_format)); + + return is_valid; + } + + //*************************************************************************** + /// + //*************************************************************************** + template + ETL_NODISCARD + ETL_CONSTEXPR14 + typename etl::enable_if::value && etl::is_unsigned::value, TValue>::type + accumulate_value(TValue value, const numeric_information& info) + { + value *= info.radix; + value += info.digit; + + return value; + } + + //*************************************************************************** + /// + //*************************************************************************** + template + ETL_NODISCARD + ETL_CONSTEXPR14 + typename etl::enable_if::value && etl::is_signed::value, TValue>::type + accumulate_value(TValue value, const numeric_information& info) + { + value *= info.radix; + info.is_negative ? value -= info.digit : value += info.digit; + + return value; + } + + //*************************************************************************** + /// + //*************************************************************************** + template + ETL_NODISCARD + ETL_CONSTEXPR14 + typename etl::enable_if::value, TValue>::type + accumulate_integral_part(TValue value, const numeric_information& info) + { + value *= info.radix; + info.is_negative ? value -= info.digit : value += info.digit; + + return value; + } + + //*************************************************************************** + /// + //*************************************************************************** + template + ETL_NODISCARD + ETL_CONSTEXPR14 + typename etl::enable_if::value, TValue>::type + accumulate_fractional_part(TValue value, const numeric_information& info) + { + value /= info.radix; + TValue d = TValue(info.digit) / info.radix; + info.is_negative ? value -= d : value += d; + return value; } } //*************************************************************************** - /// + /// Text to integral from view and radix value type. //*************************************************************************** - template - ETL_CONSTEXPR14 typename etl::enable_if::value, etl::optional >::type + template + ETL_NODISCARD + ETL_CONSTEXPR14 + typename etl::enable_if::value, etl::optional >::type to_arithmetic(etl::basic_string_view view, const etl::radix::value_type radix) { using namespace etl::private_to_arithmetic; - etl::optional result; - - bool finished_parsing = false; - + etl::optional result; etl::basic_string_view valid_characters; + view_information view_info; + numeric_information numeric_info; - switch (radix) + bool parsing = validate_information_from_view(view, radix, view_info, numeric_info); + + if (parsing) { - case etl::radix::binary: { valid_characters = etl::basic_string_view(character_set::numeric_chars, binary_length); break; } - case etl::radix::octal: { valid_characters = etl::basic_string_view(character_set::numeric_chars, octal_length); break; } - case etl::radix::decimal: { valid_characters = etl::basic_string_view(character_set::numeric_chars, decimal_length); break; } - case etl::radix::hex: { valid_characters = etl::basic_string_view(character_set::numeric_chars, hex_length); break; } - default: { ETL_ASSERT_FAIL(ETL_ERROR(etl::to_arithmetic_radix_not_supported)); finished_parsing = false; break; } - } - - if (!finished_parsing) - { - T value = 0; - - // Only used for binary, octal and hex. - int shift = (radix == etl::radix::binary) ? 1 : (radix == etl::radix::octal) ? 3 : 4; - - etl::basic_string_view::const_iterator itr = view.begin(); - - // Search for a prefix. - const bool has_positive_prefix = (*itr == character_set::positive_char); - const bool has_negative_prefix = (*itr == character_set::negative_char); - - if (has_positive_prefix || has_negative_prefix) + if (etl::is_unsigned::value && numeric_info.is_negative) { - ++itr; + parsing = false; + ETL_ASSERT_FAIL(ETL_ERROR(etl::to_arithmetic_signed_to_unsigned)); } - // Negative prefix is only allowed with decimals. - if (has_negative_prefix && (radix != etl::radix::decimal)) + if (parsing) { - ETL_ASSERT_FAIL(ETL_ERROR(etl::to_arithmetic_invalid_format)); - finished_parsing = true; - } - - // Parse the numeric part. - while (!finished_parsing) - { - if (is_valid_numeric_character(*itr, valid_characters)) + // Parse the numeric part. + TValue value = 0; + + etl::basic_string_view::const_iterator itr = view.begin(); + + while (parsing) { - value = accumulate_value(value, get_digit_value(*itr), has_negative_prefix, shift, radix); - - ++itr; - - if (itr == view.end()) + if (is_valid_numeric_character(*itr, view_info.valid_characters)) { - result = value; - finished_parsing = true; + numeric_info.digit = get_digit_value(*itr); + value = accumulate_value(value, numeric_info); + + ++itr; + + if (itr == view.end()) + { + result = value; + parsing = false; + } + } + else + { + // Character was not a valid numeric, so fail. + ETL_ASSERT_FAIL(ETL_ERROR(etl::to_arithmetic_invalid_format)); + parsing = false; } - } - else - { - // Character was not a valid numeric, so fail. - ETL_ASSERT_FAIL(ETL_ERROR(etl::to_arithmetic_invalid_format)); - finished_parsing = true; } } } @@ -251,89 +390,207 @@ namespace etl } //*************************************************************************** - /// + /// Text to integral from view and default decimal radix. //*************************************************************************** - template - ETL_CONSTEXPR14 typename etl::enable_if::value, etl::optional >::type + template + ETL_NODISCARD + ETL_CONSTEXPR14 + typename etl::enable_if::value, etl::optional >::type to_arithmetic(const etl::basic_string_view& view) { - return etl::to_arithmetic(view, etl::radix::decimal); + return etl::to_arithmetic(view, etl::radix::decimal); } //*************************************************************************** - /// + /// Text to integral from view and radix format spec. //*************************************************************************** - template - ETL_CONSTEXPR14 typename etl::enable_if::value, etl::optional >::type + template + ETL_NODISCARD + ETL_CONSTEXPR14 + typename etl::enable_if::value, etl::optional >::type to_arithmetic(const etl::basic_string_view& view, const etl::basic_format_spec >& spec) { - return etl::to_arithmetic(view, spec.get_base()); + return etl::to_arithmetic(view, spec.get_base()); } //*************************************************************************** - /// + /// Text to integral from pointer, length and radix value type. //*************************************************************************** - template - ETL_CONSTEXPR14 typename etl::enable_if::value, etl::optional >::type + template + ETL_NODISCARD + ETL_CONSTEXPR14 + typename etl::enable_if::value, etl::optional >::type to_arithmetic(const TChar* cp, size_t length, const etl::radix::value_type radix) { - return etl::to_arithmetic(etl::basic_string_view(cp, length), radix); + return etl::to_arithmetic(etl::basic_string_view(cp, length), radix); } //*************************************************************************** - /// + /// Text to integral from pointer, length and default decimal radix. //*************************************************************************** - template - ETL_CONSTEXPR14 typename etl::enable_if::value, etl::optional >::type + template + ETL_NODISCARD + ETL_CONSTEXPR14 typename etl::enable_if::value, etl::optional >::type to_arithmetic(const TChar* cp, size_t length) { - return etl::to_arithmetic(etl::basic_string_view(cp, length), etl::radix::decimal);; + return etl::to_arithmetic(etl::basic_string_view(cp, length), etl::radix::decimal);; } //*************************************************************************** - /// + /// Text to integral from pointer, length and radix format spec. //*************************************************************************** - template - ETL_CONSTEXPR14 typename etl::enable_if::value, etl::optional >::type + template + ETL_NODISCARD + ETL_CONSTEXPR14 typename etl::enable_if::value, etl::optional >::type to_arithmetic(const TChar* cp, size_t length, const typename etl::private_basic_format_spec::base_spec& spec) { - return etl::to_arithmetic(etl::basic_string_view(cp, length), spec.base);; + return etl::to_arithmetic(etl::basic_string_view(cp, length), spec.base);; } //*************************************************************************** - /// + /// Text to integral from string and radix value type. //*************************************************************************** - template - ETL_CONSTEXPR14 typename etl::enable_if::value, etl::optional >::type + template + ETL_NODISCARD + ETL_CONSTEXPR14 typename etl::enable_if::value, etl::optional >::type to_arithmetic(const etl::ibasic_string& str, const etl::radix::value_type radix) { - return etl::to_arithmetic(etl::basic_string_view(str), radix);; + return etl::to_arithmetic(etl::basic_string_view(str), radix);; } //*************************************************************************** - /// + /// Text to integral from string and default decimal radix. //*************************************************************************** - template - ETL_CONSTEXPR14 typename etl::enable_if::value, etl::optional >::type + template + ETL_NODISCARD + ETL_CONSTEXPR14 typename etl::enable_if::value, etl::optional >::type to_arithmetic(const etl::ibasic_string& str) { - return etl::to_arithmetic(etl::basic_string_view(str), radix);; + return etl::to_arithmetic(etl::basic_string_view(str), etl::radix::decimal);; } //*************************************************************************** - /// + /// Text to integral from string and radix format spec. //*************************************************************************** - template - ETL_CONSTEXPR14 typename etl::enable_if::value, etl::optional >::type + template + ETL_NODISCARD + ETL_CONSTEXPR14 typename etl::enable_if::value, etl::optional >::type to_arithmetic(const etl::ibasic_string& str, const etl::basic_format_spec >& spec) { - return etl::to_arithmetic(etl::basic_string_view(str), spec);; + return etl::to_arithmetic(etl::basic_string_view(str), spec);; } - //template - //ETL_CONSTEXPR14 typename etl::enable_if::value, etl::optional >::type - // to_arithmetic(etl::basic_string_view view, const etl::radix::value_type radix) - //{ - // return to_floating_point(view, radix); - //} + //*************************************************************************** + /// Floating point from view. + //*************************************************************************** + template + ETL_NODISCARD + ETL_CONSTEXPR14 typename etl::enable_if::value, etl::optional >::type + to_arithmetic(etl::basic_string_view view) + { + using namespace etl::private_to_arithmetic; + + etl::optional result; + etl::basic_string_view valid_characters; + view_information view_info; + numeric_information numeric_info; + + bool parsing = validate_information_from_view(view, etl::radix::decimal, view_info, numeric_info); + + if (parsing) + { + // Integral part. + etl::basic_string_view::const_iterator itr_integral_begin = view.begin(); + etl::basic_string_view::const_iterator itr_integral_end = (numeric_info.radix_point_position == etl::npos) + ? view.end() + : itr_integral_begin + numeric_info.radix_point_position; + + TValue intergal_value = 0; + + while (itr_integral_begin != itr_integral_end) + { + if (is_valid_decimal_character(*itr_integral_begin)) + { + numeric_info.digit = get_digit_value(*itr_integral_begin); + intergal_value = accumulate_integral_part(intergal_value, numeric_info); + ++itr_integral_begin; + } + else + { + // Character was not a valid numeric, so fail. + ETL_ASSERT_FAIL(ETL_ERROR(etl::to_arithmetic_invalid_format)); + parsing = false; + itr_integral_begin = itr_integral_end; + } + } + + // Fractional part. + etl::basic_string_view::const_reverse_iterator itr_fractional_end = ETL_OR_STD::reverse_iterator(itr_integral_begin + 1); + etl::basic_string_view::const_reverse_iterator itr_fractional_begin = (numeric_info.radix_point_position == etl::npos) + ? itr_fractional_end + : (numeric_info.exponential_position == etl::npos) + ? view.rbegin() + : ETL_OR_STD::reverse_iterator(view.begin() + numeric_info.exponential_position); + + TValue fractional_value = 0; + + while (itr_fractional_begin != itr_fractional_end) + { + if (is_valid_decimal_character(*itr_fractional_begin)) + { + numeric_info.digit = get_digit_value(*itr_fractional_begin); + fractional_value = accumulate_fractional_part(fractional_value, numeric_info); + ++itr_fractional_begin; + } + else + { + // Character was not a valid numeric, so fail. + ETL_ASSERT_FAIL(ETL_ERROR(etl::to_arithmetic_invalid_format)); + parsing = false; + itr_fractional_begin = itr_fractional_end; + } + } + + // Exponetial part. + etl::basic_string_view::const_iterator itr_exponential_end = view.end(); + etl::basic_string_view::const_iterator itr_exponential_begin = (numeric_info.exponential_position == etl::npos) + ? view.end() + : view.begin() + numeric_info.exponential_position + 1; + + //optional exponential_value = to_arithmetic(etl::basic_string_view(itr_exponential_begin, itr_exponential_end)); + + // Combine the integral and fractional parts. + TValue value = 0; + + if (parsing) + { + value = intergal_value + fractional_value; + result = value; + } + } + + return result; + } + + //*************************************************************************** + /// Floating point from pointer and length. + //*************************************************************************** + template + ETL_NODISCARD + ETL_CONSTEXPR14 typename etl::enable_if::value, etl::optional >::type + to_arithmetic(const TChar* cp, size_t length) + { + return etl::to_arithmetic(etl::basic_string_view(cp, length)); + } + + //*************************************************************************** + /// Floating point from string. + //*************************************************************************** + template + ETL_NODISCARD + ETL_CONSTEXPR14 typename etl::enable_if::value, etl::optional >::type + to_arithmetic(const etl::ibasic_string& str) + { + return etl::to_arithmetic(etl::basic_string_view(str)); + } } diff --git a/test/test_string_to_arithmetic.cpp b/test/test_string_to_arithmetic.cpp index 8519dfd9..e5b2d383 100644 --- a/test/test_string_to_arithmetic.cpp +++ b/test/test_string_to_arithmetic.cpp @@ -48,35 +48,37 @@ namespace //************************************************************************* TEST(test_invalid_radixes) { - const char* decimal = "128"; - CHECK_THROW(etl::to_arithmetic(decimal, strlen(decimal), 0), etl::to_arithmetic_radix_not_supported); - CHECK_THROW(etl::to_arithmetic(decimal, strlen(decimal), 1), etl::to_arithmetic_radix_not_supported); - CHECK_THROW(etl::to_arithmetic(decimal, strlen(decimal), 3), etl::to_arithmetic_radix_not_supported); - CHECK_THROW(etl::to_arithmetic(decimal, strlen(decimal), 4), etl::to_arithmetic_radix_not_supported); - CHECK_THROW(etl::to_arithmetic(decimal, strlen(decimal), 5), etl::to_arithmetic_radix_not_supported); - CHECK_THROW(etl::to_arithmetic(decimal, strlen(decimal), 6), etl::to_arithmetic_radix_not_supported); - CHECK_THROW(etl::to_arithmetic(decimal, strlen(decimal), 7), etl::to_arithmetic_radix_not_supported); - CHECK_THROW(etl::to_arithmetic(decimal, strlen(decimal), 9), etl::to_arithmetic_radix_not_supported); - CHECK_THROW(etl::to_arithmetic(decimal, strlen(decimal), 11), etl::to_arithmetic_radix_not_supported); - CHECK_THROW(etl::to_arithmetic(decimal, strlen(decimal), 12), etl::to_arithmetic_radix_not_supported); - CHECK_THROW(etl::to_arithmetic(decimal, strlen(decimal), 13), etl::to_arithmetic_radix_not_supported); - CHECK_THROW(etl::to_arithmetic(decimal, strlen(decimal), 14), etl::to_arithmetic_radix_not_supported); - CHECK_THROW(etl::to_arithmetic(decimal, strlen(decimal), 15), etl::to_arithmetic_radix_not_supported); - CHECK_THROW(etl::to_arithmetic(decimal, strlen(decimal), 17), etl::to_arithmetic_radix_not_supported); + const std::string text("128"); + CHECK_THROW((void)etl::to_arithmetic(text.c_str(), text.size(), 0), etl::to_arithmetic_invalid_radix); + CHECK_THROW((void)etl::to_arithmetic(text.c_str(), text.size(), 1), etl::to_arithmetic_invalid_radix); + CHECK_THROW((void)etl::to_arithmetic(text.c_str(), text.size(), 3), etl::to_arithmetic_invalid_radix); + CHECK_THROW((void)etl::to_arithmetic(text.c_str(), text.size(), 4), etl::to_arithmetic_invalid_radix); + CHECK_THROW((void)etl::to_arithmetic(text.c_str(), text.size(), 5), etl::to_arithmetic_invalid_radix); + CHECK_THROW((void)etl::to_arithmetic(text.c_str(), text.size(), 6), etl::to_arithmetic_invalid_radix); + CHECK_THROW((void)etl::to_arithmetic(text.c_str(), text.size(), 7), etl::to_arithmetic_invalid_radix); + CHECK_THROW((void)etl::to_arithmetic(text.c_str(), text.size(), 9), etl::to_arithmetic_invalid_radix); + CHECK_THROW((void)etl::to_arithmetic(text.c_str(), text.size(), 11), etl::to_arithmetic_invalid_radix); + CHECK_THROW((void)etl::to_arithmetic(text.c_str(), text.size(), 12), etl::to_arithmetic_invalid_radix); + CHECK_THROW((void)etl::to_arithmetic(text.c_str(), text.size(), 13), etl::to_arithmetic_invalid_radix); + CHECK_THROW((void)etl::to_arithmetic(text.c_str(), text.size(), 14), etl::to_arithmetic_invalid_radix); + CHECK_THROW((void)etl::to_arithmetic(text.c_str(), text.size(), 15), etl::to_arithmetic_invalid_radix); + CHECK_THROW((void)etl::to_arithmetic(text.c_str(), text.size(), 17), etl::to_arithmetic_invalid_radix); } //************************************************************************* TEST(test_invalid_binary_numerics) { - const char* decimal1 = " 101"; - const char* decimal2 = "101 "; - const char* decimal3 = "121"; - const char* decimal4 = "-101"; + const std::string text1(" 101"); + const std::string text2("101 "); + const std::string text3("121"); + const std::string text4(""); + const std::string text5("-101"); - CHECK_THROW(etl::to_arithmetic(decimal1, strlen(decimal1), etl::bin), etl::to_arithmetic_invalid_format); - CHECK_THROW(etl::to_arithmetic(decimal2, strlen(decimal2), etl::bin), etl::to_arithmetic_invalid_format); - CHECK_THROW(etl::to_arithmetic(decimal3, strlen(decimal3), etl::bin), etl::to_arithmetic_invalid_format); - CHECK_THROW(etl::to_arithmetic(decimal4, strlen(decimal4), etl::bin), etl::to_arithmetic_invalid_format); + CHECK_THROW((void)etl::to_arithmetic(text1.c_str(), text1.size(), etl::bin), etl::to_arithmetic_invalid_format); + CHECK_THROW((void)etl::to_arithmetic(text2.c_str(), text2.size(), etl::bin), etl::to_arithmetic_invalid_format); + CHECK_THROW((void)etl::to_arithmetic(text3.c_str(), text3.size(), etl::bin), etl::to_arithmetic_invalid_format); + CHECK_THROW((void)etl::to_arithmetic(text4.c_str(), text4.size(), etl::bin), etl::to_arithmetic_invalid_format); + CHECK_THROW((void)etl::to_arithmetic(text5.c_str(), text5.size(), etl::bin), etl::to_arithmetic_signed_to_unsigned); } //************************************************************************* @@ -88,13 +90,15 @@ namespace const std::string value4("1010"); const std::string value5("01010011"); const std::string value6("10101100"); + const std::string value7("-01010011"); - CHECK_EQUAL(int(0), int(etl::to_arithmetic(value1.c_str(), value1.size(), etl::bin).value())); - CHECK_EQUAL(int(1), int(etl::to_arithmetic(value2.c_str(), value2.size(), etl::bin).value())); - CHECK_EQUAL(int(5), int(etl::to_arithmetic(value3.c_str(), value3.size(), etl::bin).value())); - CHECK_EQUAL(int(10), int(etl::to_arithmetic(value4.c_str(), value4.size(), etl::bin).value())); - CHECK_EQUAL(int(83), int(etl::to_arithmetic(value5.c_str(), value5.size(), etl::bin).value())); + CHECK_EQUAL(int(0), int(etl::to_arithmetic(value1.c_str(), value1.size(), etl::bin).value())); + CHECK_EQUAL(int(1), int(etl::to_arithmetic(value2.c_str(), value2.size(), etl::bin).value())); + CHECK_EQUAL(int(5), int(etl::to_arithmetic(value3.c_str(), value3.size(), etl::bin).value())); + CHECK_EQUAL(int(10), int(etl::to_arithmetic(value4.c_str(), value4.size(), etl::bin).value())); + CHECK_EQUAL(int(83), int(etl::to_arithmetic(value5.c_str(), value5.size(), etl::bin).value())); CHECK_EQUAL(int(-84), int(etl::to_arithmetic(value6.c_str(), value6.size(), etl::bin).value())); + CHECK_EQUAL(int(-83), int(etl::to_arithmetic(value7.c_str(), value7.size(), etl::bin).value())); } //************************************************************************* @@ -112,15 +116,15 @@ namespace //************************************************************************* TEST(test_invalid_octal_numerics) { - const char* decimal1 = " 127"; - const char* decimal2 = "127 "; - const char* decimal3 = "187"; - const char* decimal4 = "-127"; + const std::string text1(" 127"); + const std::string text2("127 "); + const std::string text3("187"); + const std::string text4("-187"); - CHECK_THROW(etl::to_arithmetic(decimal1, strlen(decimal1), etl::oct), etl::to_arithmetic_invalid_format); - CHECK_THROW(etl::to_arithmetic(decimal2, strlen(decimal2), etl::oct), etl::to_arithmetic_invalid_format); - CHECK_THROW(etl::to_arithmetic(decimal3, strlen(decimal3), etl::oct), etl::to_arithmetic_invalid_format); - CHECK_THROW(etl::to_arithmetic(decimal4, strlen(decimal4), etl::oct), etl::to_arithmetic_invalid_format); + CHECK_THROW((void)etl::to_arithmetic(text1.c_str(), text1.size(), etl::oct), etl::to_arithmetic_invalid_format); + CHECK_THROW((void)etl::to_arithmetic(text2.c_str(), text2.size(), etl::oct), etl::to_arithmetic_invalid_format); + CHECK_THROW((void)etl::to_arithmetic(text3.c_str(), text3.size(), etl::oct), etl::to_arithmetic_invalid_format); + CHECK_THROW((void)etl::to_arithmetic(text4.c_str(), text4.size(), etl::oct), etl::to_arithmetic_signed_to_unsigned); } //************************************************************************* @@ -132,13 +136,15 @@ namespace const std::string value4("12"); const std::string value5("123"); const std::string value6("254"); + const std::string value7("-123"); - CHECK_EQUAL(int(0), int(etl::to_arithmetic(value1.c_str(), value1.size(), etl::oct).value())); - CHECK_EQUAL(int(1), int(etl::to_arithmetic(value2.c_str(), value2.size(), etl::oct).value())); - CHECK_EQUAL(int(5), int(etl::to_arithmetic(value3.c_str(), value3.size(), etl::oct).value())); - CHECK_EQUAL(int(10), int(etl::to_arithmetic(value4.c_str(), value4.size(), etl::oct).value())); - CHECK_EQUAL(int(83), int(etl::to_arithmetic(value5.c_str(), value5.size(), etl::oct).value())); + CHECK_EQUAL(int(0), int(etl::to_arithmetic(value1.c_str(), value1.size(), etl::oct).value())); + CHECK_EQUAL(int(1), int(etl::to_arithmetic(value2.c_str(), value2.size(), etl::oct).value())); + CHECK_EQUAL(int(5), int(etl::to_arithmetic(value3.c_str(), value3.size(), etl::oct).value())); + CHECK_EQUAL(int(10), int(etl::to_arithmetic(value4.c_str(), value4.size(), etl::oct).value())); + CHECK_EQUAL(int(83), int(etl::to_arithmetic(value5.c_str(), value5.size(), etl::oct).value())); CHECK_EQUAL(int(-84), int(etl::to_arithmetic(value6.c_str(), value6.size(), etl::oct).value())); + CHECK_EQUAL(int(-83), int(etl::to_arithmetic(value7.c_str(), value7.size(), etl::oct).value())); } //************************************************************************* @@ -156,96 +162,154 @@ namespace //************************************************************************* TEST(test_invalid_decimal_numerics) { - const char* decimal1 = " 128"; - const char* decimal2 = "128 "; - const char* decimal3 = "1A8"; - const char* decimal4 = "++128"; - const char* decimal5 = "-+128"; - const char* decimal6 = "+-128"; - const char* decimal7 = "--128"; - const char* decimal8 = "-127"; + const std::string text1(" 128"); + const std::string text2("128 "); + const std::string text3("1A8"); + const std::string text4("++128"); + const std::string text5("-+128"); + const std::string text6("+-128"); + const std::string text7("--128"); + const std::string text8("+"); + const std::string text9("-"); + const std::string text10(""); - CHECK_THROW(etl::to_arithmetic(decimal1, strlen(decimal1), etl::dec), etl::to_arithmetic_invalid_format); - CHECK_THROW(etl::to_arithmetic(decimal2, strlen(decimal2), etl::dec), etl::to_arithmetic_invalid_format); - CHECK_THROW(etl::to_arithmetic(decimal3, strlen(decimal3), etl::dec), etl::to_arithmetic_invalid_format); - CHECK_THROW(etl::to_arithmetic(decimal4, strlen(decimal4), etl::dec), etl::to_arithmetic_invalid_format); - CHECK_THROW(etl::to_arithmetic(decimal5, strlen(decimal5), etl::dec), etl::to_arithmetic_invalid_format); - CHECK_THROW(etl::to_arithmetic(decimal6, strlen(decimal6), etl::dec), etl::to_arithmetic_invalid_format); - CHECK_THROW(etl::to_arithmetic(decimal7, strlen(decimal7), etl::dec), etl::to_arithmetic_invalid_format); + CHECK_THROW((void)etl::to_arithmetic(text1.c_str(), text1.size(), etl::dec), etl::to_arithmetic_invalid_format); + CHECK_THROW((void)etl::to_arithmetic(text2.c_str(), text2.size(), etl::dec), etl::to_arithmetic_invalid_format); + CHECK_THROW((void)etl::to_arithmetic(text3.c_str(), text3.size(), etl::dec), etl::to_arithmetic_invalid_format); + CHECK_THROW((void)etl::to_arithmetic(text4.c_str(), text4.size(), etl::dec), etl::to_arithmetic_invalid_format); + CHECK_THROW((void)etl::to_arithmetic(text5.c_str(), text5.size(), etl::dec), etl::to_arithmetic_invalid_format); + CHECK_THROW((void)etl::to_arithmetic(text6.c_str(), text6.size(), etl::dec), etl::to_arithmetic_invalid_format); + CHECK_THROW((void)etl::to_arithmetic(text7.c_str(), text7.size(), etl::dec), etl::to_arithmetic_invalid_format); + CHECK_THROW((void)etl::to_arithmetic(text8.c_str(), text8.size(), etl::dec), etl::to_arithmetic_invalid_format); + CHECK_THROW((void)etl::to_arithmetic(text9.c_str(), text9.size(), etl::dec), etl::to_arithmetic_invalid_format); + CHECK_THROW((void)etl::to_arithmetic(text10.c_str(), text10.size(), etl::dec), etl::to_arithmetic_invalid_format); } //************************************************************************* TEST(test_valid_decimal_numerics) { - const std::string value1("0"); - const std::string value2("1"); - const std::string value3("5"); - const std::string value4("+10"); - const std::string value5("83"); - const std::string value6("-84"); + const std::string text1("0"); + const std::string text2("1"); + const std::string text3("5"); + const std::string text4("+10"); + const std::string text5("83"); + const std::string text6("-84"); - CHECK_EQUAL(int(0), int(etl::to_arithmetic(value1.c_str(), value1.size(), etl::dec).value())); - CHECK_EQUAL(int(1), int(etl::to_arithmetic(value2.c_str(), value2.size(), etl::dec).value())); - CHECK_EQUAL(int(5), int(etl::to_arithmetic(value3.c_str(), value3.size(), etl::dec).value())); - CHECK_EQUAL(int(10), int(etl::to_arithmetic(value4.c_str(), value4.size(), etl::dec).value())); - CHECK_EQUAL(int(83), int(etl::to_arithmetic(value5.c_str(), value5.size(), etl::dec).value())); - CHECK_EQUAL(int(-84), int(etl::to_arithmetic(value6.c_str(), value6.size(), etl::dec).value())); + CHECK_EQUAL(int(0), int(etl::to_arithmetic(text1.c_str(), text1.size(), etl::dec).value())); + CHECK_EQUAL(int(1), int(etl::to_arithmetic(text2.c_str(), text2.size(), etl::dec).value())); + CHECK_EQUAL(int(5), int(etl::to_arithmetic(text3.c_str(), text3.size(), etl::dec).value())); + CHECK_EQUAL(int(10), int(etl::to_arithmetic(text4.c_str(), text4.size(), etl::dec).value())); + CHECK_EQUAL(int(83), int(etl::to_arithmetic(text5.c_str(), text5.size(), etl::dec).value())); + CHECK_EQUAL(int(-84), int(etl::to_arithmetic(text6.c_str(), text6.size(), etl::dec).value())); } //************************************************************************* TEST(test_big_decimal_numerics) { - const std::string value1("-9223372036854775808"); - const std::string value2("9223372036854775807"); - const std::string value3("-1"); + const std::string text1("-9223372036854775808"); + const std::string text2("9223372036854775807"); + const std::string text3("-1"); - CHECK_EQUAL(int64_t(0x8000000000000000ULL), etl::to_arithmetic(value1.c_str(), value1.size(), etl::dec).value()); - CHECK_EQUAL(int64_t(0x7FFFFFFFFFFFFFFFULL), etl::to_arithmetic(value2.c_str(), value2.size(), etl::dec).value()); - CHECK_EQUAL(int64_t(0xFFFFFFFFFFFFFFFFULL), etl::to_arithmetic(value3.c_str(), value3.size(), etl::dec).value()); + CHECK_EQUAL(-9223372036854775808LL, etl::to_arithmetic(text1.c_str(), text1.size(), etl::dec).value()); + CHECK_EQUAL(9223372036854775807LL, etl::to_arithmetic(text2.c_str(), text2.size(), etl::dec).value()); + CHECK_EQUAL(-1LL, etl::to_arithmetic(text3.c_str(), text3.size(), etl::dec).value()); } //************************************************************************* TEST(test_invalid_hex_numerics) { - const char* decimal1 = " 1Af"; - const char* decimal2 = "1Af "; - const char* decimal3 = "1Gf"; - const char* decimal4 = "-1Af"; + const std::string text1(" 1Af"); + const std::string text2("1Af "); + const std::string text3("1Gf"); + const std::string text4("-1Af"); - CHECK_THROW(etl::to_arithmetic(decimal1, strlen(decimal1), etl::dec), etl::to_arithmetic_invalid_format); - CHECK_THROW(etl::to_arithmetic(decimal2, strlen(decimal2), etl::dec), etl::to_arithmetic_invalid_format); - CHECK_THROW(etl::to_arithmetic(decimal3, strlen(decimal3), etl::dec), etl::to_arithmetic_invalid_format); - CHECK_THROW(etl::to_arithmetic(decimal4, strlen(decimal4), etl::dec), etl::to_arithmetic_invalid_format); + CHECK_THROW((void)etl::to_arithmetic(text1.c_str(), text1.size(), etl::dec), etl::to_arithmetic_invalid_format); + CHECK_THROW((void)etl::to_arithmetic(text2.c_str(), text2.size(), etl::dec), etl::to_arithmetic_invalid_format); + CHECK_THROW((void)etl::to_arithmetic(text3.c_str(), text3.size(), etl::dec), etl::to_arithmetic_invalid_format); + CHECK_THROW((void)etl::to_arithmetic(text4.c_str(), text4.size(), etl::dec), etl::to_arithmetic_signed_to_unsigned); } //************************************************************************* TEST(test_valid_hex_numerics) { - const std::string value1("0"); - const std::string value2("1"); - const std::string value3("5"); - const std::string value4("a"); - const std::string value5("53"); - const std::string value6("Ac"); + const std::string text1("0"); + const std::string text2("1"); + const std::string text3("5"); + const std::string text4("a"); + const std::string text5("53"); + const std::string text6("Ac"); + const std::string text7("-53"); - CHECK_EQUAL(int(0), int(etl::to_arithmetic(value1.c_str(), value1.size(), etl::hex).value())); - CHECK_EQUAL(int(1), int(etl::to_arithmetic(value2.c_str(), value2.size(), etl::hex).value())); - CHECK_EQUAL(int(5), int(etl::to_arithmetic(value3.c_str(), value3.size(), etl::hex).value())); - CHECK_EQUAL(int(10), int(etl::to_arithmetic(value4.c_str(), value4.size(), etl::hex).value())); - CHECK_EQUAL(int(83), int(etl::to_arithmetic(value5.c_str(), value5.size(), etl::hex).value())); - CHECK_EQUAL(int(-84), int(etl::to_arithmetic(value6.c_str(), value6.size(), etl::hex).value())); + CHECK_EQUAL(int(0), int(etl::to_arithmetic(text1.c_str(), text1.size(), etl::hex).value())); + CHECK_EQUAL(int(1), int(etl::to_arithmetic(text2.c_str(), text2.size(), etl::hex).value())); + CHECK_EQUAL(int(5), int(etl::to_arithmetic(text3.c_str(), text3.size(), etl::hex).value())); + CHECK_EQUAL(int(10), int(etl::to_arithmetic(text4.c_str(), text4.size(), etl::hex).value())); + CHECK_EQUAL(int(83), int(etl::to_arithmetic(text5.c_str(), text5.size(), etl::hex).value())); + CHECK_EQUAL(int(-84), int(etl::to_arithmetic(text6.c_str(), text6.size(), etl::hex).value())); + CHECK_EQUAL(int(-83), int(etl::to_arithmetic(text7.c_str(), text7.size(), etl::hex).value())); } //************************************************************************* TEST(test_big_hex_numerics) { - const std::string value1("8000000000000000"); - const std::string value2("7FFFFFFFFFFFFFFF"); - const std::string value3("FFFFFFFFFFFFFFFF"); + const std::string text1("8000000000000000"); + const std::string text2("7FFFFFFFFFFFFFFF"); + const std::string text3("FFFFFFFFFFFFFFFF"); - CHECK_EQUAL(uint64_t(0x8000000000000000ULL), etl::to_arithmetic(value1.c_str(), value1.size(), etl::hex).value()); - CHECK_EQUAL(uint64_t(0x7FFFFFFFFFFFFFFFULL), etl::to_arithmetic(value2.c_str(), value2.size(), etl::hex).value()); - CHECK_EQUAL(uint64_t(0xFFFFFFFFFFFFFFFFULL), etl::to_arithmetic(value3.c_str(), value3.size(), etl::hex).value()); + CHECK_EQUAL(uint64_t(0x8000000000000000ULL), etl::to_arithmetic(text1.c_str(), text1.size(), etl::hex).value()); + CHECK_EQUAL(uint64_t(0x7FFFFFFFFFFFFFFFULL), etl::to_arithmetic(text2.c_str(), text2.size(), etl::hex).value()); + CHECK_EQUAL(uint64_t(0xFFFFFFFFFFFFFFFFULL), etl::to_arithmetic(text3.c_str(), text3.size(), etl::hex).value()); + } + + //************************************************************************* + TEST(test_valid_float) + { + const std::string text1("-123.456789"); + + float f1 = strtof(text1.c_str(), nullptr); + float f2 = etl::to_arithmetic(text1.c_str(), text1.size()).value(); + + CHECK_EQUAL(f1, f2); + + const std::string text2("-1.23456789e2"); + float f3 = etl::to_arithmetic(text2.c_str(), text2.size()).value(); + + CHECK_EQUAL(f1, f3); + } + + //************************************************************************* + TEST(test_valid_double) + { + const std::string text1("-123.45678901234567"); + + double f1 = strtod(text1.c_str(), nullptr); + double f2 = etl::to_arithmetic(text1.c_str(), text1.size()).value(); + + CHECK_EQUAL(f1, f2); + } + + //************************************************************************* + TEST(test_constexpr_integral) + { + constexpr const char* text{ "123" }; + constexpr etl::string_view view(text, 3); + + constexpr etl::optional opt = etl::to_arithmetic(view, etl::radix::decimal); + constexpr int i = opt.value(); + + CHECK_EQUAL(123, i); + } + + //************************************************************************* + TEST(test_constexpr_floating_point) + { + //constexpr const char* text{ "123.456789" }; + //constexpr etl::string_view view(text, 3); + + //constexpr etl::optional opt = etl::to_arithmetic(view); + //constexpr double i = opt.value(); + + //CHECK_EQUAL(123, i); } } }