diff --git a/include/etl/to_arithmetic.h b/include/etl/to_arithmetic.h index 28ee76da..232a233c 100644 --- a/include/etl/to_arithmetic.h +++ b/include/etl/to_arithmetic.h @@ -66,6 +66,19 @@ namespace etl } }; + //*************************************************************************** + /// + //*************************************************************************** + class to_arithmetic_overflow : public to_arithmetic_exception + { + public: + + to_arithmetic_overflow(string_type file_name_, numeric_type line_number_) + : to_arithmetic_exception(ETL_ERROR_TEXT("to arithmetic:overflow", ETL_TO_ARITHMETIC_FILE_ID"D"), file_name_, line_number_) + { + } + }; + namespace private_to_arithmetic { static ETL_CONSTANT char binary_length = 2; @@ -223,7 +236,7 @@ namespace etl ETL_NODISCARD ETL_CONSTEXPR14 - static char lookup(wchar_t c) + static char lookup(char16_t c) { for (int i = 0; i < valid_length; ++i) { @@ -261,81 +274,6 @@ namespace etl } }; - //*************************************************************************** - /// - //*************************************************************************** - //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) - // { - // 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; - //} - //*************************************************************************** /// //*************************************************************************** @@ -366,36 +304,23 @@ namespace etl 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; + //******************************************* + template + bool check_has_negative_prefix(etl::basic_string_view& view) + { + // Check for prefix. + const char c = character_set::lookup(view[0]); + const bool has_positive_prefix = (c == valid_character_set::positive_char); + const bool has_negative_prefix = (c == valid_character_set::negative_char); - // return value; - //} + // Remove the prefix if present. + if (has_positive_prefix || has_negative_prefix) + { + view.remove_prefix(1); + } - //*************************************************************************** - /// - //*************************************************************************** - //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; - //} + return has_negative_prefix; + } //*************************************************************************** /// @@ -406,10 +331,9 @@ namespace etl //********************************* ETL_NODISCARD ETL_CONSTEXPR14 - to_integral_implementation(etl::radix::value_type radix_) - : count(0) - , value(0) - , is_negative(false) + to_integral_implementation(etl::radix::value_type radix_, bool is_negative_) + : value(0) + , is_negative(is_negative_) , valid_value(false) , radix(radix_) { @@ -420,54 +344,14 @@ namespace etl ETL_CONSTEXPR14 bool add(char c) { - bool is_valid = true; - - switch (count) - { - case 0: - { - // Check for prefix. - const bool has_positive_prefix = (c == valid_character_set::positive_char); - const bool has_negative_prefix = (c == valid_character_set::negative_char); - - if (has_positive_prefix || has_negative_prefix) - { - is_negative = has_negative_prefix; - - if (etl::is_unsigned::value && is_negative) - { - is_valid = false; - ETL_ASSERT_FAIL(ETL_ERROR(etl::to_arithmetic_signed_to_unsigned)); - } - } - else - { - is_valid = valid_character_set::is_valid(c, radix); + bool is_valid = valid_character_set::is_valid(c, radix); - if (is_valid) - { - value = accumulate_value(value, valid_character_set::digit_value(c, radix), radix, is_negative); - valid_value = true; - } - } - break; - } - - default: - { - is_valid = valid_character_set::is_valid(c, radix); - - if (is_valid) - { - value = accumulate_value(value, valid_character_set::digit_value(c, radix), radix, is_negative); - valid_value = true; - } - break; - } + if (is_valid) + { + value = accumulate_value(value, valid_character_set::digit_value(c, radix), radix, is_negative); + valid_value = true; } - ++count; - return is_valid; } @@ -485,117 +369,335 @@ namespace etl private: - int count; TValue value; bool is_negative; bool valid_value; etl::radix::value_type radix; }; + + //*************************************************************************** + /// Text to integral from view and radix value type. + // For unsigned 32 int. + //*************************************************************************** + template + ETL_NODISCARD + ETL_CONSTEXPR14 + etl::optional to_arithmetic_uint32_t(etl::basic_string_view view, const etl::radix::value_type radix) + { + using namespace etl::private_to_arithmetic; + + etl::optional result; + bool is_negative = false; + + if (!view.empty()) + { + ETL_ASSERT(!check_has_negative_prefix(view), ETL_ERROR(etl::to_arithmetic_signed_to_unsigned)); + + to_integral_implementation implementation(radix, is_negative); + + bool parsing = true; + + etl::basic_string_view::const_iterator itr = view.begin(); + + while (parsing) + { + parsing = implementation.add(character_set::lookup(*itr)); + + if (parsing) + { + ++itr; + + if (itr == view.end()) + { + ETL_ASSERT(implementation.has_value(), ETL_ERROR(etl::to_arithmetic_invalid_format)); + + result = implementation.get_value(); + parsing = false; + } + } + else + { + ETL_ASSERT_FAIL(ETL_ERROR(etl::to_arithmetic_invalid_format)); + } + } + } + else + { + ETL_ASSERT_FAIL(ETL_ERROR(etl::to_arithmetic_invalid_format)); + } + + return result; + } + + //*************************************************************************** + /// Text to integral from view and radix value type. + // For signed 32 int. + //*************************************************************************** + template + ETL_NODISCARD + ETL_CONSTEXPR14 + etl::optional to_arithmetic_int32_t(etl::basic_string_view view, const etl::radix::value_type radix) + { + using namespace etl::private_to_arithmetic; + + etl::optional result; + bool is_negative = false; + + if (!view.empty()) + { + is_negative = check_has_negative_prefix(view); + } + + if (!view.empty()) + { + to_integral_implementation implementation(radix, is_negative); + + bool parsing = true; + + etl::basic_string_view::const_iterator itr = view.begin(); + + while (parsing) + { + parsing = implementation.add(character_set::lookup(*itr)); + + if (parsing) + { + ++itr; + + if (itr == view.end()) + { + ETL_ASSERT(implementation.has_value(), ETL_ERROR(etl::to_arithmetic_invalid_format)); + + result = implementation.get_value(); + parsing = false; + } + } + else + { + ETL_ASSERT_FAIL(ETL_ERROR(etl::to_arithmetic_invalid_format)); + } + } + } + else + { + ETL_ASSERT_FAIL(ETL_ERROR(etl::to_arithmetic_invalid_format)); + } + + return result; + } + +#if ETL_USING_64BIT_TYPES + //*************************************************************************** + /// Text to integral from view and radix value type. + // For unsigned 64 int. + //*************************************************************************** + template + ETL_NODISCARD + ETL_CONSTEXPR14 + etl::optional to_arithmetic_uint64_t(etl::basic_string_view view, const etl::radix::value_type radix) + { + using namespace etl::private_to_arithmetic; + + etl::optional result; + bool is_negative = false; + + if (!view.empty()) + { + ETL_ASSERT(!check_has_negative_prefix(view), ETL_ERROR(etl::to_arithmetic_signed_to_unsigned)); + + to_integral_implementation implementation(radix, is_negative); + + bool parsing = true; + + etl::basic_string_view::const_iterator itr = view.begin(); + + while (parsing) + { + parsing = implementation.add(character_set::lookup(*itr)); + + if (parsing) + { + ++itr; + + if (itr == view.end()) + { + ETL_ASSERT(implementation.has_value(), ETL_ERROR(etl::to_arithmetic_invalid_format)); + + result = implementation.get_value(); + parsing = false; + } + } + else + { + ETL_ASSERT_FAIL(ETL_ERROR(etl::to_arithmetic_invalid_format)); + } + } + } + else + { + ETL_ASSERT_FAIL(ETL_ERROR(etl::to_arithmetic_invalid_format)); + } + + return result; + } + + //*************************************************************************** + /// Text to integral from view and radix value type. + // For signed 64 int. + //*************************************************************************** + template + ETL_NODISCARD + ETL_CONSTEXPR14 + etl::optional to_arithmetic_int64_t(etl::basic_string_view view, const etl::radix::value_type radix) + { + using namespace etl::private_to_arithmetic; + + etl::optional result; + bool is_negative = false; + + if (!view.empty()) + { + is_negative = check_has_negative_prefix(view); + } + + if (!view.empty()) + { + to_integral_implementation implementation(radix, is_negative); + + bool parsing = true; + + etl::basic_string_view::const_iterator itr = view.begin(); + + while (parsing) + { + parsing = implementation.add(character_set::lookup(*itr)); + + if (parsing) + { + ++itr; + + if (itr == view.end()) + { + ETL_ASSERT(implementation.has_value(), ETL_ERROR(etl::to_arithmetic_invalid_format)); + + result = implementation.get_value(); + parsing = false; + } + } + else + { + ETL_ASSERT_FAIL(ETL_ERROR(etl::to_arithmetic_invalid_format)); + } + } + } + else + { + ETL_ASSERT_FAIL(ETL_ERROR(etl::to_arithmetic_invalid_format)); + } + + return result; + } +#endif } //*************************************************************************** /// Text to integral from view and radix value 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; - // view_information view_info; - // numeric_information numeric_info; - - // to_integral_implementation implementation(numeric_info); - - // bool parsing = validate_information_from_view(view, radix, view_info, numeric_info); - - // if (parsing) - // { - // if (etl::is_unsigned::value && numeric_info.is_negative) - // { - // parsing = false; - // ETL_ASSERT_FAIL(ETL_ERROR(etl::to_arithmetic_signed_to_unsigned)); - // } - - // if (parsing) - // { - // // Parse the numeric part. - // TValue value = 0; - - // etl::basic_string_view::const_iterator itr = view.begin(); - - // while (parsing) - // { - // implementation.add(character_set::lookup(*itr)); - - // ++itr; - - // if (itr == view.end()) - // { - // result = implementation.value; - // parsing = false; - // } - // } - // } - // } - - // return result; - //} - - //*************************************************************************** - /// Text to integral from view and radix value type. + /// Unsigned <= 32 bits. //*************************************************************************** template ETL_NODISCARD ETL_CONSTEXPR14 - typename etl::enable_if::value, etl::optional >::type + typename etl::enable_if::value && (etl::integral_limits::bits <= 32U) && etl::is_unsigned::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; + + etl::optional intermediate_result = to_arithmetic_uint32_t(view, radix); - if (!view.empty()) + if (intermediate_result.has_value()) { - to_integral_implementation implementation(radix); - - etl::basic_string_view::const_iterator itr = view.begin(); - - bool parsing = true; - - while (parsing) - { - parsing = implementation.add(character_set::lookup(*itr)); - - if (parsing) - { - ++itr; - - if (itr == view.end()) - { - ETL_ASSERT(implementation.has_value(), ETL_ERROR(etl::to_arithmetic_invalid_format)); - - result = implementation.get_value(); - parsing = false; - } - } - else - { - ETL_ASSERT_FAIL(ETL_ERROR(etl::to_arithmetic_invalid_format)); - } - } - } - else - { - ETL_ASSERT_FAIL(ETL_ERROR(etl::to_arithmetic_invalid_format)); + result = static_cast(intermediate_result.value()); } return result; } + //*************************************************************************** + /// Text to integral from view and radix value type. + /// Signed <= 32 bits. + //*************************************************************************** + template + ETL_NODISCARD + ETL_CONSTEXPR14 + typename etl::enable_if::value && (etl::integral_limits::bits <= 32U) && etl::is_signed::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; + + etl::optional intermediate_result = to_arithmetic_int32_t(view, radix); + + if (intermediate_result.has_value()) + { + result = static_cast(intermediate_result.value()); + } + + return result; + } + +#if ETL_USING_64BIT_TYPES + //*************************************************************************** + /// Text to integral from view and radix value type. + /// Unsigned == 64 bits. + //*************************************************************************** + template + ETL_NODISCARD + ETL_CONSTEXPR14 + typename etl::enable_if::value && (etl::integral_limits::bits == 64U) && etl::is_unsigned::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; + + etl::optional intermediate_result = to_arithmetic_uint64_t(view, radix); + + if (intermediate_result.has_value()) + { + result = static_cast(intermediate_result.value()); + } + + return result; + } + + //*************************************************************************** + /// Text to integral from view and radix value type. + /// Signed == 64 bits. + //*************************************************************************** + template + ETL_NODISCARD + ETL_CONSTEXPR14 + typename etl::enable_if::value && (etl::integral_limits::bits == 64U) && etl::is_signed::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; + + etl::optional intermediate_result = to_arithmetic_int64_t(view, radix); + + if (intermediate_result.has_value()) + { + result = static_cast(intermediate_result.value()); + } + + return result; + } +#endif + //*************************************************************************** /// Text to integral from view and default decimal radix. //***************************************************************************